<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

import Playback from '../../base/playback'
import assign from 'lodash.assign'
import template from '../../base/template'

import Mediator from '../../components/mediator'
import Browser from '../../components/browser'
import Events from '../../base/events'
import Styler from '../../base/styler'
import hlsStyle from './public/style.scss'
import hlsHTML from './public/hls_playback.html'
import hlsSwf from './public/HLSPlayer.swf'
import $ from 'clappr-zepto'

import HLSEvents from './flashls_events'

var objectIE = '<object type="application/x-shockwave-flash" id="<%= cid %>" class="hls-playback" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" data-hls="" width="100%" height="100%"><param name="movie" value="<%= swfPath %>"> <param name="quality" value="autohigh"> <param name="swliveconnect" value="true"> <param name="allowScriptAccess" value="always"> <param name="bgcolor" value="#001122"> <param name="allowFullScreen" value="false"> <param name="wmode" value="transparent"> <param name="tabindex" value="1"> <param name=FlashVars value="playbackId=<%= playbackId %>" /> </object>'

export default class HLS extends Playback {
  get name() { return 'hls' }
  get tagName() { return 'object' }
  get template() { return template(hlsHTML) }
  get attributes() {
    return {
      'class': 'hls-playback',
      'data-hls': '',
      'type': 'application/x-shockwave-flash',
      'width': '100%',
      'height': '100%'
    }
  }

  constructor(options) {
    super(options)
    this.src = options.src
    this.baseUrl = options.baseUrl;
    this.flushLiveURLCache = (options.flushLiveURLCache === undefined) ? true : options.flushLiveURLCache
    this.capLevelToStage = (options.capLevelToStage === undefined) ? false : options.capLevelToStage
    this.useHardwareVideoDecoder = (options.useHardwareVideoDecoder === undefined) ? false : options.useHardwareVideoDecoder
    this.maxBufferLength = (options.maxBufferLength === undefined) ? 120 : options.maxBufferLength
    this.hlsMinimumDvrSize = (options.hlsMinimumDvrSize == undefined) ? 60 : options.hlsMinimumDvrSize
    this.hlsLogEnabled = (options.hlsLogEnabled == undefined) ? true : options.hlsLogEnabled
    this.highDefinition = false
    this.autoPlay = options.autoPlay
    this.defaultSettings = {
      left: ["playstop"],
      default: ['seekbar'],
      right: ["fullscreen", "volume", "hd-indicator"],
      seekEnabled: false
    }
    this.settings = assign({}, this.defaultSettings)
    this.playbackType = 'live'
    this.addListeners()
  }

  addListeners() {
    Mediator.on(this.cid + ':flashready', () => this.bootstrap())
    Mediator.on(this.cid + ':timeupdate', (timeMetrics) => this.updateTime(timeMetrics))
    Mediator.on(this.cid + ':playbackstate', (state) => this.setPlaybackState(state))
    Mediator.on(this.cid + ':levelchanged', (level) => this.updateHighDefinition(level))
    Mediator.on(this.cid + ':playbackerror', () => this.flashPlaybackError())
    Mediator.once(this.cid + ':manifestloaded',(duration, loadmetrics) => this.manifestLoaded(duration, loadmetrics))
  }

  stopListening() {
    super.stopListening()
    Mediator.off(this.cid + ':flashready')
    Mediator.off(this.cid + ':timeupdate')
    Mediator.off(this.cid + ':playbackstate')
    Mediator.off(this.cid + ':levelchanged')
    Mediator.off(this.cid + ':playbackerror')
    Mediator.off(this.cid + ':manifestloaded')
  }

  bootstrap() {
    this.el.width = "100%"
    this.el.height = "100%"
    this.isReady = true
    this.srcLoaded = false
    this.currentState = "IDLE"
    this.setFlashSettings()
    this.updatePlaybackType()
    this.autoPlay && this.play()
    this.trigger(Events.PLAYBACK_READY, this.name)
  }

  setFlashSettings() {
    this.el.playerSetflushLiveURLCache(this.flushLiveURLCache)
    this.el.playerCapLeveltoStage(this.capLevelToStage)
    this.el.playerSetmaxBufferLength(this.maxBufferLength)
    this.el.playerSetUseHardwareVideoDecoder(this.useHardwareVideoDecoder)
    this.el.playerSetLogInfo(this.hlsLogEnabled)
  }

  updateHighDefinition(level) {
    var currentLevel = this.getLevels()[level]
    this.highDefinition = (currentLevel.height >= 720 || (currentLevel.bitrate / 1000) >= 2000);
    this.trigger(Events.PLAYBACK_HIGHDEFINITIONUPDATE)
    this.trigger(Events.PLAYBACK_BITRATE, {'bitrate': this.getCurrentBitrate()})
  }

  updateTime(timeMetrics) {
    if (this.currentState === 'IDLE') return

    var duration = this.normalizeDuration(timeMetrics.duration)
    var position = Math.min(Math.max(timeMetrics.position, 0), duration)
    var previousDVRStatus = this.dvrEnabled
    var livePlayback = (this.playbackType === 'live')
    this.dvrEnabled = (livePlayback && duration > this.hlsMinimumDvrSize)

    if (duration === 100 || livePlayback === undefined) {
      return;
    }

    if (this.dvrEnabled !== previousDVRStatus) {
      this.updateSettings()
      this.trigger(Events.PLAYBACK_SETTINGSUPDATE, this.name)
    }

    if (livePlayback && (!this.dvrEnabled || !this.dvrInUse)) {
      position = duration
    }

    this.trigger(Events.PLAYBACK_TIMEUPDATE, position, duration, this.name)
  }

  play() {
    if(this.currentState === 'PAUSED') {
      this.el.playerResume()
    } else if (!this.srcLoaded && this.currentState !== "PLAYING") {
      this.firstPlay()
    } else {
      this.el.playerPlay()
    }
  }

  getPlaybackType() {
    return this.playbackType? this.playbackType: null
  }

  getCurrentBitrate() {
    var currentLevel = this.getLevels()[this.el.getLevel()]
    return currentLevel.bitrate
  }

  isHighDefinitionInUse() {
    return this.highDefinition
  }

  getLevels() {
    if (!this.levels || this.levels.length === 0) {
      this.levels = this.el.getLevels()
    }
    return this.levels
  }

  setPlaybackState(state) {
    if (["PLAYING_BUFFERING", "PAUSED_BUFFERING"].indexOf(state) >= 0)  {
      this.trigger(Events.PLAYBACK_BUFFERING, this.name)
      this.updateCurrentState(state)
    } else if (["PLAYING", "PAUSED"].indexOf(state) >= 0) {
      if (["PLAYING_BUFFERING", "PAUSED_BUFFERING", "IDLE"].indexOf(this.currentState) >= 0) {
        this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
      }
      this.updateCurrentState(state)
    } else if (state === "IDLE") {
      this.updateCurrentState(state)
      this.trigger(Events.PLAYBACK_TIMEUPDATE, 0, this.el.getDuration(), this.name)
      this.trigger(Events.PLAYBACK_ENDED, this.name)
    }
  }

  updateCurrentState(state) {
    this.currentState = state
    this.updatePlaybackType()
    if (state === "PLAYING") {
      this.trigger(Events.PLAYBACK_PLAY, this.name)
    } else if (state === "PAUSED") {
      this.trigger(Events.PLAYBACK_PAUSE, this.name)
    }
  }

  updatePlaybackType() {
    this.playbackType = this.el.getType()
    if (this.playbackType) {
      this.playbackType = this.playbackType.toLowerCase()
      if (this.playbackType === 'vod') {
        this.startReportingProgress()
      } else {
        this.stopReportingProgress()
      }
    }
    this.trigger(Events.PLAYBACK_PLAYBACKSTATE)
  }

  startReportingProgress() {
    if (!this.reportingProgress) {
      this.reportingProgress = true
      Mediator.on(this.cid + ':fragmentloaded',() => this.onFragmentLoaded())
    }
  }

  stopReportingProgress() {
    Mediator.off(this.cid + ':fragmentloaded', this.onFragmentLoaded, this)
  }

  onFragmentLoaded() {
    var buffered = this.el.getPosition() + this.el.getbufferLength()
    this.trigger(Events.PLAYBACK_PROGRESS, this.el.getPosition(), buffered, this.el.getDuration(), this.name)
  }

  firstPlay() {
    this.setFlashSettings() //ensure flushLiveURLCache will work (#327)
    this.el.playerLoad(this.src)
    Mediator.once(this.cid + ':manifestloaded',() => this.el.playerPlay())
    this.srcLoaded = true
  }

  volume(value) {
    if (this.isReady) {
      this.el.playerVolume(value)
    } else {
      this.listenToOnce(this, Events.PLAYBACK_BUFFERFULL, () => this.volume(value))
    }
  }

  pause() {
    if (this.playbackType !== 'live' || this.dvrEnabled) {
      this.el.playerPause()
      if (this.playbackType === 'live' && this.dvrEnabled) {
        this.updateDvr(true)
      }
    }
  }

  stop() {
    this.el.playerStop()
    this.trigger(Events.PLAYBACK_TIMEUPDATE, 0, this.name)
  }

  isPlaying() {
    if (this.currentState) {
      return !!(this.currentState.match(/playing/i))
    }
    return false
  }

  getDuration() {
    return this.normalizeDuration(this.el.getDuration())
  }

  normalizeDuration(duration) {
    if (this.playbackType === 'live') {
      // estimate 10 seconds of buffer time for live streams for seek positions
      duration = duration - 10
    }
    return duration
  }

  seek(time) {
    var duration = this.el.getDuration()
    if (time > 0) {
      time = duration * time / 100
    }

    if (this.playbackType === 'live') {
      // seek operations to a time within 5 seconds from live stream will position playhead back to live
      var dvrInUse = (time >= 0 && duration - time > 5)
      if (!dvrInUse) {
        time = -1
      }
      this.updateDvr(dvrInUse)
    }
    this.el.playerSeek(time)
    this.trigger(Events.PLAYBACK_TIMEUPDATE, time, duration, this.name)
    this.trigger(Events.PLAYBACK_HIGHDEFINITIONUPDATE)
  }

  updateDvr(dvrInUse) {
    var previousDvrInUse = !!this.dvrInUse
    this.dvrInUse = dvrInUse
    if (this.dvrInUse !== previousDvrInUse) {
      this.updateSettings()
      this.trigger(Events.PLAYBACK_DVR, this.dvrInUse)
      this.trigger(Events.PLAYBACK_STATS_ADD, {'dvr': this.dvrInUse})
    }
  }

  flashPlaybackError() {
    this.trigger(Events.PLAYBACK_STOP)
  }

  manifestLoaded(duration, loadmetrics) {
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, duration, loadmetrics)
  }

  timeUpdate(time, duration) {
    this.trigger(Events.PLAYBACK_TIMEUPDATE, time, duration, this.name)
  }

  destroy() {
    this.stopListening()
    this.$el.remove()
  }

  setupFirefox() {
    var $el = this.$('embed')
    $el.attr('data-hls', '')
    this.setElement($el)
  }

  setupIE(swfPath) {
    this.setElement($(template(objectIE)({cid: this.cid, swfPath: swfPath, baseUrl: this.baseUrl, playbackId: this.uniqueId})))
  }

  updateSettings() {
    this.settings = assign({}, this.defaultSettings)
    if (this.playbackType === "vod" || this.dvrInUse) {
      this.settings.left = ["playpause", "position", "duration"]
      this.settings.seekEnabled = true
    } else if (this.dvrEnabled) {
      this.settings.left = ["playpause"]
      this.settings.seekEnabled = true
    } else {
      this.settings.seekEnabled = false
    }
  }

  setElement(element) {
    this.$el = element
    this.el = element[0]
  }

  createCallbacks() {
    if (!window.Clappr.flashlsCallbacks) {
      window.Clappr.flashlsCallbacks = {}
    }
    this.flashlsEvents = new HLSEvents(this.cid)
    window.Clappr.flashlsCallbacks[this.cid] = (eventName, args) => {
      this.flashlsEvents[eventName].apply(this.flashlsEvents, args)
    }
  }

  render() {
    var style = Styler.getStyleFor(hlsStyle)
    var swfPath = hlsSwf
    if (this.baseUrl) {
      swfPath = `${this.baseUrl}/public/HLSPlayer.swf`
    }
    if(Browser.isLegacyIE) {
      this.setupIE(swfPath)
    } else {
      this.createCallbacks()
      this.$el.html(this.template({cid: this.cid, swfPath: swfPath, baseUrl: this.baseUrl, playbackId: this.uniqueId, callbackName: `window.Clappr.flashlsCallbacks.${this.cid}`}))
      if(Browser.isFirefox) {
        this.setupFirefox()
      } else if (Browser.isIE) {
        this.$('embed').remove()
      }
    }
    this.el.id = this.cid
    this.$el.append(style)
    return this
  }
}

HLS.canPlay = function(resource, mimeType) {
  var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || []
  return Browser.hasFlash &&
        ((resourceParts.length > 1 && resourceParts[1] == "m3u8") ||
          mimeType === 'application/x-mpegURL' || mimeType === 'application/vnd.apple.mpegurl')
}

<commit_msg>hls: change swf url to use baseUrl template<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

import Playback from '../../base/playback'
import assign from 'lodash.assign'
import template from '../../base/template'

import Mediator from '../../components/mediator'
import Browser from '../../components/browser'
import Events from '../../base/events'
import Styler from '../../base/styler'
import hlsStyle from './public/style.scss'
import hlsHTML from './public/hls_playback.html'
import hlsSwf from './public/HLSPlayer.swf'
import $ from 'clappr-zepto'

import HLSEvents from './flashls_events'

var objectIE = '<object type="application/x-shockwave-flash" id="<%= cid %>" class="hls-playback" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" data-hls="" width="100%" height="100%"><param name="movie" value="<%= swfPath %>"> <param name="quality" value="autohigh"> <param name="swliveconnect" value="true"> <param name="allowScriptAccess" value="always"> <param name="bgcolor" value="#001122"> <param name="allowFullScreen" value="false"> <param name="wmode" value="transparent"> <param name="tabindex" value="1"> <param name=FlashVars value="playbackId=<%= playbackId %>" /> </object>'

export default class HLS extends Playback {
  get name() { return 'hls' }
  get tagName() { return 'object' }
  get template() { return template(hlsHTML) }
  get attributes() {
    return {
      'class': 'hls-playback',
      'data-hls': '',
      'type': 'application/x-shockwave-flash',
      'width': '100%',
      'height': '100%'
    }
  }

  constructor(options) {
    super(options)
    this.src = options.src
    this.baseUrl = options.baseUrl;
    this.flushLiveURLCache = (options.flushLiveURLCache === undefined) ? true : options.flushLiveURLCache
    this.capLevelToStage = (options.capLevelToStage === undefined) ? false : options.capLevelToStage
    this.useHardwareVideoDecoder = (options.useHardwareVideoDecoder === undefined) ? false : options.useHardwareVideoDecoder
    this.maxBufferLength = (options.maxBufferLength === undefined) ? 120 : options.maxBufferLength
    this.hlsMinimumDvrSize = (options.hlsMinimumDvrSize == undefined) ? 60 : options.hlsMinimumDvrSize
    this.hlsLogEnabled = (options.hlsLogEnabled == undefined) ? true : options.hlsLogEnabled
    this.highDefinition = false
    this.autoPlay = options.autoPlay
    this.defaultSettings = {
      left: ["playstop"],
      default: ['seekbar'],
      right: ["fullscreen", "volume", "hd-indicator"],
      seekEnabled: false
    }
    this.settings = assign({}, this.defaultSettings)
    this.playbackType = 'live'
    this.addListeners()
  }

  addListeners() {
    Mediator.on(this.cid + ':flashready', () => this.bootstrap())
    Mediator.on(this.cid + ':timeupdate', (timeMetrics) => this.updateTime(timeMetrics))
    Mediator.on(this.cid + ':playbackstate', (state) => this.setPlaybackState(state))
    Mediator.on(this.cid + ':levelchanged', (level) => this.updateHighDefinition(level))
    Mediator.on(this.cid + ':playbackerror', () => this.flashPlaybackError())
    Mediator.once(this.cid + ':manifestloaded',(duration, loadmetrics) => this.manifestLoaded(duration, loadmetrics))
  }

  stopListening() {
    super.stopListening()
    Mediator.off(this.cid + ':flashready')
    Mediator.off(this.cid + ':timeupdate')
    Mediator.off(this.cid + ':playbackstate')
    Mediator.off(this.cid + ':levelchanged')
    Mediator.off(this.cid + ':playbackerror')
    Mediator.off(this.cid + ':manifestloaded')
  }

  bootstrap() {
    this.el.width = "100%"
    this.el.height = "100%"
    this.isReady = true
    this.srcLoaded = false
    this.currentState = "IDLE"
    this.setFlashSettings()
    this.updatePlaybackType()
    this.autoPlay && this.play()
    this.trigger(Events.PLAYBACK_READY, this.name)
  }

  setFlashSettings() {
    this.el.playerSetflushLiveURLCache(this.flushLiveURLCache)
    this.el.playerCapLeveltoStage(this.capLevelToStage)
    this.el.playerSetmaxBufferLength(this.maxBufferLength)
    this.el.playerSetUseHardwareVideoDecoder(this.useHardwareVideoDecoder)
    this.el.playerSetLogInfo(this.hlsLogEnabled)
  }

  updateHighDefinition(level) {
    var currentLevel = this.getLevels()[level]
    this.highDefinition = (currentLevel.height >= 720 || (currentLevel.bitrate / 1000) >= 2000);
    this.trigger(Events.PLAYBACK_HIGHDEFINITIONUPDATE)
    this.trigger(Events.PLAYBACK_BITRATE, {'bitrate': this.getCurrentBitrate()})
  }

  updateTime(timeMetrics) {
    if (this.currentState === 'IDLE') return

    var duration = this.normalizeDuration(timeMetrics.duration)
    var position = Math.min(Math.max(timeMetrics.position, 0), duration)
    var previousDVRStatus = this.dvrEnabled
    var livePlayback = (this.playbackType === 'live')
    this.dvrEnabled = (livePlayback && duration > this.hlsMinimumDvrSize)

    if (duration === 100 || livePlayback === undefined) {
      return;
    }

    if (this.dvrEnabled !== previousDVRStatus) {
      this.updateSettings()
      this.trigger(Events.PLAYBACK_SETTINGSUPDATE, this.name)
    }

    if (livePlayback && (!this.dvrEnabled || !this.dvrInUse)) {
      position = duration
    }

    this.trigger(Events.PLAYBACK_TIMEUPDATE, position, duration, this.name)
  }

  play() {
    if(this.currentState === 'PAUSED') {
      this.el.playerResume()
    } else if (!this.srcLoaded && this.currentState !== "PLAYING") {
      this.firstPlay()
    } else {
      this.el.playerPlay()
    }
  }

  getPlaybackType() {
    return this.playbackType? this.playbackType: null
  }

  getCurrentBitrate() {
    var currentLevel = this.getLevels()[this.el.getLevel()]
    return currentLevel.bitrate
  }

  isHighDefinitionInUse() {
    return this.highDefinition
  }

  getLevels() {
    if (!this.levels || this.levels.length === 0) {
      this.levels = this.el.getLevels()
    }
    return this.levels
  }

  setPlaybackState(state) {
    if (["PLAYING_BUFFERING", "PAUSED_BUFFERING"].indexOf(state) >= 0)  {
      this.trigger(Events.PLAYBACK_BUFFERING, this.name)
      this.updateCurrentState(state)
    } else if (["PLAYING", "PAUSED"].indexOf(state) >= 0) {
      if (["PLAYING_BUFFERING", "PAUSED_BUFFERING", "IDLE"].indexOf(this.currentState) >= 0) {
        this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
      }
      this.updateCurrentState(state)
    } else if (state === "IDLE") {
      this.updateCurrentState(state)
      this.trigger(Events.PLAYBACK_TIMEUPDATE, 0, this.el.getDuration(), this.name)
      this.trigger(Events.PLAYBACK_ENDED, this.name)
    }
  }

  updateCurrentState(state) {
    this.currentState = state
    this.updatePlaybackType()
    if (state === "PLAYING") {
      this.trigger(Events.PLAYBACK_PLAY, this.name)
    } else if (state === "PAUSED") {
      this.trigger(Events.PLAYBACK_PAUSE, this.name)
    }
  }

  updatePlaybackType() {
    this.playbackType = this.el.getType()
    if (this.playbackType) {
      this.playbackType = this.playbackType.toLowerCase()
      if (this.playbackType === 'vod') {
        this.startReportingProgress()
      } else {
        this.stopReportingProgress()
      }
    }
    this.trigger(Events.PLAYBACK_PLAYBACKSTATE)
  }

  startReportingProgress() {
    if (!this.reportingProgress) {
      this.reportingProgress = true
      Mediator.on(this.cid + ':fragmentloaded',() => this.onFragmentLoaded())
    }
  }

  stopReportingProgress() {
    Mediator.off(this.cid + ':fragmentloaded', this.onFragmentLoaded, this)
  }

  onFragmentLoaded() {
    var buffered = this.el.getPosition() + this.el.getbufferLength()
    this.trigger(Events.PLAYBACK_PROGRESS, this.el.getPosition(), buffered, this.el.getDuration(), this.name)
  }

  firstPlay() {
    this.setFlashSettings() //ensure flushLiveURLCache will work (#327)
    this.el.playerLoad(this.src)
    Mediator.once(this.cid + ':manifestloaded',() => this.el.playerPlay())
    this.srcLoaded = true
  }

  volume(value) {
    if (this.isReady) {
      this.el.playerVolume(value)
    } else {
      this.listenToOnce(this, Events.PLAYBACK_BUFFERFULL, () => this.volume(value))
    }
  }

  pause() {
    if (this.playbackType !== 'live' || this.dvrEnabled) {
      this.el.playerPause()
      if (this.playbackType === 'live' && this.dvrEnabled) {
        this.updateDvr(true)
      }
    }
  }

  stop() {
    this.el.playerStop()
    this.trigger(Events.PLAYBACK_TIMEUPDATE, 0, this.name)
  }

  isPlaying() {
    if (this.currentState) {
      return !!(this.currentState.match(/playing/i))
    }
    return false
  }

  getDuration() {
    return this.normalizeDuration(this.el.getDuration())
  }

  normalizeDuration(duration) {
    if (this.playbackType === 'live') {
      // estimate 10 seconds of buffer time for live streams for seek positions
      duration = duration - 10
    }
    return duration
  }

  seek(time) {
    var duration = this.el.getDuration()
    if (time > 0) {
      time = duration * time / 100
    }

    if (this.playbackType === 'live') {
      // seek operations to a time within 5 seconds from live stream will position playhead back to live
      var dvrInUse = (time >= 0 && duration - time > 5)
      if (!dvrInUse) {
        time = -1
      }
      this.updateDvr(dvrInUse)
    }
    this.el.playerSeek(time)
    this.trigger(Events.PLAYBACK_TIMEUPDATE, time, duration, this.name)
    this.trigger(Events.PLAYBACK_HIGHDEFINITIONUPDATE)
  }

  updateDvr(dvrInUse) {
    var previousDvrInUse = !!this.dvrInUse
    this.dvrInUse = dvrInUse
    if (this.dvrInUse !== previousDvrInUse) {
      this.updateSettings()
      this.trigger(Events.PLAYBACK_DVR, this.dvrInUse)
      this.trigger(Events.PLAYBACK_STATS_ADD, {'dvr': this.dvrInUse})
    }
  }

  flashPlaybackError() {
    this.trigger(Events.PLAYBACK_STOP)
  }

  manifestLoaded(duration, loadmetrics) {
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, duration, loadmetrics)
  }

  timeUpdate(time, duration) {
    this.trigger(Events.PLAYBACK_TIMEUPDATE, time, duration, this.name)
  }

  destroy() {
    this.stopListening()
    this.$el.remove()
  }

  setupFirefox() {
    var $el = this.$('embed')
    $el.attr('data-hls', '')
    this.setElement($el)
  }

  setupIE(swfPath) {
    this.setElement($(template(objectIE)({cid: this.cid, swfPath: swfPath, baseUrl: this.baseUrl, playbackId: this.uniqueId})))
  }

  updateSettings() {
    this.settings = assign({}, this.defaultSettings)
    if (this.playbackType === "vod" || this.dvrInUse) {
      this.settings.left = ["playpause", "position", "duration"]
      this.settings.seekEnabled = true
    } else if (this.dvrEnabled) {
      this.settings.left = ["playpause"]
      this.settings.seekEnabled = true
    } else {
      this.settings.seekEnabled = false
    }
  }

  setElement(element) {
    this.$el = element
    this.el = element[0]
  }

  createCallbacks() {
    if (!window.Clappr.flashlsCallbacks) {
      window.Clappr.flashlsCallbacks = {}
    }
    this.flashlsEvents = new HLSEvents(this.cid)
    window.Clappr.flashlsCallbacks[this.cid] = (eventName, args) => {
      this.flashlsEvents[eventName].apply(this.flashlsEvents, args)
    }
  }

  render() {
    var style = Styler.getStyleFor(hlsStyle)
    var swfPath = template(hlsSwf)({baseUrl: this.baseUrl})
    if(Browser.isLegacyIE) {
      this.setupIE(swfPath)
    } else {
      this.createCallbacks()
      this.$el.html(this.template({cid: this.cid, swfPath: swfPath, baseUrl: this.baseUrl, playbackId: this.uniqueId, callbackName: `window.Clappr.flashlsCallbacks.${this.cid}`}))
      if(Browser.isFirefox) {
        this.setupFirefox()
      } else if (Browser.isIE) {
        this.$('embed').remove()
      }
    }
    this.el.id = this.cid
    this.$el.append(style)
    return this
  }
}

HLS.canPlay = function(resource, mimeType) {
  var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || []
  return Browser.hasFlash &&
        ((resourceParts.length > 1 && resourceParts[1] == "m3u8") ||
          mimeType === 'application/x-mpegURL' || mimeType === 'application/vnd.apple.mpegurl')
}

<|endoftext|>


<commit_before>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Plots = require('../plots/plots');
var Lib = require('../lib');

module.exports = function register(_modules) {
    if(!_modules) {
        throw new Error('No argument passed to Plotly.register.');
    }
    else if(_modules && !Array.isArray(_modules)) {
        _modules = [_modules];
    }

    for(var i = 0; i < _modules.length; i++) {
        var newModule = _modules[i];

        if(!newModule) {
            throw new Error('Invalid module was attempted to be registered!');
        }

        switch(newModule.moduleType) {
            case 'trace':
                Plots.register(newModule, newModule.name, newModule.categories, newModule.meta);

                if(!Plots.subplotsRegistry[newModule.basePlotModule.name]) {
                    Plots.registerSubplot(newModule.basePlotModule);
                }

                break;

            case 'transform':
                if(typeof newModule.name !== 'string') {
                    throw new Error('Transform module *name* must be a string.');
                }

                var prefix = 'Transform module ' + newModule.name;

                if(typeof newModule.transform !== 'function') {
                    throw new Error(prefix + ' is missing a *transform* function.');
                }
                if(!Lib.isPlainObject(newModule.attributes)) {
                    Lib.log(prefix + ' registered without an *attributes* object.');
                }
                if(typeof newModule.supplyDefaults !== 'function') {
                    Lib.log(prefix + ' registered without a *supplyDefaults* function.');
                }

                Plots.transformsRegistry[newModule.name] = newModule;

                break;

            default:
                throw new Error('Invalid module was attempted to be registered!');
        }
    }
};
<commit_msg>lint: split registry switch block into routines<commit_after>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Plots = require('../plots/plots');
var Lib = require('../lib');

module.exports = function register(_modules) {
    if(!_modules) {
        throw new Error('No argument passed to Plotly.register.');
    }
    else if(_modules && !Array.isArray(_modules)) {
        _modules = [_modules];
    }

    for(var i = 0; i < _modules.length; i++) {
        var newModule = _modules[i];

        if(!newModule) {
            throw new Error('Invalid module was attempted to be registered!');
        }

        switch(newModule.moduleType) {
            case 'trace':
                registerTraceModule(newModule);
                break;

            case 'transform':
                registerTransformModule(newModule);
                break;

            default:
                throw new Error('Invalid module was attempted to be registered!');
        }
    }
};

function registerTraceModule(newModule) {
    Plots.register(newModule, newModule.name, newModule.categories, newModule.meta);

    if(!Plots.subplotsRegistry[newModule.basePlotModule.name]) {
        Plots.registerSubplot(newModule.basePlotModule);
    }
}

function registerTransformModule(newModule) {
    if(typeof newModule.name !== 'string') {
        throw new Error('Transform module *name* must be a string.');
    }

    var prefix = 'Transform module ' + newModule.name;

    if(typeof newModule.transform !== 'function') {
        throw new Error(prefix + ' is missing a *transform* function.');
    }
    if(!Lib.isPlainObject(newModule.attributes)) {
        Lib.log(prefix + ' registered without an *attributes* object.');
    }
    if(typeof newModule.supplyDefaults !== 'function') {
        Lib.log(prefix + ' registered without a *supplyDefaults* function.');
    }

    Plots.transformsRegistry[newModule.name] = newModule;
}
<|endoftext|>


<commit_before>PLUGINS.imagemap = function(api, area, corner, adjustMethod)
{
	if(!area.jquery) { area = $(area); }

	var shape = area.attr('shape').toLowerCase().replace('poly', 'polygon'),
		image = $('img[usemap="#'+area.parent('map').attr('name')+'"]'),
		coordsString = $.trim(area.attr('coords')),
		coordsArray = coordsString.replace(/,$/, '').split(','),
		imageOffset, coords, i, next, result, len;

	// If we can't find the image using the map...
	if(!image.length) { return FALSE; }

	// Pass coordinates string if polygon
	if(shape === 'polygon') {
		result = PLUGINS.polys.polygon(coordsArray, corner);
	}

	// Otherwise parse the coordinates and pass them as arguments
	else if(PLUGINS.polys[shape]) {
		for(i = -1, len = coordsArray.length, coords = []; ++i < len;) {
			coords.push( parseInt(coordsArray[i], 10) );
		}

		result = PLUGINS.polys[shape].apply(
			this, coords.concat(corner)
		);
	}

	// If no shapre calculation method was found, return false
	else { return FALSE; }

	// Make sure we account for padding and borders on the image
	imageOffset = image.offset();
	imageOffset.left += Math.ceil((image.outerWidth(FALSE) - image.width()) / 2);
	imageOffset.top += Math.ceil((image.outerHeight(FALSE) - image.height()) / 2);

	// Add image position to offset coordinates
	result.position.left += imageOffset.left;
	result.position.top += imageOffset.top;

	return result;
};<commit_msg>Assume default 'rect' shape if non defined. Fixes #631<commit_after>PLUGINS.imagemap = function(api, area, corner, adjustMethod)
{
	if(!area.jquery) { area = $(area); }

	var shape = (area.attr('shape') || 'rect').toLowerCase().replace('poly', 'polygon'),
		image = $('img[usemap="#'+area.parent('map').attr('name')+'"]'),
		coordsString = $.trim(area.attr('coords')),
		coordsArray = coordsString.replace(/,$/, '').split(','),
		imageOffset, coords, i, next, result, len;

	// If we can't find the image using the map...
	if(!image.length) { return FALSE; }

	// Pass coordinates string if polygon
	if(shape === 'polygon') {
		result = PLUGINS.polys.polygon(coordsArray, corner);
	}

	// Otherwise parse the coordinates and pass them as arguments
	else if(PLUGINS.polys[shape]) {
		for(i = -1, len = coordsArray.length, coords = []; ++i < len;) {
			coords.push( parseInt(coordsArray[i], 10) );
		}

		result = PLUGINS.polys[shape].apply(
			this, coords.concat(corner)
		);
	}

	// If no shapre calculation method was found, return false
	else { return FALSE; }

	// Make sure we account for padding and borders on the image
	imageOffset = image.offset();
	imageOffset.left += Math.ceil((image.outerWidth(FALSE) - image.width()) / 2);
	imageOffset.top += Math.ceil((image.outerHeight(FALSE) - image.height()) / 2);

	// Add image position to offset coordinates
	result.position.left += imageOffset.left;
	result.position.top += imageOffset.top;

	return result;
};<|endoftext|>


<commit_before>var compiler = bolt.compiler = bolt.compiler || {};
compiler.bootstrap = compiler.bootstrap || {};
compiler.core = compiler.core || {};
compiler.config = compiler.config || {};
compiler.load = compiler.load || {};
compiler.mode = compiler.mode || {};
compiler.output = compiler.output || {};
compiler.tools = compiler.tools || {};
<commit_msg>module list<commit_after>var compiler = bolt.compiler = bolt.compiler || {};
compiler.bootstrap = compiler.bootstrap || {};
compiler.core = compiler.core || {};
compiler.compile= compiler.compile || {};
compiler.config = compiler.config || {};
compiler.load = compiler.load || {};
compiler.mode = compiler.mode || {};
compiler.output = compiler.output || {};
compiler.tools = compiler.tools || {};
<|endoftext|>


<commit_before>import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App';
import routeConfig from './routeConfig';

Vue.use(VueRouter);
App.router = new VueRouter(routeConfig);
/* eslint-disable */
const app = new Vue(App).$mount('#app');
<commit_msg>add polyfill for 'require.ensure'<commit_after>import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App';
import routeConfig from './routeConfig';
import promise from 'es6-promise';

// webpack的require.ensure方法用到浏览器Promise
// 此处polyfill主要是对IE浏览器的支持
promise.polyfill();
Vue.use(VueRouter);
App.router = new VueRouter(routeConfig);
/* eslint-disable */
const app = new Vue(App).$mount('#app');
<|endoftext|>


<commit_before>/**
 * The root level reducer for the app.
 * @module reducer
 **/

import { combineReducers } from 'redux';
import {
	CLICK_TRACK_ACTION,
	CLICK_TRACK_CLEAR_ACTION
} from '../actions/clickActionCreators';

export const DEFAULT_APP_STATE = {};

/**
 * The primary reducer for data provided by the API
 * `state.app` sub-tree
 *
 * @param {Object} state
 * @param {ReduxAction} action
 * @return {Object}
 */
export function app(state=DEFAULT_APP_STATE, action={}) {
	let newState;

	switch (action.type) {
	case 'API_REQUEST':
		if (action.meta.logout) {
			return DEFAULT_APP_STATE;  // clear app state during logout
		}
		return state;
	case 'CACHE_SUCCESS':  // fall through - same effect as API success
	case 'API_SUCCESS':
		// API_SUCCESS contains an array of responses, but we just need to build a single
		// object to update state with
		newState = action.payload.responses.reduce((s, r) => ({ ...s, ...r }), {});
		delete state.error;
		return { ...state, ...newState };
	case 'API_ERROR':
		return {
			...state,
			error: action.payload
		};
	default:
		return state;
	}
}

export const DEFAULT_CLICK_TRACK = { clicks: [] };
/**
 * @param {Object} data extensible object to store click data {
 *   clicks: array
 * }
 * @param {Object} action the dispatched action
 * @return {Object} new state
 */
export function clickTracking(state=DEFAULT_CLICK_TRACK, action) {
	if (action.type === CLICK_TRACK_ACTION) {
		const clicks = [
			...state.clicks,
			action.payload,
		];
		return {
			...state,
			clicks,
		};
	}
	if (action.type === CLICK_TRACK_CLEAR_ACTION) {
		return DEFAULT_CLICK_TRACK;
	}
	return state;
}

export function config(state={}, action) {
	let apiUrl,
		trackId;

	switch(action.type) {
	case 'CONFIGURE_API_URL':
		apiUrl = action.payload;
		return { ...state, apiUrl };
	case 'CONFIGURE_TRACKING_ID':
		trackId = action.payload;
		return { ...state, trackId };
	default:
		return state;
	}
}

/**
 * This reducer manages a list of boolean flags that indicate the 'ready to
 * render' state of the application. It is used exclusively by the server,
 * which triggers actions when initializing a response that should eventually
 * make all flags 'true'
 *
 * The server can then read these flags from state and render when ready
 */
export function preRenderChecklist([apiDataLoaded] = [false], action) {
	return [
		apiDataLoaded || Boolean(['API_COMPLETE', 'API_ERROR'].find(type => type === action.type)),
	];
}

const platformReducers = {
	app,
	clickTracking,
	config,
	preRenderChecklist,
};

/**
 * A function that builds a reducer combining platform-standard reducers and
 * app-specific reducers
 */
export default function makeRootReducer(appReducers={}) {
	Object.keys(appReducers).forEach(reducer => {
		if (reducer in platformReducers) {
			throw new Error(`'${reducer}' is a reserved platform reducer name`);
		}
	});
	return combineReducers({
		...platformReducers,
		...appReducers,
	});
}

<commit_msg>match format of click-track data<commit_after>/**
 * The root level reducer for the app.
 * @module reducer
 **/

import { combineReducers } from 'redux';
import {
	CLICK_TRACK_ACTION,
	CLICK_TRACK_CLEAR_ACTION
} from '../actions/clickActionCreators';

export const DEFAULT_APP_STATE = {};

/**
 * The primary reducer for data provided by the API
 * `state.app` sub-tree
 *
 * @param {Object} state
 * @param {ReduxAction} action
 * @return {Object}
 */
export function app(state=DEFAULT_APP_STATE, action={}) {
	let newState;

	switch (action.type) {
	case 'API_REQUEST':
		if (action.meta.logout) {
			return DEFAULT_APP_STATE;  // clear app state during logout
		}
		return state;
	case 'CACHE_SUCCESS':  // fall through - same effect as API success
	case 'API_SUCCESS':
		// API_SUCCESS contains an array of responses, but we just need to build a single
		// object to update state with
		newState = action.payload.responses.reduce((s, r) => ({ ...s, ...r }), {});
		delete state.error;
		return { ...state, ...newState };
	case 'API_ERROR':
		return {
			...state,
			error: action.payload
		};
	default:
		return state;
	}
}

export const DEFAULT_CLICK_TRACK = { history: [] };
/**
 * @param {Object} data extensible object to store click data {
 *   history: array
 * }
 * @param {Object} action the dispatched action
 * @return {Object} new state
 */
export function clickTracking(state=DEFAULT_CLICK_TRACK, action) {
	if (action.type === CLICK_TRACK_ACTION) {
		const history = [
			...state.history,
			action.payload,
		];
		return {
			...state,
			history,
		};
	}
	if (action.type === CLICK_TRACK_CLEAR_ACTION) {
		return DEFAULT_CLICK_TRACK;
	}
	return state;
}

export function config(state={}, action) {
	let apiUrl,
		trackId;

	switch(action.type) {
	case 'CONFIGURE_API_URL':
		apiUrl = action.payload;
		return { ...state, apiUrl };
	case 'CONFIGURE_TRACKING_ID':
		trackId = action.payload;
		return { ...state, trackId };
	default:
		return state;
	}
}

/**
 * This reducer manages a list of boolean flags that indicate the 'ready to
 * render' state of the application. It is used exclusively by the server,
 * which triggers actions when initializing a response that should eventually
 * make all flags 'true'
 *
 * The server can then read these flags from state and render when ready
 */
export function preRenderChecklist([apiDataLoaded] = [false], action) {
	return [
		apiDataLoaded || Boolean(['API_COMPLETE', 'API_ERROR'].find(type => type === action.type)),
	];
}

const platformReducers = {
	app,
	clickTracking,
	config,
	preRenderChecklist,
};

/**
 * A function that builds a reducer combining platform-standard reducers and
 * app-specific reducers
 */
export default function makeRootReducer(appReducers={}) {
	Object.keys(appReducers).forEach(reducer => {
		if (reducer in platformReducers) {
			throw new Error(`'${reducer}' is a reserved platform reducer name`);
		}
	});
	return combineReducers({
		...platformReducers,
		...appReducers,
	});
}

<|endoftext|>


<commit_before>import Immutable from 'immutable';
import { CALL_API } from 'redux-api-middleware';
import { getError } from './common/utils';

import {
  FETCH_FLICKR_BEGIN,
  FETCH_FLICKR_SUCCESS,
  FETCH_FLICKR_FAILURE,
  FETCH_FLICKR_DISMISS_ERROR,
} from './common/constants';

import flickr from './common/flickr';
const endpointUrl = `${flickr.endpoint}/?method=flickr.photos.search&api_key=${flickr.apiKey}&${flickr.alwaysParameters}&tags=`;

export function fetchFlickr(searchTags, fromIndex = 1) {
  return {
    [CALL_API]: {
      endpoint: endpointUrl + searchTags + "&page=" + fromIndex,
      method: 'GET',
      types: [
        {
          type: FETCH_FLICKR_BEGIN,
          meta: {
            searchTags,
            fromIndex
          },
        },
        {
          type: FETCH_FLICKR_SUCCESS,
          meta: {
            searchTags,
            fromIndex
          },
        },
        {
          type: FETCH_FLICKR_FAILURE,
          meta: {
            searchTags,
            fromIndex
          },
        }
      ]
    }
  };
}

export function dismissFetchFlickrError() {
  return {
    type: FETCH_FLICKR_DISMISS_ERROR,
  };
}

function parsePhotos (state, action) {
  const flickrApiResponse = action.payload;
  const { page, pages, perpage, total, photo } = flickrApiResponse.photos;

  const photos = photo.map(function(p){
    return {
      url: `https://farm${p.farm}.staticflickr.com/${p.server}/${p.id}_${p.secret}.jpg`,
      title: p.title,
      owner: p.owner,
    };
  });

  const results = {
    page, // changes
    pages,
    perpage,
    total,
    photos, // changes
  };

  if(page > 1) {
    const previousPhotos = state.get('fetchFlickrResults').get('photos').toJS();
    // console.log("Previous Photos", previousPhotos);
    results.photos = (previousPhotos || []).concat(photos);
  }

  // console.log("parsePhotos results", results);
  return results;
}

export function reducer(state, action) {
  switch (action.type) {
    case FETCH_FLICKR_BEGIN: {
      const beginResponse = action.error ? getError(action) : (action.payload || {});       // If error is true, then payload is a RequestError
      return state
          .set('fetchFlickrTags', action.meta.searchTags)
          .set('fetchFlickerFromIndex', action.meta.fromIndex)
          .set('fetchFlickrError', action.error ? Immutable.fromJS(getError(beginResponse)) : null)
          .set('fetchFlickrPending', !action.error);          // Set pending to inverse of error
    }
    case FETCH_FLICKR_SUCCESS: {
      return state
        .set('fetchFlickrPending', false)
        .set('fetchFlickrError', null)
        .set('fetchFlickrTags', action.meta.searchTags)
        .set('fetchFlickerFromIndex', action.meta.fromIndex)
        // Note: Append the results here, not overwrite them
        .set('fetchFlickrResults', Immutable.fromJS(parsePhotos(state, action)));
    }
    case FETCH_FLICKR_FAILURE: {
      const failResponse = getError(action);
      return state
        .set('fetchFlickrPending', false)
        .set('fetchFlickrError', Immutable.fromJS(failResponse));
    }
    case FETCH_FLICKR_DISMISS_ERROR:
      return state.set('fetchFlickrError', null);
    default:
      return state;
  }
}
<commit_msg>Encode uri parameters from user<commit_after>import Immutable from 'immutable';
import { CALL_API } from 'redux-api-middleware';
import { getError } from './common/utils';

import {
  FETCH_FLICKR_BEGIN,
  FETCH_FLICKR_SUCCESS,
  FETCH_FLICKR_FAILURE,
  FETCH_FLICKR_DISMISS_ERROR,
} from './common/constants';

import flickr from './common/flickr';
const endpointUrl = `${flickr.endpoint}/?method=flickr.photos.search&api_key=${flickr.apiKey}&${flickr.alwaysParameters}&tags=`;

export function fetchFlickr(searchTags, fromIndex = 1) {
  return {
    [CALL_API]: {
      endpoint: endpointUrl + encodeURIComponent(searchTags) + "&page=" + fromIndex,
      method: 'GET',
      types: [
        {
          type: FETCH_FLICKR_BEGIN,
          meta: {
            searchTags,
            fromIndex
          },
        },
        {
          type: FETCH_FLICKR_SUCCESS,
          meta: {
            searchTags,
            fromIndex
          },
        },
        {
          type: FETCH_FLICKR_FAILURE,
          meta: {
            searchTags,
            fromIndex
          },
        }
      ]
    }
  };
}

export function dismissFetchFlickrError() {
  return {
    type: FETCH_FLICKR_DISMISS_ERROR,
  };
}

function parsePhotos (state, action) {
  const flickrApiResponse = action.payload;
  const { page, pages, perpage, total, photo } = flickrApiResponse.photos;

  const photos = photo.map(function(p){
    return {
      url: `https://farm${p.farm}.staticflickr.com/${p.server}/${p.id}_${p.secret}.jpg`,
      title: p.title,
      owner: p.owner,
    };
  });

  const results = {
    page, // changes
    pages,
    perpage,
    total,
    photos, // changes
  };

  if(page > 1) {
    const previousPhotos = state.get('fetchFlickrResults').get('photos').toJS();
    // console.log("Previous Photos", previousPhotos);
    results.photos = (previousPhotos || []).concat(photos);
  }

  // console.log("parsePhotos results", results);
  return results;
}

export function reducer(state, action) {
  switch (action.type) {
    case FETCH_FLICKR_BEGIN: {
      const beginResponse = action.error ? getError(action) : (action.payload || {});       // If error is true, then payload is a RequestError
      return state
          .set('fetchFlickrTags', action.meta.searchTags)
          .set('fetchFlickerFromIndex', action.meta.fromIndex)
          .set('fetchFlickrError', action.error ? Immutable.fromJS(getError(beginResponse)) : null)
          .set('fetchFlickrPending', !action.error);          // Set pending to inverse of error
    }
    case FETCH_FLICKR_SUCCESS: {
      return state
        .set('fetchFlickrPending', false)
        .set('fetchFlickrError', null)
        .set('fetchFlickrTags', action.meta.searchTags)
        .set('fetchFlickerFromIndex', action.meta.fromIndex)
        // Note: Append the results here, not overwrite them
        .set('fetchFlickrResults', Immutable.fromJS(parsePhotos(state, action)));
    }
    case FETCH_FLICKR_FAILURE: {
      const failResponse = getError(action);
      return state
        .set('fetchFlickrPending', false)
        .set('fetchFlickrError', Immutable.fromJS(failResponse));
    }
    case FETCH_FLICKR_DISMISS_ERROR:
      return state.set('fetchFlickrError', null);
    default:
      return state;
  }
}
<|endoftext|>


<commit_before>cls.ReplService = function(view, data)
{
  if (cls.ReplService.instance)
  {
    return cls.ReplService.instance;
  }
  cls.ReplService.instance = this;

  this._on_consolelog = function(msg)
  {
    var type = msg[1];
    /**
     * This value indicates which function was called:
     *
     * 1 - console.log
     * 2 - console.debug
     * 3 - console.info
     * 4 - console.warn
     * 5 - console.error
     * 6 - console.assert
     * 7 - console.dir
     * 8 - console.dirxml
     * 9 - console.group
     * 10 - console.groupCollapsed
     * 11 - console.groupEnded
     * 12 - console.count
     */

    switch(type)
    {
      case 1:
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
        this._handle_log(msg);
        break;
      case 7:
        this._handle_dir(msg);
        break;
    }
  };

  this._on_consoletime = function(msg)
  {
    const TITLE = 1;
    this._data.add_output_str("Started: " + msg[TITLE]);
  };

  this._on_consoletimeend = function(msg)
  {
    const TITLE = 1, DURATION = 2;
    var dur = msg[DURATION];
    var ms = Math.round(dur / 1000);
    this._data.add_output_str(msg[TITLE] + ": " + ms + "ms (" + dur + "µsec)" );
  };

  this._handle_log = function(msg)
  {

  };

  this._handle_dir = function(msg)
  {
    var rt = msg[0];
    var obj = msg[2][0][1][0];
     this._data.add_output_iobj(rt, obj, "fixme");
  };

  this._on_eval_done = function(status, msg, rt_id, thread_id, frame_id)
  {
    const STATUS = 0, TYPE = 1;

    if (msg[STATUS] == "unhandled-exception")
    {
      this._handle_exception(msg, rt_id);
    }
    else if (msg[TYPE] == "object")
    {
      this._handle_object(msg, rt_id);
    }
    else
    {
      this._handle_native(msg);
    }
  };

  this._handle_exception = function(msg, rt_id)
  {
    const VALUE = 2;
    this._get_exception_info(rt_id, msg[3][0]);
  };

  this._handle_object = function(msg, rt_id)
  {
    const TYPE = 1, OBJVALUE = 3;
    const OBJID = 0, CLASS = 4; FUNCTION = 5;

    var obj = msg[OBJVALUE];
    this._data.add_output_pobj(rt_id, obj[OBJID], obj[FUNCTION] || obj[CLASS]);
  };

  this._handle_native = function(msg)
  {
    const VALUE = 2;
    const TYPE = 1;
    var type = msg[TYPE];
    var val = msg[VALUE];

    switch(type)
    {
      case "null":
      case "undefined":
        val = type;
        break;
      case "string":
        val = '"' + val + '"';
        break;
    }

    this._data.add_output_str(val);
  };

  this._get_exception_info = function(rt, obj)
  {
    var tag = this._tagman.set_callback(this, this._on_get_exception_info.bind(this));
    this._service.requestExamineObjects(tag, [rt, [obj], 0, 0, 1]);
  };

  this._on_get_exception_info = function(status, msg)
  {
    var props = {};
    var propslist = msg[0][0][0][0][1];
    for (var n=0, e; e=propslist[n]; n++)
    {
      props[e[0]] = e[2];
    }

    this._data.add_output_exception(props.message, props.stacktrace);
  };

  this.handle_input = function(input)
  {
    this._data.add_input(input);
    this._evaluate_input(input);
  }.bind(this);

  this._evaluate_input = function(input)
  {
    var rt_id = runtimes.getSelectedRuntimeId();
    var thread = window.stop_at.getThreadId();
    var frame = window.stop_at.getSelectedFrameIndex();
    if (frame == -1)
    {
      thread = 0;
      frame = 0;
    }

    var cooked = this._transformer.transform(input);
    var tag = this._tagman.set_callback(this, this._on_eval_done.bind(this), [rt_id, thread, frame]);
    this._service.requestEval(tag, [rt_id, thread, frame, cooked]);
  };

  this.init = function(view, data)
  {
    this._view = view;
    this._data = data;
    this._transformer = new HostCommandTransformer();
    this._tagman = window.tagManager; //TagManager.getInstance(); <- fixme: use singleton
    this._service = window.services['ecmascript-debugger'];
    this._service.addListener("consolelog", this._on_consolelog.bind(this));
    this._service.addListener("consoletime", this._on_consoletime.bind(this));
    this._service.addListener("consoletimeend", this._on_consoletimeend.bind(this));
  };

  this.init(view, data);
};
<commit_msg>Use proper class name for commandtransformer<commit_after>cls.ReplService = function(view, data)
{
  if (cls.ReplService.instance)
  {
    return cls.ReplService.instance;
  }
  cls.ReplService.instance = this;

  this._on_consolelog = function(msg)
  {
    var type = msg[1];
    /**
     * This value indicates which function was called:
     *
     * 1 - console.log
     * 2 - console.debug
     * 3 - console.info
     * 4 - console.warn
     * 5 - console.error
     * 6 - console.assert
     * 7 - console.dir
     * 8 - console.dirxml
     * 9 - console.group
     * 10 - console.groupCollapsed
     * 11 - console.groupEnded
     * 12 - console.count
     */

    switch(type)
    {
      case 1:
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
        this._handle_log(msg);
        break;
      case 7:
        this._handle_dir(msg);
        break;
    }
  };

  this._on_consoletime = function(msg)
  {
    const TITLE = 1;
    this._data.add_output_str("Started: " + msg[TITLE]);
  };

  this._on_consoletimeend = function(msg)
  {
    const TITLE = 1, DURATION = 2;
    var dur = msg[DURATION];
    var ms = Math.round(dur / 1000);
    this._data.add_output_str(msg[TITLE] + ": " + ms + "ms (" + dur + "µsec)" );
  };

  this._handle_log = function(msg)
  {

  };

  this._handle_dir = function(msg)
  {
    var rt = msg[0];
    var obj = msg[2][0][1][0];
     this._data.add_output_iobj(rt, obj, "fixme");
  };

  this._on_eval_done = function(status, msg, rt_id, thread_id, frame_id)
  {
    const STATUS = 0, TYPE = 1;

    if (msg[STATUS] == "unhandled-exception")
    {
      this._handle_exception(msg, rt_id);
    }
    else if (msg[TYPE] == "object")
    {
      this._handle_object(msg, rt_id);
    }
    else
    {
      this._handle_native(msg);
    }
  };

  this._handle_exception = function(msg, rt_id)
  {
    const VALUE = 2;
    this._get_exception_info(rt_id, msg[3][0]);
  };

  this._handle_object = function(msg, rt_id)
  {
    const TYPE = 1, OBJVALUE = 3;
    const OBJID = 0, CLASS = 4; FUNCTION = 5;

    var obj = msg[OBJVALUE];
    this._data.add_output_pobj(rt_id, obj[OBJID], obj[FUNCTION] || obj[CLASS]);
  };

  this._handle_native = function(msg)
  {
    const VALUE = 2;
    const TYPE = 1;
    var type = msg[TYPE];
    var val = msg[VALUE];

    switch(type)
    {
      case "null":
      case "undefined":
        val = type;
        break;
      case "string":
        val = '"' + val + '"';
        break;
    }

    this._data.add_output_str(val);
  };

  this._get_exception_info = function(rt, obj)
  {
    var tag = this._tagman.set_callback(this, this._on_get_exception_info.bind(this));
    this._service.requestExamineObjects(tag, [rt, [obj], 0, 0, 1]);
  };

  this._on_get_exception_info = function(status, msg)
  {
    var props = {};
    var propslist = msg[0][0][0][0][1];
    for (var n=0, e; e=propslist[n]; n++)
    {
      props[e[0]] = e[2];
    }

    this._data.add_output_exception(props.message, props.stacktrace);
  };

  this.handle_input = function(input)
  {
    this._data.add_input(input);
    this._evaluate_input(input);
  }.bind(this);

  this._evaluate_input = function(input)
  {
    var rt_id = runtimes.getSelectedRuntimeId();
    var thread = window.stop_at.getThreadId();
    var frame = window.stop_at.getSelectedFrameIndex();
    if (frame == -1)
    {
      thread = 0;
      frame = 0;
    }

    var cooked = this._transformer.transform(input);
    var tag = this._tagman.set_callback(this, this._on_eval_done.bind(this), [rt_id, thread, frame]);
    this._service.requestEval(tag, [rt_id, thread, frame, cooked]);
  };

  this.init = function(view, data)
  {
    this._view = view;
    this._data = data;
    this._transformer = new cls.HostCommandTransformer();
    this._tagman = window.tagManager; //TagManager.getInstance(); <- fixme: use singleton
    this._service = window.services['ecmascript-debugger'];
    this._service.addListener("consolelog", this._on_consolelog.bind(this));
    this._service.addListener("consoletime", this._on_consoletime.bind(this));
    this._service.addListener("consoletimeend", this._on_consoletimeend.bind(this));
  };

  this.init(view, data);
};
<|endoftext|>


<commit_before>var chalk = require('chalk');

function pad(t, length, char) {
	t = '' + t;
	var missing = Math.max(length - t.length, 0);
	return new Array(missing + 1).join(char) + t;
}

function renderError(message, code, filename) {
	console.log(chalk.bold(message) + ' [' + code + '] at ' + chalk.green(filename));
}

function renderLine(n, line) {
	line = line.replace(/\t/g, ' ');
	console.log(chalk.grey(pad(n, 6, ' ')) + ' |' + line);
}

function renderPointer(column) {
	console.log(chalk.grey(pad('^', column + 8, '-')));
}

module.exports = function(err, lints) {
	if (err) {
		console.log(chalk.bold.red('Error' + (err.length > 1 ? 's' : '') + ':'));
		for (var i = 0; i < err.length; i++) {
			var e = err[i];
			console.log(' * ' + chalk.red(typeof e === 'string' ? e : e.message));
			if (e.stack) {
				console.log(e.stack.replace(/.*\n/, '') + '\n');
			}
		}
	}

	if (lints.length) {
		if (err) console.log('\n' + chalk.bold.yellow('Lint' + (lints.length > 1 ? 's' : '') + ':'));
		lints.forEach(function(file) {
			var lines = file.lines;
			var path = file.file;
			file.errors.forEach(function(error) {
				var line = error.line;
				renderError(error.message, error.code, path);
				for (var i = Math.max(line - 2, 1); i <= line; i++) {
					renderLine(i, lines[i - 1]);
				}
				renderPointer(error.column);
				for (i = line + 1; i < lines.length && i <= line + 2; i++) {
					renderLine(i, lines[i - 1]);
				}
			});
		});
	}
};
<commit_msg>Add status message at the end of default reporter<commit_after>var chalk = require('chalk');

var okMsg = [
	"It's time to relax.",
	'Well done.',
	'Good job.',
	'Congratulations.',
	"I'm so proud of you.",
	'Hooray!',
	"You've got a Crockford point.",
	"You've got a Stephen C. Johnson point.",
	'Great! How about some chocolate as recompense?',
	'Commit time!'
];

var failMsg = [
	'Good luck to fix that.',
	'Argh, more work needed!!',
	"I'm a broken robot, please fix my code.",
	'Fix that before anyone notice.',
	'Douglas Crockford will be sad.',
	'Goodbye cruel world.',
	'Ooops.',
	'Dura lex sed lex.',
	'By ignorance we mistake, and by mistakes we learn.',
	'Your mission, should you decide to accept it, is to fix that.' +
		'This tape will self-destruct in five seconds. Good luck, Jim!'
];

function pad(t, length, char) {
	t = '' + t;
	var missing = Math.max(length - t.length, 0);
	return new Array(missing + 1).join(char) + t;
}

function getError(message, code, filename) {
	return chalk.bold(message) + ' [' + code + '] at ' + chalk.green(filename);
}

function getLine(n, line) {
	line = line.replace(/\t/g, ' ');
	return chalk.grey(pad(n, 6, ' ')) + ' |' + line;
}

function getPointer(column) {
	return chalk.grey(pad('^', column + 8, '-'));
}

module.exports = function(err, lints) {
	var nbLints = 0;
	if (err) {
		console.log(chalk.bold.red('Error' + (err.length > 1 ? 's' : '') + ':'));
		for (var i = 0; i < err.length; i++) {
			var e = err[i];
			console.log(' * ' + chalk.red(typeof e === 'string' ? e : e.message));
			if (e.stack) {
				console.log(e.stack.replace(/.*\n/, '') + '\n');
			}
		}
	}

	if (lints.length) {
		var report = [];
		lints.forEach(function(file) {
			var lines = file.lines;
			var path = file.file;
			file.errors.forEach(function(error) {
				nbLints++;
				var line = error.line;
				report.push(getError(error.message, error.code, path));
				for (var i = Math.max(line - 2, 1); i <= line; i++) {
					report.push(getLine(i, lines[i - 1]));
				}
				report.push(getPointer(error.column));
				for (i = line + 1; i < lines.length && i <= line + 2; i++) {
					report.push(getLine(i, lines[i - 1]));
				}
			});
		});
		if (err) console.log('\n' + chalk.bold.yellow('Lint' + (nbLints > 1 ? 's' : '') + ':'));
		console.log(report.join('\n'));
	}

	var msg, quoteArray;
	if (err || nbLints) {
		var nb = (err ? err.length : 0) + nbLints;
		msg = 'Found ' + chalk.bold.red(nb + ' error' + (nb > 1 ? 's' : '')) + '.';
		quoteArray = failMsg;
	} else {
		msg = 'Everything is ' + chalk.bold.green('ok') + '.';
		quoteArray = okMsg;
	}
	console.log('\n' + msg + ' ' + quoteArray[Math.floor(Math.random() * quoteArray.length)] + '\n');
};
<|endoftext|>


<commit_before>/* global describe, it, expect, jest, afterEach */
import React from "react";
import { Container, createStore, enableHistory, Link, Match } from "../main";
import {
  updateHistory,
  debounce,
  stringifyStoreDataHelper,
  extractStoreFromLocation,
  filter
} from "./index";
import renderer from "react-test-renderer";
import { mount } from "enzyme";

const url =
  "http://example.com/page1?queryParam=queryValue&a[]=1&a[]=2&storeData=%7B%22counter%22%3A%7B%22value%22%3A1%7D%2C%22counter2%22%3A%7B%22value%22%3A2%7D%7D";

describe("router/index", () => {
  describe("filter", () => {
    it("returns the given object unmodified if filter is not defined", () => {
      const data = {
        a: 1,
        b: 2
      };
      expect(filter(data)).toEqual(data);
      expect(filter(data, null)).toEqual(data);
    });

    it("throws an error if filters is defined but not an array", () => {
      const fn = () => filter({}, "sdd");
      expect(fn).toThrow();
    });

    it("returns subset of the given data object based on the filters key", () => {
      const data = {
        a: 1,
        b: 2,
        c: 3,
        d: 4
      };
      expect(filter(data, ["b", "d"])).toEqual({ b: 2, d: 4 });
    });
  });

  describe("stringifyStoreDataHelper", () => {
    it("encodes data into uri as JSON encoded storeData query parameter", () => {
      const data = { prop1: "value", prop2: 10 };
      const result = stringifyStoreDataHelper(data);
      const expected = `storeData=%7B%22prop1%22%3A%22value%22%2C%22prop2%22%3A10%7D`;
      expect(result).toEqual(expected);
    });

    it("appends store data to end of an existing query", () => {
      const data = {};
      const query = `?storeData={"prop":2}&foo=bar`;
      expect(stringifyStoreDataHelper(data, query)).toEqual(
        "foo=bar&storeData=%7B%7D"
      );
    });
  });

  describe("extractStoreFromLocation", () => {
    it("extracts storeData parameter from query string", () => {
      const query = `?storeData={"prop":2}&foo=bar`;
      expect(extractStoreFromLocation(query)).toEqual({ prop: 2 });
    });

    it("returns an empty object if the no store is found or its baddly formed", () => {
      expect(extractStoreFromLocation("")).toEqual({});
      expect(extractStoreFromLocation(`storeData={"`)).toEqual({});
    });
  });

  describe("enableHistory", () => {
    describe("on initial page load", () => {
      let unsubscribe = null;

      afterEach(() => {
        if (unsubscribe) unsubscribe();
        history.pushState(null, null, url);
      });

      it("syncs the url to the store", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        expect(store.get("location")).toHaveProperty("href", url);
      });

      it("syncs the pathname to the store", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);

        expect(store.get("location")).toHaveProperty("pathname", "/page1");
      });

      it("syncs the query string to the store", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);

        expect(store.get("location")).toHaveProperty(
          "queryString",
          "?queryParam=queryValue&a[]=1&a[]=2&storeData=%7B%22counter%22%3A%7B%22value%22%3A1%7D%2C%22counter2%22%3A%7B%22value%22%3A2%7D%7D"
        );
      });

      it("syncs storeData from the query parameters to the store", () => {
        const store = createStore();
        unsubscribe = enableHistory(store, ["counter", "counter2"]);

        expect(store.get("counter")).toEqual({ value: 1 });
        expect(store.get("counter2")).toEqual({ value: 2 });
      });
    });

    describe("on history change", () => {
      let unsubscribe = null;

      afterEach(() => {
        if (unsubscribe) unsubscribe();
        history.pushState(null, null, url);
      });

      it("syncs browser location changes to the store", done => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        const assertions = [
          () => {
            expect(store.get("location")).toHaveProperty("href", url);
            expect(store.get("location")).toHaveProperty("pathname", "/page1");
          },

          () => {
            expect(store.get("location")).toHaveProperty(
              "href",
              "http://example.com/page2"
            );
            expect(store.get("location")).toHaveProperty("pathname", "/page2");
            expect(store.get("location")).toHaveProperty("queryString", "");
          },

          () => {
            expect(store.get("location")).toHaveProperty(
              "href",
              "http://example.com/page3?queryParam=queryValue&a[]=1&a[]=2"
            );
            expect(store.get("location")).toHaveProperty("pathname", "/page3");
            expect(store.get("location")).toHaveProperty(
              "queryString",
              "?queryParam=queryValue&a[]=1&a[]=2"
            );
          }
        ];

        store.subscribe(() => {
          const assert = assertions.pop();

          try {
            assert();
          } catch (error) {
            done(error);
          }

          if (assertions.length === 0) {
            return done();
          }

          history.back();
        });

        history.pushState(null, null, "/page2");
        history.pushState(
          null,
          null,
          "/page3?queryParam=queryValue&a[]=1&a[]=2"
        );
        history.pushState(null, null, "/ignored");
        history.back();
      });

      it("syncs registered storeData from location to the store", done => {
        const store = createStore();
        unsubscribe = enableHistory(store, ["counter", "counter2"]);
        const assertions = [
          () => {
            expect(store.get("counter")).toEqual({ value: 1 });
            expect(store.get("counter2")).toEqual({ value: 2 });
          },
          () => {
            expect(store.get("counter")).toEqual({ value: 2 });
            expect(store.get("counter2")).toEqual({ value: 3 });
          }
        ];

        store.subscribe(() => {
          const assert = assertions.pop();

          try {
            assert();
          } catch (error) {
            done(error);
          }

          if (assertions.length === 0) {
            return done();
          }
          history.back();
        });

        history.pushState(
          null,
          null,
          "http://example.com/page1?queryParam=queryValue&a[]=1&a[]=2&storeData=%7B%22counter%22%3A%7B%22value%22%3A2%7D%2C%22counter2%22%3A%7B%22value%22%3A3%7D%7D"
        );
        history.pushState(null, null, "/ignored");
        history.back();
      });

      it("changes made directly to the registered sync data in the store automatically update the browser location and store location", done => {
        const store = createStore();
        unsubscribe = enableHistory(store, ["counter", "counter2"]);

        const assertions = [
          () => {
            expect(store.get("counter")).toEqual({ value: 2 });
            expect(store.get("counter2")).toEqual({ value: 3 });
            expect(store.get("location")).toHaveProperty(
              "queryString",
              "?queryParam=queryValue&a[]=1&a[]=2&storeData=%7B%22counter%22%3A%7B%22value%22%3A2%7D%2C%22counter2%22%3A%7B%22value%22%3A3%7D%7D"
            );
          }
        ];

        store.subscribe(() => {
          const assert = assertions.pop();

          try {
            assert();
          } catch (error) {
            done(error);
          }

          if (assertions.length === 0) {
            return done();
          }
        });

        expect(store.get("counter")).toEqual({ value: 1 });
        expect(store.get("counter2")).toEqual({ value: 2 });
        store.setAll({ counter: { value: 2 }, counter2: { value: 3 } });
      });

      it("changes made directly to the replaceStateMountPoints in the store replace the browser location", done => {
        jest.useFakeTimers();

        const oldPush = window.history.pushState;
        const oldReplace = window.history.replaceState;

        const pushState = (window.history.pushState = jest.fn(
          oldPush.bind(window.history)
        ));
        const replaceState = (window.history.replaceState = jest.fn(
          oldReplace.bind(window.history)
        ));

        const store = createStore();
        expect(replaceState.mock.calls.length).toEqual(0);
        unsubscribe = enableHistory(store, ["counter"], ["counter2"], {
          debounceTime: 1000
        });
        expect(replaceState.mock.calls.length).toEqual(1);

        const assertions = [
          () => {
            expect(store.get("counter")).toEqual({ value: 2 });
            expect(store.get("counter2")).toEqual({ value: 2 });
            expect(pushState.mock.calls.length).toEqual(1);
            expect(replaceState.mock.calls.length).toEqual(1);
          },
          () => {
            expect(store.get("counter")).toEqual({ value: 2 });
            expect(store.get("counter2")).toEqual({ value: 3 });
            expect(pushState.mock.calls.length).toEqual(1);
            expect(replaceState.mock.calls.length).toEqual(1);
          },
          () => {
            expect(store.get("counter")).toEqual({ value: 3 });
            expect(store.get("counter2")).toEqual({ value: 3 });
            expect(pushState.mock.calls.length).toEqual(2);
            expect(replaceState.mock.calls.length).toEqual(1);
          },
          () => {
            expect(store.get("counter")).toEqual({ value: 3 });
            expect(store.get("counter2")).toEqual({ value: 4 });
            expect(pushState.mock.calls.length).toEqual(2);
            expect(replaceState.mock.calls.length).toEqual(1);
          }
        ];

        expect(store.get("counter")).toEqual({ value: 1 });
        expect(store.get("counter2")).toEqual({ value: 2 });

        store.subscribe(() => {
          const assert = assertions.shift();

          try {
            assert();
          } catch (error) {
            window.history.pushState = oldPush;
            window.history.replaceState = oldReplace;
            done(error);
          }

          if (assertions.length === 0) {
            jest.runOnlyPendingTimers();
            expect(replaceState.mock.calls.length).toEqual(2);
            window.history.pushState = oldPush;
            window.history.replaceState = oldReplace;
            return done();
          }
        });

        store.set("counter", { value: 2 }); // pushState
        store.set("counter2", { value: 3 }); // replaceState
        store.set("counter", { value: 3 }); // pushState
        store.set("counter2", { value: 4 }); // replaceState
      });
    });

    describe("Match", () => {
      let unsubscribe = null;

      afterEach(() => {
        if (unsubscribe) unsubscribe();
        history.pushState(
          null,
          null,
          "http://example.com/page1?queryParam=queryValue&a[]=1&a[]=2"
        );
      });

      it("only renders children if the window.location path matches", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        const childComponent = jest.fn(() => null);
        const Component = () => childComponent();

        renderer.create(
          <Container store={store}>
            <Match path="/page1">
              <Component />
            </Match>
          </Container>
        );
        expect(childComponent.mock.calls.length).toEqual(1);
      });

      it("does not render children if the window.location path does not match", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        const childComponent = jest.fn(() => null);
        const Component = () => childComponent();

        renderer.create(
          <Container store={store}>
            <Match path="/page2">
              <Component />
            </Match>
          </Container>
        );
        expect(childComponent.mock.calls.length).toEqual(0);
      });

      it("renders children when the store updates and the paths match", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        const childComponent = jest.fn(() => null);
        const Component = () => childComponent();

        renderer.create(
          <Container store={store}>
            <Match path="/page2">
              <Component />
            </Match>
          </Container>
        );
        expect(childComponent.mock.calls.length).toEqual(0);
        updateHistory(store, "/page2");
        expect(location.search).toEqual("");
        expect(childComponent.mock.calls.length).toEqual(1);
      });
    });

    describe("Link", () => {
      let unsubscribe = null;

      afterEach(() => {
        if (unsubscribe) unsubscribe();
        history.pushState(
          null,
          null,
          "http://example.com/page1?queryParam=queryValue&a[]=1&a[]=2"
        );
      });

      it("updates location and store when clicked on", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);

        const component = mount(
          <Container store={store}>
            <Link href="/page2" />
          </Container>
        );

        expect(store.get("location")).toHaveProperty("pathname", "/page1");
        component.simulate("click");
        expect(store.get("location")).toHaveProperty("pathname", "/page2");
      });
    });

    describe("debounce", () => {
      it("should fire a function after the debounce time", () => {
        jest.useFakeTimers();
        const callee = jest.fn();
        const timed = debounce(1000, callee);
        timed();
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(0);
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(1);
        jest.runOnlyPendingTimers();
      });

      it("should not trigger a pending call if interrupted by another", () => {
        jest.useFakeTimers();
        const callee = jest.fn();
        const timed = debounce(1000, callee);
        timed();
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(0);
        timed();
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(0);
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(1);
        jest.runOnlyPendingTimers();
      });

      it("should forward arguments for debounced function", () => {
        jest.useFakeTimers();
        const callee = jest.fn();
        const timed = debounce(1000, callee);
        timed("dick", "tracy");
        jest.runOnlyPendingTimers();
        expect(callee.mock.calls.length).toEqual(1);
        expect(callee.mock.calls[0]).toEqual(["dick", "tracy"]);
      });
    });
  });
});
<commit_msg>tests<commit_after>/* global describe, it, expect, jest, afterEach */
import React from "react";
import { Container, createStore, enableHistory, Link, Match } from "../main";
import {
  updateHistory,
  debounce,
  stringifyStoreDataHelper,
  extractStoreFromLocation,
  filter,
  getQuery
} from "./index";
import renderer from "react-test-renderer";
import { mount } from "enzyme";

const url =
  "http://example.com/page1?queryParam=queryValue&a[]=1&a[]=2&storeData=%7B%22counter%22%3A%7B%22value%22%3A1%7D%2C%22counter2%22%3A%7B%22value%22%3A2%7D%7D";

describe("router/index", () => {
  describe("filter", () => {
    it("returns the given object unmodified if filter is not defined", () => {
      const data = {
        a: 1,
        b: 2
      };
      expect(filter(data)).toEqual(data);
      expect(filter(data, null)).toEqual(data);
    });

    it("throws an error if filters is defined but not an array", () => {
      const fn = () => filter({}, "sdd");
      expect(fn).toThrow();
    });

    it("returns subset of the given data object based on the filters key", () => {
      const data = {
        a: 1,
        b: 2,
        c: 3,
        d: 4
      };
      expect(filter(data, ["b", "d"])).toEqual({ b: 2, d: 4 });
    });
  });

  describe("stringifyStoreDataHelper", () => {
    it("encodes data into uri as JSON encoded storeData query parameter", () => {
      const data = { prop1: "value", prop2: 10 };
      const result = stringifyStoreDataHelper(data);
      const expected = `storeData=%7B%22prop1%22%3A%22value%22%2C%22prop2%22%3A10%7D`;
      expect(result).toEqual(expected);
    });

    it("appends store data to end of an existing query", () => {
      const data = {};
      const query = `?storeData={"prop":2}&foo=bar`;
      expect(stringifyStoreDataHelper(data, query)).toEqual(
        "foo=bar&storeData=%7B%7D"
      );
    });

    it("filters data", () => {
      const data = { prop1: "value", prop2: 10 };
      const result = stringifyStoreDataHelper(data, "", ["prop2"]);
      const expected = `storeData=%7B%22prop2%22%3A10%7D`;
      expect(result).toEqual(expected);
    });
  });

  describe("extractStoreFromLocation", () => {
    it("extracts storeData parameter from query string", () => {
      const query = `?storeData={"prop":2}&foo=bar`;
      expect(extractStoreFromLocation(query)).toEqual({ prop: 2 });
    });

    it("returns an empty object if the no store is found or its baddly formed", () => {
      expect(extractStoreFromLocation("")).toEqual({});
      expect(extractStoreFromLocation(`storeData={"`)).toEqual({});
    });
  });

  describe("enableHistory", () => {
    describe("on initial page load", () => {
      let unsubscribe = null;

      afterEach(() => {
        if (unsubscribe) unsubscribe();
        history.pushState(null, null, url);
      });

      it("syncs the url to the store", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        expect(store.get("location")).toHaveProperty("href", url);
      });

      it("syncs the pathname to the store", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);

        expect(store.get("location")).toHaveProperty("pathname", "/page1");
      });

      it("syncs the query string to the store", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);

        expect(store.get("location")).toHaveProperty(
          "queryString",
          "?queryParam=queryValue&a[]=1&a[]=2&storeData=%7B%22counter%22%3A%7B%22value%22%3A1%7D%2C%22counter2%22%3A%7B%22value%22%3A2%7D%7D"
        );
      });

      it("syncs storeData from the query parameters to the store", () => {
        const store = createStore();
        unsubscribe = enableHistory(store, ["counter", "counter2"]);

        expect(store.get("counter")).toEqual({ value: 1 });
        expect(store.get("counter2")).toEqual({ value: 2 });
      });

      describe("getQuery", () => {
        it("returns a query string by mergeing the browser query with the store params", () => {
          const store = createStore();
          unsubscribe = enableHistory(store, ["counter", "counter2"]);
          expect(getQuery(store, ["counter2"])).toEqual(
            "queryParam=queryValue&a[]=1&a[]=2&storeData=%7B%22counter2%22%3A%7B%22value%22%3A2%7D%7D"
          );
        });
      });
    });

    describe("on history change", () => {
      let unsubscribe = null;

      afterEach(() => {
        if (unsubscribe) unsubscribe();
        history.pushState(null, null, url);
      });

      it("syncs browser location changes to the store", done => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        const assertions = [
          () => {
            expect(store.get("location")).toHaveProperty("href", url);
            expect(store.get("location")).toHaveProperty("pathname", "/page1");
          },

          () => {
            expect(store.get("location")).toHaveProperty(
              "href",
              "http://example.com/page2"
            );
            expect(store.get("location")).toHaveProperty("pathname", "/page2");
            expect(store.get("location")).toHaveProperty("queryString", "");
          },

          () => {
            expect(store.get("location")).toHaveProperty(
              "href",
              "http://example.com/page3?queryParam=queryValue&a[]=1&a[]=2"
            );
            expect(store.get("location")).toHaveProperty("pathname", "/page3");
            expect(store.get("location")).toHaveProperty(
              "queryString",
              "?queryParam=queryValue&a[]=1&a[]=2"
            );
          }
        ];

        store.subscribe(() => {
          const assert = assertions.pop();

          try {
            assert();
          } catch (error) {
            done(error);
          }

          if (assertions.length === 0) {
            return done();
          }

          history.back();
        });

        history.pushState(null, null, "/page2");
        history.pushState(
          null,
          null,
          "/page3?queryParam=queryValue&a[]=1&a[]=2"
        );
        history.pushState(null, null, "/ignored");
        history.back();
      });

      it("syncs registered storeData from location to the store", done => {
        const store = createStore();
        unsubscribe = enableHistory(store, ["counter", "counter2"]);
        const assertions = [
          () => {
            expect(store.get("counter")).toEqual({ value: 1 });
            expect(store.get("counter2")).toEqual({ value: 2 });
          },
          () => {
            expect(store.get("counter")).toEqual({ value: 2 });
            expect(store.get("counter2")).toEqual({ value: 3 });
          }
        ];

        store.subscribe(() => {
          const assert = assertions.pop();

          try {
            assert();
          } catch (error) {
            done(error);
          }

          if (assertions.length === 0) {
            return done();
          }
          history.back();
        });

        history.pushState(
          null,
          null,
          "http://example.com/page1?queryParam=queryValue&a[]=1&a[]=2&storeData=%7B%22counter%22%3A%7B%22value%22%3A2%7D%2C%22counter2%22%3A%7B%22value%22%3A3%7D%7D"
        );
        history.pushState(null, null, "/ignored");
        history.back();
      });

      it("changes made directly to the registered sync data in the store automatically update the browser location and store location", done => {
        const store = createStore();
        unsubscribe = enableHistory(store, ["counter", "counter2"]);

        const assertions = [
          () => {
            expect(store.get("counter")).toEqual({ value: 2 });
            expect(store.get("counter2")).toEqual({ value: 3 });
            expect(store.get("location")).toHaveProperty(
              "queryString",
              "?queryParam=queryValue&a[]=1&a[]=2&storeData=%7B%22counter%22%3A%7B%22value%22%3A2%7D%2C%22counter2%22%3A%7B%22value%22%3A3%7D%7D"
            );
          }
        ];

        store.subscribe(() => {
          const assert = assertions.pop();

          try {
            assert();
          } catch (error) {
            done(error);
          }

          if (assertions.length === 0) {
            return done();
          }
        });

        expect(store.get("counter")).toEqual({ value: 1 });
        expect(store.get("counter2")).toEqual({ value: 2 });
        store.setAll({ counter: { value: 2 }, counter2: { value: 3 } });
      });

      it("changes made directly to the replaceStateMountPoints in the store replace the browser location", done => {
        jest.useFakeTimers();

        const oldPush = window.history.pushState;
        const oldReplace = window.history.replaceState;

        const pushState = (window.history.pushState = jest.fn(
          oldPush.bind(window.history)
        ));
        const replaceState = (window.history.replaceState = jest.fn(
          oldReplace.bind(window.history)
        ));

        const store = createStore();
        expect(replaceState.mock.calls.length).toEqual(0);
        unsubscribe = enableHistory(store, ["counter"], ["counter2"], {
          debounceTime: 1000
        });
        expect(replaceState.mock.calls.length).toEqual(1);

        const assertions = [
          () => {
            expect(store.get("counter")).toEqual({ value: 2 });
            expect(store.get("counter2")).toEqual({ value: 2 });
            expect(pushState.mock.calls.length).toEqual(1);
            expect(replaceState.mock.calls.length).toEqual(1);
          },
          () => {
            expect(store.get("counter")).toEqual({ value: 2 });
            expect(store.get("counter2")).toEqual({ value: 3 });
            expect(pushState.mock.calls.length).toEqual(1);
            expect(replaceState.mock.calls.length).toEqual(1);
          },
          () => {
            expect(store.get("counter")).toEqual({ value: 3 });
            expect(store.get("counter2")).toEqual({ value: 3 });
            expect(pushState.mock.calls.length).toEqual(2);
            expect(replaceState.mock.calls.length).toEqual(1);
          },
          () => {
            expect(store.get("counter")).toEqual({ value: 3 });
            expect(store.get("counter2")).toEqual({ value: 4 });
            expect(pushState.mock.calls.length).toEqual(2);
            expect(replaceState.mock.calls.length).toEqual(1);
          }
        ];

        expect(store.get("counter")).toEqual({ value: 1 });
        expect(store.get("counter2")).toEqual({ value: 2 });

        store.subscribe(() => {
          const assert = assertions.shift();

          try {
            assert();
          } catch (error) {
            window.history.pushState = oldPush;
            window.history.replaceState = oldReplace;
            done(error);
          }

          if (assertions.length === 0) {
            jest.runOnlyPendingTimers();
            expect(replaceState.mock.calls.length).toEqual(2);
            window.history.pushState = oldPush;
            window.history.replaceState = oldReplace;
            return done();
          }
        });

        store.set("counter", { value: 2 }); // pushState
        store.set("counter2", { value: 3 }); // replaceState
        store.set("counter", { value: 3 }); // pushState
        store.set("counter2", { value: 4 }); // replaceState
      });
    });

    describe("Match", () => {
      let unsubscribe = null;

      afterEach(() => {
        if (unsubscribe) unsubscribe();
        history.pushState(
          null,
          null,
          "http://example.com/page1?queryParam=queryValue&a[]=1&a[]=2"
        );
      });

      it("only renders children if the window.location path matches", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        const childComponent = jest.fn(() => null);
        const Component = () => childComponent();

        renderer.create(
          <Container store={store}>
            <Match path="/page1">
              <Component />
            </Match>
          </Container>
        );
        expect(childComponent.mock.calls.length).toEqual(1);
      });

      it("does not render children if the window.location path does not match", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        const childComponent = jest.fn(() => null);
        const Component = () => childComponent();

        renderer.create(
          <Container store={store}>
            <Match path="/page2">
              <Component />
            </Match>
          </Container>
        );
        expect(childComponent.mock.calls.length).toEqual(0);
      });

      it("renders children when the store updates and the paths match", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);
        const childComponent = jest.fn(() => null);
        const Component = () => childComponent();

        renderer.create(
          <Container store={store}>
            <Match path="/page2">
              <Component />
            </Match>
          </Container>
        );
        expect(childComponent.mock.calls.length).toEqual(0);
        updateHistory(store, "/page2");
        expect(location.search).toEqual("");
        expect(childComponent.mock.calls.length).toEqual(1);
      });
    });

    describe("Link", () => {
      let unsubscribe = null;

      afterEach(() => {
        if (unsubscribe) unsubscribe();
        history.pushState(
          null,
          null,
          "http://example.com/page1?queryParam=queryValue&a[]=1&a[]=2"
        );
      });

      it("updates location and store when clicked on", () => {
        const store = createStore();
        unsubscribe = enableHistory(store);

        const component = mount(
          <Container store={store}>
            <Link href="/page2" />
          </Container>
        );

        expect(store.get("location")).toHaveProperty("pathname", "/page1");
        component.simulate("click");
        expect(store.get("location")).toHaveProperty("pathname", "/page2");
      });
    });

    describe("debounce", () => {
      it("should fire a function after the debounce time", () => {
        jest.useFakeTimers();
        const callee = jest.fn();
        const timed = debounce(1000, callee);
        timed();
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(0);
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(1);
        jest.runOnlyPendingTimers();
      });

      it("should not trigger a pending call if interrupted by another", () => {
        jest.useFakeTimers();
        const callee = jest.fn();
        const timed = debounce(1000, callee);
        timed();
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(0);
        timed();
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(0);
        jest.advanceTimersByTime(500);
        expect(callee.mock.calls.length).toEqual(1);
        jest.runOnlyPendingTimers();
      });

      it("should forward arguments for debounced function", () => {
        jest.useFakeTimers();
        const callee = jest.fn();
        const timed = debounce(1000, callee);
        timed("dick", "tracy");
        jest.runOnlyPendingTimers();
        expect(callee.mock.calls.length).toEqual(1);
        expect(callee.mock.calls[0]).toEqual(["dick", "tracy"]);
      });
    });
  });
});
<|endoftext|>


<commit_before>"use strict";

var COLOR = 'colors',
    POSITIONS = 'positions',
    TRANSFORM = 'transform',
    DIMENSIONS = 'dimensions',
    SHADOW = 'shadow';

module.exports = {
    // Color properties
    color: COLOR,
    backgroundColor: COLOR,
    borderColor: COLOR,
    borderTopColor: COLOR,
    borderRightColor: COLOR,
    borderBottomColor: COLOR,
    borderLeftColor: COLOR,
    outlineColor: COLOR,

    // Dimensions
    margin: DIMENSIONS,
    padding: DIMENSIONS,

    // Positions
    backgroundPosition: POSITIONS,
    perspectiveOrigin: POSITIONS,
    transformOrigin: POSITIONS,

    // Transform functions
    skew: TRANSFORM,
    translate: TRANSFORM,
    rotate: TRANSFORM,
    scale: TRANSFORM,

    // Shadows
    textShadow: SHADOW,
    boxShadow: SHADOW
};<commit_msg>adding fill and stroke to css lookup<commit_after>"use strict";

var COLOR = 'colors',
    POSITIONS = 'positions',
    TRANSFORM = 'transform',
    DIMENSIONS = 'dimensions',
    SHADOW = 'shadow';

module.exports = {
    // Color properties
    color: COLOR,
    backgroundColor: COLOR,
    borderColor: COLOR,
    borderTopColor: COLOR,
    borderRightColor: COLOR,
    borderBottomColor: COLOR,
    borderLeftColor: COLOR,
    outlineColor: COLOR,
    fill: COLOR,
    stroke: COLOR,

    // Dimensions
    margin: DIMENSIONS,
    padding: DIMENSIONS,

    // Positions
    backgroundPosition: POSITIONS,
    perspectiveOrigin: POSITIONS,
    transformOrigin: POSITIONS,

    // Transform functions
    skew: TRANSFORM,
    translate: TRANSFORM,
    rotate: TRANSFORM,
    scale: TRANSFORM,

    // Shadows
    textShadow: SHADOW,
    boxShadow: SHADOW
};<|endoftext|>


<commit_before>var express = require('express'),
       yelp = require('yelp-fusion');
var router = express.Router();

var client;

const token = yelp.accessToken(process.env.YELP_KEY, process.env.YELP_SECRET).then(response =>{
    client = yelp.client(response.jsonBody.access_token);
  }).catch(e => {
    console.log(e);
  });

function randomGenerator (numBus) {
  return Math.floor(Math.random() * numBus);
}

function yelpS (query, lat, lon, rad, res, offset, times) {
  client.search({
    term: query,
    latitude: lat ,
    longitude: lon ,
    radius: rad,
    categories: ("coffee"),
    offset: offset,
    limit: 50
  }).then(response => {
    const resJson = response.jsonBody;
    const filteredJson = resJson.businesses.filter(b => b.rating >= 4 && b.review_count >= 10);
    // console.log(filteredJson);
    let count = filteredJson.length;

    if (count > 0) {
      for (let f = 0; f < count; f++) {
        let filter = filteredJson[f];
        console.log("Found: " + filter.name + " with rating of: " + filter.rating + " and " + filter.review_count + " reviews");
      }
      let randBus = randomGenerator(count);
      return res.status(200).json(filteredJson[randBus]);
    }

    if (count == 0 && times < 6) {
      console.log("expanding search radius to: " + rad);
      rad *= 2;
      times += 1;

      yelpS(query, lat, lon, rad, res, offset, times);
    } else if (count == 0 && times == 7) {
      return res.status(200).json({name: "Could not find :("});
    }

  }).catch(e => {
    console.log(e);
    return res.status(400).json({name: "Could not find :("});
  });
}

router.post('/yelpSearch', (req, res) => {
  let query = req.body.data.query;
  let coords = req.body.data.coords.split(',');
  // Splits the coordinates into latitude and longitude values
  let lat = coords[0], lon = coords[1];
  // Radius of search in meters
  let rad = 9000;
  let times = 0;
  let stay = req.body.data.stay;
  let offset = 0;
  console.log("Your query is: " + query + " , coords are: " + coords + " , and stay is: " + stay );
  // If stay, shows radius of 100m, otherwise 6 miles
  if (stay) {
    let randRad = randomGenerator(3);
    rad = 250 + (125*randRad);
  } else {
    rad = 9000;
    offset = randomGenerator(250);
  }
  console.log("Search radius is: " + rad + ", offset is: " + offset);
  // Check to make sure query and coords got passed through
  if (query || coords === undefined) {
    yelpS(query, lat, lon, rad, res, offset, times);
  }
})

module.exports = router;
<commit_msg>Added check for if yelp business is closed or not<commit_after>var express = require('express'),
       yelp = require('yelp-fusion');
var router = express.Router();

var client;

const token = yelp.accessToken(process.env.YELP_KEY, process.env.YELP_SECRET).then(response =>{
    client = yelp.client(response.jsonBody.access_token);
  }).catch(e => {
    console.log(e);
  });

function randomGenerator (numBus) {
  return Math.floor(Math.random() * numBus);
}

function yelpS (query, lat, lon, rad, res, offset, times) {
  client.search({
    term: query,
    latitude: lat ,
    longitude: lon ,
    radius: rad,
    categories: ("coffee"),
    offset: offset,
    limit: 50
  }).then(response => {
    const resJson = response.jsonBody;
    const filteredJson = resJson.businesses.filter(b => b.rating >= 4 && b.review_count >= 10 && b.is_closed == false);
    // console.log(filteredJson);
    let count = filteredJson.length;

    if (count > 0) {
      for (let f = 0; f < count; f++) {
        let filter = filteredJson[f];
        console.log("Found: " + filter.name + " with rating of: " + filter.rating + " and " + filter.review_count + " reviews");
      }
      let randBus = randomGenerator(count);
      return res.status(200).json(filteredJson[randBus]);
    }

    if (count == 0 && times < 6) {
      console.log("expanding search radius to: " + rad);
      rad *= 2;
      times += 1;

      yelpS(query, lat, lon, rad, res, offset, times);
    } else if (count == 0 && times == 7) {
      return res.status(200).json({name: "Could not find :("});
    }

  }).catch(e => {
    console.log(e);
    return res.status(400).json({name: "Could not find :("});
  });
}

router.post('/yelpSearch', (req, res) => {
  let query = req.body.data.query;
  let coords = req.body.data.coords.split(',');
  // Splits the coordinates into latitude and longitude values
  let lat = coords[0], lon = coords[1];
  // Radius of search in meters
  let rad = 9000;
  let times = 0;
  let stay = req.body.data.stay;
  let offset = 0;
  console.log("Your query is: " + query + " , coords are: " + coords + " , and stay is: " + stay );
  // If stay, shows radius of 100m, otherwise 6 miles
  if (stay) {
    let randRad = randomGenerator(3);
    rad = 250 + (125*randRad);
  } else {
    rad = 9000;
    offset = randomGenerator(250);
  }
  console.log("Search radius is: " + rad + ", offset is: " + offset);
  // Check to make sure query and coords got passed through
  if (query || coords === undefined) {
    yelpS(query, lat, lon, rad, res, offset, times);
  }
})

module.exports = router;
<|endoftext|>