<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 {seekStringToSeconds} from 'base/utils'

import Playback from 'base/playback'
import template from 'base/template'
import Styler from 'base/styler'
import Browser from 'components/browser'
import Events from 'base/events'
import tagStyle from './public/style.scss'
import sourceHTML from './public/index.html'
import find from 'lodash.find'

const MIMETYPES = {
  'mp4': ["avc1.42E01E", "avc1.58A01E", "avc1.4D401E", "avc1.64001E", "mp4v.20.8", "mp4v.20.240", "mp4a.40.2"].map(
    (codec) => { return 'video/mp4; codecs="' + codec + ', mp4a.40.2"'}),
  'ogg': ['video/ogg; codecs="theora, vorbis"', 'video/ogg; codecs="dirac"', 'video/ogg; codecs="theora, speex"'],
  '3gpp': ['video/3gpp; codecs="mp4v.20.8, samr"'],
  'webm': ['video/webm; codecs="vp8, vorbis"'],
  'mkv': ['video/x-matroska; codecs="theora, vorbis"'],
  'm3u8': ['application/x-mpegurl']
}
MIMETYPES['ogv'] = MIMETYPES['ogg']
MIMETYPES['3gp'] = MIMETYPES['3gpp']

export default class HTML5Video extends Playback {
  get name() { return 'html5_video' }
  get tagName() { return 'video' }
  get template() { return template(sourceHTML) }

  get attributes() {
    return {
      'data-html5-video': ''
    }
  }

  get events() {
    return {
      'canplay': 'handleBufferingEvents',
      'canplaythrough': 'handleBufferingEvents',
      'durationchange': 'onDurationChange',
      'ended': 'onEnded',
      'error': 'onError',
      'loadedmetadata': 'onLoadedMetadata',
      'loadstart': 'onLoadStart',
      'pause': 'onPause',
      'playing': 'onPlaying',
      'progress': 'onProgress',
      'seeked': 'handleBufferingEvents',
      'seeking': 'handleBufferingEvents',
      'stalled': 'handleBufferingEvents',
      'timeupdate': 'onTimeUpdate',
      'waiting': 'handleBufferingEvents'
    }
  }

  /**
   * Determine if the playback has ended.
   * @property ended
   * @type Boolean
   */
  get ended() {
    return this.el.ended
  }

  /**
   * Determine if the playback is having to buffer in order for
   * playback to be smooth.
   * This is related to the PLAYBACK_BUFFERING and PLAYBACK_BUFFERFULL events
   * @property buffering
   * @type Boolean
   */
  get buffering() {
    return this.bufferingState
  }

  constructor(options) {
    super(options)
    this.loadStarted = false
    this.playheadMoving = false
    this.playheadMovingTimeOnCheck = null
    this.playheadMovingTimer = setInterval(this.determineIfPlayheadMoving.bind(this), 500)
    this.options = options
    this.setupSrc(options.src)
    this.el.loop = options.loop
    if (options.poster) {
      this.$el.attr("poster", options.poster)
    }
    this.el.autoplay = options.autoPlay
    if (Browser.isSafari) {
      this.setupSafari()
    } else {
      this.el.preload = options.preload ? options.preload: 'metadata'
      this.settings.seekEnabled = true
    }
    this.settings = {default: ['seekbar']}
    this.settings.left = ["playpause", "position", "duration"]
    this.settings.right = ["fullscreen", "volume", "hd-indicator"]
  }

  /**
   * Sets the source url on the <video> element, and also the 'src' property.
   * @method setupSrc
   * @param {String} srcUrl The source URL.
   */
  setupSrc(srcUrl) {
    this.src = srcUrl
    this.el.src = srcUrl
  }

  setupSafari() {
    this.el.preload = 'auto'
  }

  onLoadedMetadata(e) {
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, {duration: e.target.duration, data: e})
    this.updateSettings()
    var autoSeekFromUrl = typeof(this.options.autoSeekFromUrl) === "undefined" || this.options.autoSeekFromUrl
    if (this.getPlaybackType() !== Playback.LIVE && autoSeekFromUrl) {
      this.checkInitialSeek()
    }
  }

  onDurationChange() {
    this.updateSettings()
    this.onTimeUpdate()
  }

  updateSettings() {
    // we can't figure out if hls resource is VoD or not until it is being loaded or duration has changed.
    // that's why we check it again and update media control accordingly.
    if (this.getPlaybackType() === Playback.VOD) {
      this.settings.left = ["playpause", "position", "duration"]
    } else {
      this.settings.left = ["playstop"]
    }
    this.settings.seekEnabled = this.isSeekEnabled()
    this.trigger(Events.PLAYBACK_SETTINGSUPDATE)
  }

  isSeekEnabled() {
    return isFinite(this.getDuration())
  }

  getPlaybackType() {
    return [0, undefined, Infinity].indexOf(this.el.duration) >= 0 ? Playback.LIVE : Playback.VOD
  }

  isHighDefinitionInUse() {
    return false
  }

  play() {
    if (!this.loadStarted && this.el.preload === 'none') {
      this.loadStarted = true
      this.handleBufferingEvents()
    }
    this.el.play()
  }

  pause() {
    this.el.pause()
  }

  stop() {
    this.pause()
    this.el.currentTime = 0
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_STOP)
  }

  volume(value) {
    this.el.volume = value / 100
  }

  mute() {
    this.el.volume = 0
  }

  unmute() {
    this.el.volume = 1
  }

  isMuted() {
    return !!this.el.volume
  }

  isPlaying() {
    return !this.el.paused && !this.el.ended
  }

  get isReady() {
    return this.isReadyState
  }

  determineIfPlayheadMoving() {
    var before = this.playheadMovingTimeOnCheck
    var now = this.el.currentTime
    this.playheadMoving = before !== now
    this.playheadMovingTimeOnCheck = now
    this.handleBufferingEvents()
  }

  onLoadStart() {
    if (this.el.preload !== 'none') {
      // when preload is none the onLoadStart event is still fired
      // immediately. Pretend that load starts in play()
      this.loadStarted = true
      this.handleBufferingEvents()
    }
  }

  onPlaying() {
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_PLAY)
  }

  onPause() {
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_PAUSE)
  }

  onEnded() {
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_ENDED, this.name)
  }

  // The playback should be classed as buffering if the following are true:
  // - the ready state is less then HAVE_FUTURE_DATA or the playhead isn't moving and it should be
  // - the media hasn't "ended"
  // - loading has started
  handleBufferingEvents() {
    var playheadShouldBeMoving = !this.elended && !this.el.paused
    var buffering = this.loadStarted && !this.el.ended && ((playheadShouldBeMoving && !this.playheadMoving) || this.el.readyState < this.el.HAVE_FUTURE_DATA)
    if (this.bufferingState !== buffering) {
      this.bufferingState = buffering
      if (buffering) {
        this.trigger(Events.PLAYBACK_BUFFERING, this.name)
      }
      else {
        this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
      }
    }
  }

  onError(event) {
    this.trigger(Events.PLAYBACK_ERROR, this.el.error, this.name)
  }

  destroy() {
    this.stop()
    this.el.src = ''
    this.src = ''
    clearInterval(this.playheadMovingTimer)
    this.$el.remove()
  }

  seek(time) {
    this.el.currentTime = time
  }

  seekPercentage(percentage) {
    var time = this.el.duration * (percentage / 100)
    this.seek(time)
  }

  checkInitialSeek() {
    var seekTime = seekStringToSeconds(window.location.href)
    if (seekTime !== 0) {
      this.seek(seekTime)
    }
  }

  getCurrentTime() {
    return this.el.currentTime
  }

  getDuration() {
    return this.el.duration
  }

  onTimeUpdate() {
    this.handleBufferingEvents()
    if (this.getPlaybackType() === Playback.LIVE) {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, {current: 1, total: 1}, this.name)
    } else {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, {current: this.el.currentTime, total: this.el.duration}, this.name)
    }
  }

  onProgress() {
    if (!this.el.buffered.length) {
      return
    }
    var bufferedPos = 0
    for (var i = 0;  i < this.el.buffered.length; i++) {
      if (this.el.currentTime >= this.el.buffered.start(i) && this.el.currentTime <= this.el.buffered.end(i)) {
        bufferedPos = i
        break
      }
    }
    this.trigger(Events.PLAYBACK_PROGRESS, {
      start: this.el.buffered.start(bufferedPos),
      current: this.el.buffered.end(bufferedPos),
      total: this.el.duration
    })
  }

  typeFor(src) {
    return 'video/mp4'
  }

  ready() {
    if (this.isReadyState) {
      return
    }
    this.isReadyState = true
    this.trigger(Events.PLAYBACK_READY, this.name)
  }

  render() {
    var style = Styler.getStyleFor(tagStyle)

    this.src && this.$el.html(this.template({ src: this.src, type: this.typeFor(this.src) }))

    if (this.options.useVideoTagDefaultControls) {
      this.$el.attr('controls', 'controls')
    }

    if (this.options.disableVideoTagContextMenu) {
      this.$el.on("contextmenu", () => {
        return false
      })
    }

    this.$el.append(style)
    this.ready()
    return this
  }
}

HTML5Video._canPlay = function(type, mimeTypesByExtension, resourceUrl, mimeType) {
  var extension = (resourceUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1]
  var mimeTypes = mimeType || mimeTypesByExtension[extension] || []
  mimeTypes = (mimeTypes.constructor === Array) ? mimeTypes : [mimeTypes]

  var media = document.createElement(type)
  return !!find(mimeTypes, (mediaType) => !!media.canPlayType(mediaType).replace(/no/, ''))
}

HTML5Video.canPlay = function(resourceUrl, mimeType) {
  return HTML5Video._canPlay('video', MIMETYPES, resourceUrl, mimeType)
}

module.exports = HTML5Video
<commit_msg>Fix accessing 'ended' property on tech<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 {seekStringToSeconds} from 'base/utils'

import Playback from 'base/playback'
import template from 'base/template'
import Styler from 'base/styler'
import Browser from 'components/browser'
import Events from 'base/events'
import tagStyle from './public/style.scss'
import sourceHTML from './public/index.html'
import find from 'lodash.find'

const MIMETYPES = {
  'mp4': ["avc1.42E01E", "avc1.58A01E", "avc1.4D401E", "avc1.64001E", "mp4v.20.8", "mp4v.20.240", "mp4a.40.2"].map(
    (codec) => { return 'video/mp4; codecs="' + codec + ', mp4a.40.2"'}),
  'ogg': ['video/ogg; codecs="theora, vorbis"', 'video/ogg; codecs="dirac"', 'video/ogg; codecs="theora, speex"'],
  '3gpp': ['video/3gpp; codecs="mp4v.20.8, samr"'],
  'webm': ['video/webm; codecs="vp8, vorbis"'],
  'mkv': ['video/x-matroska; codecs="theora, vorbis"'],
  'm3u8': ['application/x-mpegurl']
}
MIMETYPES['ogv'] = MIMETYPES['ogg']
MIMETYPES['3gp'] = MIMETYPES['3gpp']

export default class HTML5Video extends Playback {
  get name() { return 'html5_video' }
  get tagName() { return 'video' }
  get template() { return template(sourceHTML) }

  get attributes() {
    return {
      'data-html5-video': ''
    }
  }

  get events() {
    return {
      'canplay': 'handleBufferingEvents',
      'canplaythrough': 'handleBufferingEvents',
      'durationchange': 'onDurationChange',
      'ended': 'onEnded',
      'error': 'onError',
      'loadedmetadata': 'onLoadedMetadata',
      'loadstart': 'onLoadStart',
      'pause': 'onPause',
      'playing': 'onPlaying',
      'progress': 'onProgress',
      'seeked': 'handleBufferingEvents',
      'seeking': 'handleBufferingEvents',
      'stalled': 'handleBufferingEvents',
      'timeupdate': 'onTimeUpdate',
      'waiting': 'handleBufferingEvents'
    }
  }

  /**
   * Determine if the playback has ended.
   * @property ended
   * @type Boolean
   */
  get ended() {
    return this.el.ended
  }

  /**
   * Determine if the playback is having to buffer in order for
   * playback to be smooth.
   * This is related to the PLAYBACK_BUFFERING and PLAYBACK_BUFFERFULL events
   * @property buffering
   * @type Boolean
   */
  get buffering() {
    return this.bufferingState
  }

  constructor(options) {
    super(options)
    this.loadStarted = false
    this.playheadMoving = false
    this.playheadMovingTimeOnCheck = null
    this.playheadMovingTimer = setInterval(this.determineIfPlayheadMoving.bind(this), 500)
    this.options = options
    this.setupSrc(options.src)
    this.el.loop = options.loop
    if (options.poster) {
      this.$el.attr("poster", options.poster)
    }
    this.el.autoplay = options.autoPlay
    if (Browser.isSafari) {
      this.setupSafari()
    } else {
      this.el.preload = options.preload ? options.preload: 'metadata'
      this.settings.seekEnabled = true
    }
    this.settings = {default: ['seekbar']}
    this.settings.left = ["playpause", "position", "duration"]
    this.settings.right = ["fullscreen", "volume", "hd-indicator"]
  }

  /**
   * Sets the source url on the <video> element, and also the 'src' property.
   * @method setupSrc
   * @param {String} srcUrl The source URL.
   */
  setupSrc(srcUrl) {
    this.src = srcUrl
    this.el.src = srcUrl
  }

  setupSafari() {
    this.el.preload = 'auto'
  }

  onLoadedMetadata(e) {
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, {duration: e.target.duration, data: e})
    this.updateSettings()
    var autoSeekFromUrl = typeof(this.options.autoSeekFromUrl) === "undefined" || this.options.autoSeekFromUrl
    if (this.getPlaybackType() !== Playback.LIVE && autoSeekFromUrl) {
      this.checkInitialSeek()
    }
  }

  onDurationChange() {
    this.updateSettings()
    this.onTimeUpdate()
  }

  updateSettings() {
    // we can't figure out if hls resource is VoD or not until it is being loaded or duration has changed.
    // that's why we check it again and update media control accordingly.
    if (this.getPlaybackType() === Playback.VOD) {
      this.settings.left = ["playpause", "position", "duration"]
    } else {
      this.settings.left = ["playstop"]
    }
    this.settings.seekEnabled = this.isSeekEnabled()
    this.trigger(Events.PLAYBACK_SETTINGSUPDATE)
  }

  isSeekEnabled() {
    return isFinite(this.getDuration())
  }

  getPlaybackType() {
    return [0, undefined, Infinity].indexOf(this.el.duration) >= 0 ? Playback.LIVE : Playback.VOD
  }

  isHighDefinitionInUse() {
    return false
  }

  play() {
    if (!this.loadStarted && this.el.preload === 'none') {
      this.loadStarted = true
      this.handleBufferingEvents()
    }
    this.el.play()
  }

  pause() {
    this.el.pause()
  }

  stop() {
    this.pause()
    this.el.currentTime = 0
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_STOP)
  }

  volume(value) {
    this.el.volume = value / 100
  }

  mute() {
    this.el.volume = 0
  }

  unmute() {
    this.el.volume = 1
  }

  isMuted() {
    return !!this.el.volume
  }

  isPlaying() {
    return !this.el.paused && !this.el.ended
  }

  get isReady() {
    return this.isReadyState
  }

  determineIfPlayheadMoving() {
    var before = this.playheadMovingTimeOnCheck
    var now = this.el.currentTime
    this.playheadMoving = before !== now
    this.playheadMovingTimeOnCheck = now
    this.handleBufferingEvents()
  }

  onLoadStart() {
    if (this.el.preload !== 'none') {
      // when preload is none the onLoadStart event is still fired
      // immediately. Pretend that load starts in play()
      this.loadStarted = true
      this.handleBufferingEvents()
    }
  }

  onPlaying() {
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_PLAY)
  }

  onPause() {
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_PAUSE)
  }

  onEnded() {
    this.handleBufferingEvents()
    this.trigger(Events.PLAYBACK_ENDED, this.name)
  }

  // The playback should be classed as buffering if the following are true:
  // - the ready state is less then HAVE_FUTURE_DATA or the playhead isn't moving and it should be
  // - the media hasn't "ended"
  // - loading has started
  handleBufferingEvents() {
    var playheadShouldBeMoving = !this.el.ended && !this.el.paused
    var buffering = this.loadStarted && !this.el.ended && ((playheadShouldBeMoving && !this.playheadMoving) || this.el.readyState < this.el.HAVE_FUTURE_DATA)
    if (this.bufferingState !== buffering) {
      this.bufferingState = buffering
      if (buffering) {
        this.trigger(Events.PLAYBACK_BUFFERING, this.name)
      }
      else {
        this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
      }
    }
  }

  onError(event) {
    this.trigger(Events.PLAYBACK_ERROR, this.el.error, this.name)
  }

  destroy() {
    this.stop()
    this.el.src = ''
    this.src = ''
    clearInterval(this.playheadMovingTimer)
    this.$el.remove()
  }

  seek(time) {
    this.el.currentTime = time
  }

  seekPercentage(percentage) {
    var time = this.el.duration * (percentage / 100)
    this.seek(time)
  }

  checkInitialSeek() {
    var seekTime = seekStringToSeconds(window.location.href)
    if (seekTime !== 0) {
      this.seek(seekTime)
    }
  }

  getCurrentTime() {
    return this.el.currentTime
  }

  getDuration() {
    return this.el.duration
  }

  onTimeUpdate() {
    this.handleBufferingEvents()
    if (this.getPlaybackType() === Playback.LIVE) {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, {current: 1, total: 1}, this.name)
    } else {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, {current: this.el.currentTime, total: this.el.duration}, this.name)
    }
  }

  onProgress() {
    if (!this.el.buffered.length) {
      return
    }
    var bufferedPos = 0
    for (var i = 0;  i < this.el.buffered.length; i++) {
      if (this.el.currentTime >= this.el.buffered.start(i) && this.el.currentTime <= this.el.buffered.end(i)) {
        bufferedPos = i
        break
      }
    }
    this.trigger(Events.PLAYBACK_PROGRESS, {
      start: this.el.buffered.start(bufferedPos),
      current: this.el.buffered.end(bufferedPos),
      total: this.el.duration
    })
  }

  typeFor(src) {
    return 'video/mp4'
  }

  ready() {
    if (this.isReadyState) {
      return
    }
    this.isReadyState = true
    this.trigger(Events.PLAYBACK_READY, this.name)
  }

  render() {
    var style = Styler.getStyleFor(tagStyle)

    this.src && this.$el.html(this.template({ src: this.src, type: this.typeFor(this.src) }))

    if (this.options.useVideoTagDefaultControls) {
      this.$el.attr('controls', 'controls')
    }

    if (this.options.disableVideoTagContextMenu) {
      this.$el.on("contextmenu", () => {
        return false
      })
    }

    this.$el.append(style)
    this.ready()
    return this
  }
}

HTML5Video._canPlay = function(type, mimeTypesByExtension, resourceUrl, mimeType) {
  var extension = (resourceUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1]
  var mimeTypes = mimeType || mimeTypesByExtension[extension] || []
  mimeTypes = (mimeTypes.constructor === Array) ? mimeTypes : [mimeTypes]

  var media = document.createElement(type)
  return !!find(mimeTypes, (mediaType) => !!media.canPlayType(mediaType).replace(/no/, ''))
}

HTML5Video.canPlay = function(resourceUrl, mimeType) {
  return HTML5Video._canPlay('video', MIMETYPES, resourceUrl, mimeType)
}

module.exports = HTML5Video
<|endoftext|>


<commit_before>var RhythmSample = {
  bpm:0,
  startTimer:0
};

RhythmSample.setBPM = function(b,startTime) {
  this.bpm = b;
  this.startTimer = startTime;
};

RhythmSample.play = function() {
  function playSound(buffer, time) {
    var source = context.createBufferSource();
    source.buffer = buffer;
    source.connect(context.destination);
    if (!source.start)
      source.start = source.noteOn;
    source.start(time);
  }

  var kick = BUFFERS.kick;
  var snare = BUFFERS.snare;
  var hihat = BUFFERS.hihat;
  var hey = BUFFERS.hey;

  // We'll start playing the rhythm 100 milliseconds from "now"
//  var startTime = context.currentTime + 0.100;
  var tempo = this.bpm; // BPM (beats per minute)
  var eighthNoteTime = (60 / tempo) / 2;
  var startTime = this.startTimer + ((60 / tempo));

  // Play 2 bars of the following:
  for (var bar = 0; bar < 1; bar++) {
    var time = startTime + bar * 8 * eighthNoteTime;
    // Play the bass (kick) drum on beats 1, 5
    playSound(hey, time);
    playSound(hey, time + 2 * eighthNoteTime);

  }
};
<commit_msg>Revert "heyhey"<commit_after>var RhythmSample = {
  bpm:0,
  startTimer:0
};

RhythmSample.setBPM = function(b,startTime) {
  this.bpm = b;
  this.startTimer = startTime;
};

RhythmSample.play = function() {
  function playSound(buffer, time) {
    var source = context.createBufferSource();
    source.buffer = buffer;
    source.connect(context.destination);
    if (!source.start)
      source.start = source.noteOn;
    source.start(time);
  }

  var kick = BUFFERS.kick;
  var snare = BUFFERS.snare;
  var hihat = BUFFERS.hihat;
  var hey = BUFFERS.hey;

  // We'll start playing the rhythm 100 milliseconds from "now"
//  var startTime = context.currentTime + 0.100;
  var tempo = this.bpm; // BPM (beats per minute)
  var eighthNoteTime = (60 / tempo) / 2;
  var startTime = this.startTimer + ((60 / tempo));

  // Play 2 bars of the following:
  for (var bar = 0; bar < 2; bar++) {
    var time = startTime + bar * 8 * eighthNoteTime;
    // Play the bass (kick) drum on beats 1, 5
    playSound(hey, time);
    playSound(hey, time + 4 * eighthNoteTime);

  }
};
<|endoftext|>


<commit_before>/* global define, describe, it */

define(function(require) {
	'use strict';

	describe('Models', function() {
		describe('CategoryModel', function() {
			var CategoryModel = require('CategoryModel');
			describe('it should have good defaults', function() {
				var categoryModel = new CategoryModel();
				it('should have default name of empty string', function() {
					var defaultName = categoryModel.get('name');
					defaultName.should.equal('');
				});
			});
		});
		describe('ProductModel', function() {
			var ProductModel = require('ProductModel');
			describe('it should have good defaults', function() {
				var productModel = new ProductModel();
				it('should have a default name of empty string', function() {
					var defaultName = productModel.get('name');
					defaultName.should.equal('');
				});
				it('should have a default price of zero', function() {
					var defaultPrice = productModel.get('price');
					defaultPrice.should.equal(0);
				});
				it('should have a default description of empty string', function() {
					var defaultDescription = productModel.get('description');
					defaultDescription.should.equal('');
				});
			});
		});
	});
});
<commit_msg>Whitespace change<commit_after>/* global define, describe, it */

define(function(require) {
	'use strict';

	describe('Models', function() {
		describe('CategoryModel', function() {
			var CategoryModel = require('CategoryModel');
			describe('it should have good defaults', function() {
				var categoryModel = new CategoryModel();
				it('should have default name of empty string', function() {
					var defaultName = categoryModel.get('name');
					defaultName.should.equal('');
				});
			});
		});
		describe('ProductModel', function() {
			var ProductModel = require('ProductModel');
			describe('it should have good defaults', function() {
				var productModel = new ProductModel();
				it('should have a default name of empty string', function() {
					var defaultName = productModel.get('name');
					defaultName.should.equal('');
				});
				it('should have a default price of zero', function() {
					var defaultPrice = productModel.get('price');
					defaultPrice.should.equal(0);
				});
				it('should have a default description of empty string', function() {
					var defaultDescription = productModel.get('description');
					defaultDescription.should.equal('');
				});
			});
		});
	});
});
<|endoftext|>


<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 {seekStringToSeconds} from 'base/utils'

import Playback from 'base/playback'
import template from 'base/template'
import Styler from 'base/styler'
import Browser from 'components/browser'
import Events from 'base/events'
import tagStyle from './public/style.scss'
import sourceHTML from './public/index.html'
import find from 'lodash.find'
import $ from 'clappr-zepto'

const MIMETYPES = {
  'mp4': ['avc1.42E01E', 'avc1.58A01E', 'avc1.4D401E', 'avc1.64001E', 'mp4v.20.8', 'mp4v.20.240', 'mp4a.40.2'].map(
    (codec) => { return 'video/mp4; codecs="' + codec + ', mp4a.40.2"'}),
  'ogg': ['video/ogg; codecs="theora, vorbis"', 'video/ogg; codecs="dirac"', 'video/ogg; codecs="theora, speex"'],
  '3gpp': ['video/3gpp; codecs="mp4v.20.8, samr"'],
  'webm': ['video/webm; codecs="vp8, vorbis"'],
  'mkv': ['video/x-matroska; codecs="theora, vorbis"'],
  'm3u8': ['application/x-mpegurl']
}
MIMETYPES['ogv'] = MIMETYPES['ogg']
MIMETYPES['3gp'] = MIMETYPES['3gpp']

const AUDIO_MIMETYPES = {
  'wav': ['audio/wav'],
  'mp3': ['audio/mp3', 'audio/mpeg;codecs="mp3"'],
  'aac': ['audio/mp4;codecs="mp4a.40.5"'],
  'oga': ['audio/ogg']
}

// TODO: rename this Playback to HTML5Playback (breaking change, only after 0.3.0)
export default class HTML5Video extends Playback {
  get name() { return 'html5_video' }
  get tagName() { return this.isAudioOnly ? 'audio' : 'video' }
  get template() { return template(sourceHTML) }

  get isAudioOnly() {
    let resourceUrl = this.options.src
    let mimeType = this.options.mimeType
    return this.options.playback && this.options.playback.audioOnly || HTML5Video._canPlay('audio', AUDIO_MIMETYPES, resourceUrl, mimeType)
  }

  get attributes() {
    return {
      'data-html5-video': ''
    }
  }

  get events() {
    return {
      'canplay': '_onCanPlay',
      'canplaythrough': '_handleBufferingEvents',
      'durationchange': '_onDurationChange',
      'ended': '_onEnded',
      'error': '_onError',
      'loadeddata': '_onLoadedData',
      'loadedmetadata': '_onLoadedMetadata',
      'pause': '_onPause',
      'playing': '_onPlaying',
      'progress': '_onProgress',
      'seeked': '_handleBufferingEvents',
      'seeking': '_handleBufferingEvents',
      'stalled': '_handleBufferingEvents',
      'timeupdate': '_onTimeUpdate',
      'waiting': '_onWaiting'
    }
  }

  /**
   * Determine if the playback has ended.
   * @property ended
   * @type Boolean
   */
  get ended() {
    return this.el.ended
  }

  /**
   * Determine if the playback is having to buffer in order for
   * playback to be smooth.
   * This is related to the PLAYBACK_BUFFERING and PLAYBACK_BUFFERFULL events
   * @property buffering
   * @type Boolean
   */
  get buffering() {
    return !!this._bufferingState
  }

  constructor(...args) {
    super(...args)
    this._loadStarted = false
    this._playheadMoving = false
    this._playheadMovingTimer = null
    this._stopped = false
    this._setupSrc(this.options.src)
    // backwards compatibility (TODO: remove on 0.3.0)
    this.options.playback || (this.options.playback = this.options.playbackConfig)

    var playbackConfig = (this.options.playback || {})
    var preload = playbackConfig.preload || (Browser.isSafari ? 'auto' : this.options.preload)

    $.extend(this.el, {
      loop: this.options.loop,
      autoplay: this.options.autoPlay,
      poster: this.options.poster,
      preload: preload || 'metadata',
      controls: playbackConfig.controls || this.options.useVideoTagDefaultControls,
      crossOrigin: playbackConfig.crossOrigin
    })

    // TODO should settings be private?
    this.settings = {default: ['seekbar']}
    this.settings.left = ['playpause', 'position', 'duration']
    this.settings.right = ['fullscreen', 'volume', 'hd-indicator']
  }

  /**
   * Sets the source url on the <video> element, and also the 'src' property.
   * @method setupSrc
   * @private
   * @param {String} srcUrl The source URL.
   */
  _setupSrc(srcUrl) {
    this._src = srcUrl
    this.el.src = srcUrl
  }

  _onLoadedMetadata(e) {
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, {duration: e.target.duration, data: e})
    this._updateSettings()
    var autoSeekFromUrl = typeof(this._options.autoSeekFromUrl) === 'undefined' || this._options.autoSeekFromUrl
    if (this.getPlaybackType() !== Playback.LIVE && autoSeekFromUrl) {
      this._checkInitialSeek()
    }
  }

  _onDurationChange() {
    this._updateSettings()
    this._onTimeUpdate()
    // onProgress uses the duration
    this._onProgress()
  }

  _updateSettings() {
    // we can't figure out if hls resource is VoD or not until it is being loaded or duration has changed.
    // that's why we check it again and update media control accordingly.
    if (this.getPlaybackType() === Playback.VOD || this.getPlaybackType() === Playback.AOD) {
      this.settings.left = ['playpause', 'position', 'duration']
    } else {
      this.settings.left = ['playstop']
    }
    this.settings.seekEnabled = this.isSeekEnabled()
    this.trigger(Events.PLAYBACK_SETTINGSUPDATE)
  }

  isSeekEnabled() {
    return isFinite(this.getDuration())
  }

  getPlaybackType() {
    const onDemandType = this.tagName === 'audio' ? Playback.AOD : Playback.VOD
    return [0, undefined, Infinity].indexOf(this.el.duration) >= 0 ? Playback.LIVE : onDemandType
  }

  isHighDefinitionInUse() {
    return false
  }

  play() {
    this.trigger(Events.PLAYBACK_PLAY_INTENT)
    this._stopped = false
    this._handleBufferingEvents()
    this.el.play()
  }

  pause() {
    this.el.pause()
  }

  stop() {
    this.pause()
    this._stopped = true
    this.el.currentTime = 0
    this._stopPlayheadMovingChecks()
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_STOP)
  }

  volume(value) {
    this.el.volume = value / 100
  }

  mute() {
    this.el.volume = 0
  }

  unmute() {
    this.el.volume = 1
  }

  isMuted() {
    return !!this.el.volume
  }

  isPlaying() {
    return !this.el.paused && !this.el.ended
  }

  get isReady() {
    return this._isReadyState
  }

  _startPlayheadMovingChecks() {
    if (this._playheadMovingTimer !== null) {
      return
    }
    this._playheadMovingTimeOnCheck = null
    this._determineIfPlayheadMoving()
    this._playheadMovingTimer = setInterval(this._determineIfPlayheadMoving.bind(this), 500)
  }

  _stopPlayheadMovingChecks() {
    if (this._playheadMovingTimer === null) {
      return
    }
    clearInterval(this._playheadMovingTimer)
    this._playheadMovingTimer = null
    this._playheadMoving = false
  }

  _determineIfPlayheadMoving() {
    var before = this._playheadMovingTimeOnCheck
    var now = this.el.currentTime
    this._playheadMoving = before !== now
    this._playheadMovingTimeOnCheck = now
    this._handleBufferingEvents()
  }

  // this seems to happen when the user is having to wait
  // for something to happen AFTER A USER INTERACTION
  // e.g the player might be buffering, but when `play()` is called
  // only at this point will this be called.
  // Or the user may seek somewhere but the new area requires buffering,
  // so it will fire then as well.
  // On devices where playing is blocked until requested with a user action,
  // buffering may start, but never finish until the user initiates a play,
  // but this only happens when play is actually requested
  _onWaiting() {
    this._loadStarted = true
    this._handleBufferingEvents()
  }

  // called after the first frame has loaded
  // note this doesn't fire on ios before the user has requested play
  // ideally the "loadstart" event would be used instead, but this fires
  // before a user has requested play on iOS, and also this is always fired
  // even if the preload setting is "none". In both these cases this causes
  // infinite buffering until the user does something which isn't great.
  _onLoadedData() {
    this._loadStarted = true
    this._handleBufferingEvents()
  }

  // note this doesn't fire on ios before user has requested play
  _onCanPlay() {
    this._handleBufferingEvents()
  }

  _onPlaying() {
    this._startPlayheadMovingChecks()
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_PLAY)
  }

  _onPause() {
    this._stopPlayheadMovingChecks()
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_PAUSE)
  }

  _onEnded() {
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_ENDED, this.name)
  }

  // The playback should be classed as buffering if the following are true:
  // - the ready state is less then HAVE_FUTURE_DATA or the playhead isn't moving and it should be
  // - the media hasn't "ended",
  // - the media hasn't been stopped
  // - loading has started
  _handleBufferingEvents() {
    var playheadShouldBeMoving = !this.el.ended && !this.el.paused
    var buffering = this._loadStarted && !this.el.ended && !this.stopped && ((playheadShouldBeMoving && !this._playheadMoving) || this.el.readyState < this.el.HAVE_FUTURE_DATA)
    if (this._bufferingState !== buffering) {
      this._bufferingState = buffering
      if (buffering) {
        this.trigger(Events.PLAYBACK_BUFFERING, this.name)
      }
      else {
        this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
      }
    }
  }

  _onError() {
    this.trigger(Events.PLAYBACK_ERROR, this.el.error, this.name)
  }

  destroy() {
    this.$el.remove()
    this.el.src = ''
    this._src = null
  }

  seek(time) {
    this.el.currentTime = time
  }

  seekPercentage(percentage) {
    var time = this.el.duration * (percentage / 100)
    this.seek(time)
  }

  _checkInitialSeek() {
    var seekTime = seekStringToSeconds(window.location.href)
    if (seekTime !== 0) {
      this.seek(seekTime)
    }
  }

  getCurrentTime() {
    return this.el.currentTime
  }

  getDuration() {
    return this.el.duration
  }

  _onTimeUpdate() {
    this._handleBufferingEvents()
    if (this.getPlaybackType() === Playback.LIVE) {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, {current: 1, total: 1}, this.name)
    } else {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, {current: this.el.currentTime, total: this.el.duration}, this.name)
    }
  }

  _onProgress() {
    if (!this.el.buffered.length) {
      return
    }
    var bufferedPos = 0
    for (var i = 0;  i < this.el.buffered.length; i++) {
      if (this.el.currentTime >= this.el.buffered.start(i) && this.el.currentTime <= this.el.buffered.end(i)) {
        bufferedPos = i
        break
      }
    }
    this.trigger(Events.PLAYBACK_PROGRESS, {
      start: this.el.buffered.start(bufferedPos),
      current: this.el.buffered.end(bufferedPos),
      total: this.el.duration
    })
  }

  _typeFor(src) {
    var resourceParts = src.split('?')[0].match(/.*\.(.*)$/) || []
    var isHls = resourceParts.length > 1 && resourceParts[1] === 'm3u8'
    return isHls ? 'application/vnd.apple.mpegurl' : 'video/mp4'
  }

  _ready() {
    if (this._isReadyState) {
      return
    }
    this._isReadyState = true
    this.trigger(Events.PLAYBACK_READY, this.name)
  }

  render() {
    var style = Styler.getStyleFor(tagStyle)

    this._src && this.$el.html(this.template({ src: this._src, type: this._typeFor(this._src) }))

    if (this._options.useVideoTagDefaultControls) {
      this.$el.attr('controls', 'controls')
    }

    if (this._options.disableVideoTagContextMenu) {
      this.$el.on('contextmenu', () => {
        return false
      })
    }

    this.$el.append(style)
    this._ready()
    return this
  }
}

HTML5Video._canPlay = function(type, mimeTypesByExtension, resourceUrl, mimeType) {
  var extension = (resourceUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1]
  var mimeTypes = mimeType || mimeTypesByExtension[extension] || []
  mimeTypes = (mimeTypes.constructor === Array) ? mimeTypes : [mimeTypes]

  var media = document.createElement(type)
  return !!find(mimeTypes, (mediaType) => !!media.canPlayType(mediaType).replace(/no/, ''))
}

HTML5Video.canPlay = function(resourceUrl, mimeType) {
  return HTML5Video._canPlay('audio', AUDIO_MIMETYPES, resourceUrl, mimeType) ||
         HTML5Video._canPlay('video', MIMETYPES, resourceUrl, mimeType)
}

module.exports = HTML5Video
<commit_msg>html5: uses private stopped fixes #1062<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 {seekStringToSeconds} from 'base/utils'

import Playback from 'base/playback'
import template from 'base/template'
import Styler from 'base/styler'
import Browser from 'components/browser'
import Events from 'base/events'
import tagStyle from './public/style.scss'
import sourceHTML from './public/index.html'
import find from 'lodash.find'
import $ from 'clappr-zepto'

const MIMETYPES = {
  'mp4': ['avc1.42E01E', 'avc1.58A01E', 'avc1.4D401E', 'avc1.64001E', 'mp4v.20.8', 'mp4v.20.240', 'mp4a.40.2'].map(
    (codec) => { return 'video/mp4; codecs="' + codec + ', mp4a.40.2"'}),
  'ogg': ['video/ogg; codecs="theora, vorbis"', 'video/ogg; codecs="dirac"', 'video/ogg; codecs="theora, speex"'],
  '3gpp': ['video/3gpp; codecs="mp4v.20.8, samr"'],
  'webm': ['video/webm; codecs="vp8, vorbis"'],
  'mkv': ['video/x-matroska; codecs="theora, vorbis"'],
  'm3u8': ['application/x-mpegurl']
}
MIMETYPES['ogv'] = MIMETYPES['ogg']
MIMETYPES['3gp'] = MIMETYPES['3gpp']

const AUDIO_MIMETYPES = {
  'wav': ['audio/wav'],
  'mp3': ['audio/mp3', 'audio/mpeg;codecs="mp3"'],
  'aac': ['audio/mp4;codecs="mp4a.40.5"'],
  'oga': ['audio/ogg']
}

// TODO: rename this Playback to HTML5Playback (breaking change, only after 0.3.0)
export default class HTML5Video extends Playback {
  get name() { return 'html5_video' }
  get tagName() { return this.isAudioOnly ? 'audio' : 'video' }
  get template() { return template(sourceHTML) }

  get isAudioOnly() {
    let resourceUrl = this.options.src
    let mimeType = this.options.mimeType
    return this.options.playback && this.options.playback.audioOnly || HTML5Video._canPlay('audio', AUDIO_MIMETYPES, resourceUrl, mimeType)
  }

  get attributes() {
    return {
      'data-html5-video': ''
    }
  }

  get events() {
    return {
      'canplay': '_onCanPlay',
      'canplaythrough': '_handleBufferingEvents',
      'durationchange': '_onDurationChange',
      'ended': '_onEnded',
      'error': '_onError',
      'loadeddata': '_onLoadedData',
      'loadedmetadata': '_onLoadedMetadata',
      'pause': '_onPause',
      'playing': '_onPlaying',
      'progress': '_onProgress',
      'seeked': '_handleBufferingEvents',
      'seeking': '_handleBufferingEvents',
      'stalled': '_handleBufferingEvents',
      'timeupdate': '_onTimeUpdate',
      'waiting': '_onWaiting'
    }
  }

  /**
   * Determine if the playback has ended.
   * @property ended
   * @type Boolean
   */
  get ended() {
    return this.el.ended
  }

  /**
   * Determine if the playback is having to buffer in order for
   * playback to be smooth.
   * This is related to the PLAYBACK_BUFFERING and PLAYBACK_BUFFERFULL events
   * @property buffering
   * @type Boolean
   */
  get buffering() {
    return !!this._bufferingState
  }

  constructor(...args) {
    super(...args)
    this._loadStarted = false
    this._playheadMoving = false
    this._playheadMovingTimer = null
    this._stopped = false
    this._setupSrc(this.options.src)
    // backwards compatibility (TODO: remove on 0.3.0)
    this.options.playback || (this.options.playback = this.options.playbackConfig)

    var playbackConfig = (this.options.playback || {})
    var preload = playbackConfig.preload || (Browser.isSafari ? 'auto' : this.options.preload)

    $.extend(this.el, {
      loop: this.options.loop,
      autoplay: this.options.autoPlay,
      poster: this.options.poster,
      preload: preload || 'metadata',
      controls: playbackConfig.controls || this.options.useVideoTagDefaultControls,
      crossOrigin: playbackConfig.crossOrigin
    })

    // TODO should settings be private?
    this.settings = {default: ['seekbar']}
    this.settings.left = ['playpause', 'position', 'duration']
    this.settings.right = ['fullscreen', 'volume', 'hd-indicator']
  }

  /**
   * Sets the source url on the <video> element, and also the 'src' property.
   * @method setupSrc
   * @private
   * @param {String} srcUrl The source URL.
   */
  _setupSrc(srcUrl) {
    this._src = srcUrl
    this.el.src = srcUrl
  }

  _onLoadedMetadata(e) {
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, {duration: e.target.duration, data: e})
    this._updateSettings()
    var autoSeekFromUrl = typeof(this._options.autoSeekFromUrl) === 'undefined' || this._options.autoSeekFromUrl
    if (this.getPlaybackType() !== Playback.LIVE && autoSeekFromUrl) {
      this._checkInitialSeek()
    }
  }

  _onDurationChange() {
    this._updateSettings()
    this._onTimeUpdate()
    // onProgress uses the duration
    this._onProgress()
  }

  _updateSettings() {
    // we can't figure out if hls resource is VoD or not until it is being loaded or duration has changed.
    // that's why we check it again and update media control accordingly.
    if (this.getPlaybackType() === Playback.VOD || this.getPlaybackType() === Playback.AOD) {
      this.settings.left = ['playpause', 'position', 'duration']
    } else {
      this.settings.left = ['playstop']
    }
    this.settings.seekEnabled = this.isSeekEnabled()
    this.trigger(Events.PLAYBACK_SETTINGSUPDATE)
  }

  isSeekEnabled() {
    return isFinite(this.getDuration())
  }

  getPlaybackType() {
    const onDemandType = this.tagName === 'audio' ? Playback.AOD : Playback.VOD
    return [0, undefined, Infinity].indexOf(this.el.duration) >= 0 ? Playback.LIVE : onDemandType
  }

  isHighDefinitionInUse() {
    return false
  }

  play() {
    this.trigger(Events.PLAYBACK_PLAY_INTENT)
    this._stopped = false
    this._handleBufferingEvents()
    this.el.play()
  }

  pause() {
    this.el.pause()
  }

  stop() {
    this.pause()
    this._stopped = true
    this.el.currentTime = 0
    this._stopPlayheadMovingChecks()
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_STOP)
  }

  volume(value) {
    this.el.volume = value / 100
  }

  mute() {
    this.el.volume = 0
  }

  unmute() {
    this.el.volume = 1
  }

  isMuted() {
    return !!this.el.volume
  }

  isPlaying() {
    return !this.el.paused && !this.el.ended
  }

  get isReady() {
    return this._isReadyState
  }

  _startPlayheadMovingChecks() {
    if (this._playheadMovingTimer !== null) {
      return
    }
    this._playheadMovingTimeOnCheck = null
    this._determineIfPlayheadMoving()
    this._playheadMovingTimer = setInterval(this._determineIfPlayheadMoving.bind(this), 500)
  }

  _stopPlayheadMovingChecks() {
    if (this._playheadMovingTimer === null) {
      return
    }
    clearInterval(this._playheadMovingTimer)
    this._playheadMovingTimer = null
    this._playheadMoving = false
  }

  _determineIfPlayheadMoving() {
    var before = this._playheadMovingTimeOnCheck
    var now = this.el.currentTime
    this._playheadMoving = before !== now
    this._playheadMovingTimeOnCheck = now
    this._handleBufferingEvents()
  }

  // this seems to happen when the user is having to wait
  // for something to happen AFTER A USER INTERACTION
  // e.g the player might be buffering, but when `play()` is called
  // only at this point will this be called.
  // Or the user may seek somewhere but the new area requires buffering,
  // so it will fire then as well.
  // On devices where playing is blocked until requested with a user action,
  // buffering may start, but never finish until the user initiates a play,
  // but this only happens when play is actually requested
  _onWaiting() {
    this._loadStarted = true
    this._handleBufferingEvents()
  }

  // called after the first frame has loaded
  // note this doesn't fire on ios before the user has requested play
  // ideally the "loadstart" event would be used instead, but this fires
  // before a user has requested play on iOS, and also this is always fired
  // even if the preload setting is "none". In both these cases this causes
  // infinite buffering until the user does something which isn't great.
  _onLoadedData() {
    this._loadStarted = true
    this._handleBufferingEvents()
  }

  // note this doesn't fire on ios before user has requested play
  _onCanPlay() {
    this._handleBufferingEvents()
  }

  _onPlaying() {
    this._startPlayheadMovingChecks()
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_PLAY)
  }

  _onPause() {
    this._stopPlayheadMovingChecks()
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_PAUSE)
  }

  _onEnded() {
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_ENDED, this.name)
  }

  // The playback should be classed as buffering if the following are true:
  // - the ready state is less then HAVE_FUTURE_DATA or the playhead isn't moving and it should be
  // - the media hasn't "ended",
  // - the media hasn't been stopped
  // - loading has started
  _handleBufferingEvents() {
    var playheadShouldBeMoving = !this.el.ended && !this.el.paused
    var buffering = this._loadStarted && !this.el.ended && !this._stopped && ((playheadShouldBeMoving && !this._playheadMoving) || this.el.readyState < this.el.HAVE_FUTURE_DATA)
    if (this._bufferingState !== buffering) {
      this._bufferingState = buffering
      if (buffering) {
        this.trigger(Events.PLAYBACK_BUFFERING, this.name)
      }
      else {
        this.trigger(Events.PLAYBACK_BUFFERFULL, this.name)
      }
    }
  }

  _onError() {
    this.trigger(Events.PLAYBACK_ERROR, this.el.error, this.name)
  }

  destroy() {
    this.$el.remove()
    this.el.src = ''
    this._src = null
  }

  seek(time) {
    this.el.currentTime = time
  }

  seekPercentage(percentage) {
    var time = this.el.duration * (percentage / 100)
    this.seek(time)
  }

  _checkInitialSeek() {
    var seekTime = seekStringToSeconds(window.location.href)
    if (seekTime !== 0) {
      this.seek(seekTime)
    }
  }

  getCurrentTime() {
    return this.el.currentTime
  }

  getDuration() {
    return this.el.duration
  }

  _onTimeUpdate() {
    this._handleBufferingEvents()
    if (this.getPlaybackType() === Playback.LIVE) {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, {current: 1, total: 1}, this.name)
    } else {
      this.trigger(Events.PLAYBACK_TIMEUPDATE, {current: this.el.currentTime, total: this.el.duration}, this.name)
    }
  }

  _onProgress() {
    if (!this.el.buffered.length) {
      return
    }
    var bufferedPos = 0
    for (var i = 0;  i < this.el.buffered.length; i++) {
      if (this.el.currentTime >= this.el.buffered.start(i) && this.el.currentTime <= this.el.buffered.end(i)) {
        bufferedPos = i
        break
      }
    }
    this.trigger(Events.PLAYBACK_PROGRESS, {
      start: this.el.buffered.start(bufferedPos),
      current: this.el.buffered.end(bufferedPos),
      total: this.el.duration
    })
  }

  _typeFor(src) {
    var resourceParts = src.split('?')[0].match(/.*\.(.*)$/) || []
    var isHls = resourceParts.length > 1 && resourceParts[1] === 'm3u8'
    return isHls ? 'application/vnd.apple.mpegurl' : 'video/mp4'
  }

  _ready() {
    if (this._isReadyState) {
      return
    }
    this._isReadyState = true
    this.trigger(Events.PLAYBACK_READY, this.name)
  }

  render() {
    var style = Styler.getStyleFor(tagStyle)

    this._src && this.$el.html(this.template({ src: this._src, type: this._typeFor(this._src) }))

    if (this._options.useVideoTagDefaultControls) {
      this.$el.attr('controls', 'controls')
    }

    if (this._options.disableVideoTagContextMenu) {
      this.$el.on('contextmenu', () => {
        return false
      })
    }

    this.$el.append(style)
    this._ready()
    return this
  }
}

HTML5Video._canPlay = function(type, mimeTypesByExtension, resourceUrl, mimeType) {
  var extension = (resourceUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1]
  var mimeTypes = mimeType || mimeTypesByExtension[extension] || []
  mimeTypes = (mimeTypes.constructor === Array) ? mimeTypes : [mimeTypes]

  var media = document.createElement(type)
  return !!find(mimeTypes, (mediaType) => !!media.canPlayType(mediaType).replace(/no/, ''))
}

HTML5Video.canPlay = function(resourceUrl, mimeType) {
  return HTML5Video._canPlay('audio', AUDIO_MIMETYPES, resourceUrl, mimeType) ||
         HTML5Video._canPlay('video', MIMETYPES, resourceUrl, mimeType)
}

module.exports = HTML5Video
<|endoftext|>


<commit_before>/*
 * candy-replies-plugin
 * @version 0.1 (2013-2-20)
 * @author Drew Harry (drew.harry@gmail.com)
 *
 * Adds @reply highlighting to chat messages to help with high velocity
 * conversations.
 */

var CandyShop = (function(self) { return self; }(CandyShop || {}));

CandyShop.Replies = (function(self, Candy, $) {

	self.init = function() {

    Candy.View.Event.Message.onShow = handleOnShow;

	  return self;
  };

  var handleOnShow = function(args) {
    var localNick = Candy.Core.getUser().getNick().toLowerCase();

    var re = new RegExp("@" + localNick + "[ .!><\":\/@-]|$");

    if(re.test(args.message.toLowerCase())) {
      var el = args.element;

      el.addClass("mention");
      el.prev().addClass("mention");
    }
  }

  return self;
}(CandyShop.Replies || {}, Candy, jQuery));<commit_msg>Fixed the regular expression.<commit_after>/*
 * candy-replies-plugin
 * @version 0.1 (2013-2-20)
 * @author Drew Harry (drew.harry@gmail.com)
 *
 * Adds @reply highlighting to chat messages to help with high velocity
 * conversations.
 */

var CandyShop = (function(self) { return self; }(CandyShop || {}));

CandyShop.Replies = (function(self, Candy, $) {

	self.init = function() {

    Candy.View.Event.Message.onShow = handleOnShow;

	  return self;
  };

  var handleOnShow = function(args) {
    var localNick = Candy.Core.getUser().getNick().toLowerCase();

    var re = new RegExp("@" + localNick + "([ .!><\":\/@-]|$)");

    if(re.test(args.message.toLowerCase())) {
      var el = args.element;

      el.addClass("mention");
      el.prev().addClass("mention");
    }
  }

  return self;
}(CandyShop.Replies || {}, Candy, jQuery));<|endoftext|>


<commit_before>define (function (require, exports, module) {
	var ComponentPlugin = require("ide-component-plugin");
	var beautify = require("js-beautify");
	var IgniteUIComponentPlugin = IgniteUIComponentPlugin || ComponentPlugin.extend({
		init: function (options) {
			this._super(options);
		},
		getName: function () {
			return null;
		},
		_getWidgetName: function (type) {
			/*
			var comp;
			if (this.settings && this.settings.packageInfo) {
				comp = this.settings.packageInfo.components[type];
				if (comp && typeof comp.name === "string") {
					return comp.name.replace("ui.", "");
				}
			}*/
			return "ig" + type.charAt(0).toUpperCase() + type.slice(1);
		},
		getHeadMarkup: function () {
			return null;
		},
		getCodeEditorHeadSnippet: function () {
			return null;
		},
		// retrieves the initial markup for the current component
		getMarkup: function (descriptor) {
			return "

";
			//return this.evalTemplate("default.html", descriptor, true);
		},
		getCodeEditorScriptSnippet: function (descriptor) {
			var code = "";
			var opts = descriptor.options;
			var name = this._getWidgetName(descriptor.type);
			if (!name) {
				console.error("Could not get widget name for '" + descriptor.type +"'.");
				return null;
			}
			var lineCount = 5;
			code = "\t\t\t\t$(\"#" + descriptor.id + "\")." + name + "({\n" +
				"\t\t\t\t\theight: " + opts.height + ",\n" +
				"\t\t\t\t\twidth: " + opts.width;
			if (descriptor.data && window[descriptor.data]) {
				code += ",\n\t\t\t\t\tdataSource: " + descriptor.data;
			}
			var props = this.settings.packageInfo.components[descriptor.type].properties;
			for (var key in opts) {
				if (opts.hasOwnProperty(key) && key !== "dataSource" && key !== "height" && key !== "width") {
					if (props[key].type === "string") {
						code += ",\n\t\t\t\t\t" + key + ": \"" + opts[key] + "\"";
					} else if (props[key].type === "array") {
						var formattedStr = beautify(JSON.stringify(opts[key]));
						//code += ",\n\t\t\t\t\t" + key + ": " + formattedStr;
						code += ",\n";
						formattedStr = key + ": " + formattedStr;
						var formattedStrTabbed = "";
						var tabbedArr = formattedStr.split("\n");
						for (var i = 0; i < tabbedArr.length; i++) {
							formattedStrTabbed += "\t\t\t\t\t" + tabbedArr[i];
							if (i < tabbedArr.length - 1) {
								formattedStrTabbed += "\n";
							}
						}
						code += formattedStrTabbed;
						lineCount += code.split("\n").length;
					} else {
						code += ",\n\t\t\t\t\t" + key + ": " + opts[key];
					}
					lineCount++;
				}
			}
			code += "\n\t\t\t\t});\n";
			return {codeString: code, lineCount: lineCount};
			//return this.evalTemplate("default.code.js", descriptor);
		},
		getCodeEditorMarkupSnippet: function (descriptor) {
			// as a developer, i would like to be able to provide the direct manual formatting, as well as specify a template, and evaluate it
			var extraIndentStr = "", i = 0;
			if (descriptor.extraIndent) {
				for (i = 0; i < descriptor.extraIndent; i++) {
					extraIndentStr += "\t";
				}
			}
			return {codeString: "\t" + extraIndentStr + "

\n", lineCount: 1};
			//return this.evalTemplate("default.code.html", descriptor);
		},
		requiresInitialization: function () {
			return true;
		},
		getPropValue: function (descriptor) {
			var name = this._getWidgetName(descriptor.type);
			var data = typeof window.frames[0].$(descriptor.placeholder).data === "function" && window.frames[0].$(descriptor.placeholder).data(name);
			if (data) {
				return data.options && typeof(data.options[descriptor.propName]) !== "undefined" ? data.options[descriptor.propName] : descriptor.defaultValue;
			}
			return descriptor.defaultValue;
		},
		initComponent: function (descriptor) {
			var name = this._getWidgetName(descriptor.type);
			if (window.frames[0].$(descriptor.placeholder)[name]) {
				window.frames[0].$(descriptor.placeholder)[name](descriptor.options);
			}
		},
		navigate: function (descriptor) {

		},
		update: function (descriptor) {
			//console.log("Updating property or event: " + descriptor.propName);
			var ide = this.settings.ide;
			var name = this._getWidgetName(descriptor.type);
			if (descriptor.args) {
				// handle events
				// try to find an existing marker, for the event, if one doesn't exist, create it
				var component = null;
				for (var i = 0; i < ide.componentIds.length; i++) {
					if (ide.componentIds[i].id === descriptor.id) {
						component = ide.componentIds[i];
						break;
					}
				}
				if (component) {
					if (!component.eventMarkers) {
						component.eventMarkers = {};
					}
					//var codeRange = ide.editor.find("


<commit_before>const { Transform } = require('stream');

/**
 * Demuxes a Webm stream (containing Opus audio) to output an Opus stream.
 * @extends {TransformStream}
 */
class WebmOpusDemuxer extends Transform {
  /**
   * Creates a new WebmOpus demuxer.
   * @param {Object} [options] options that you would pass to a regular Transform stream.
   */
  constructor(options = {}) {
    super(Object.assign({ readableObjectMode: true }, options));
    this._remainder = null;
    this._length = 0;
    this._count = 0;
    this._skipUntil = null;
    this._track = null;
    this._incompleteTrack = {};
  }

  _transform(chunk, encoding, done) {
    this._length += chunk.length;
    if (this._remainder) {
      chunk = Buffer.concat([this._remainder, chunk]);
      this._remainder = null;
    }
    let offset = 0;
    if (this._skipUntil && this._length > this._skipUntil) {
      offset = this._skipUntil - this._count;
      this._skipUntil = null;
    } else if (this._skipUntil) {
      this._count += chunk.length;
      return done();
    }
    let result;
    while (result !== TOO_SHORT) {
      result = this._readTag(chunk, offset);
      if (result === TOO_SHORT) break;
      if (result._skipUntil) {
        this._skipUntil = result._skipUntil;
        break;
      }
      if (result.offset) offset = result.offset;
      else break;
    }
    this._count += offset;
    this._remainder = chunk.slice(offset);
    return done();
  }

  /**
   * Reads an EBML ID from a buffer.
   * @private
   * @param {Buffer} chunk the buffer to read from.
   * @param {number} offset the offset in the buffer.
   * @returns {Object|Symbol} contains an `id` property (buffer) and the new `offset` (number).
   * Returns the TOO_SHORT symbol if the data wasn't big enough to facilitate the request.
   */
  _readEBMLId(chunk, offset) {
    const idLength = vintLength(chunk, offset);
    if (idLength === TOO_SHORT) return TOO_SHORT;
    return {
      id: chunk.slice(offset, offset + idLength),
      offset: offset + idLength,
    };
  }

  /**
   * Reads a size variable-integer to calculate the length of the data of a tag.
   * @private
   * @param {Buffer} chunk the buffer to read from.
   * @param {number} offset the offset in the buffer.
   * @returns {Object|Symbol} contains property `offset` (number), `dataLength` (number) and `sizeLength` (number).
   * Returns the TOO_SHORT symbol if the data wasn't big enough to facilitate the request.
   */
  _readTagDataSize(chunk, offset) {
    const sizeLength = vintLength(chunk, offset);
    if (sizeLength === TOO_SHORT) return TOO_SHORT;
    const dataLength = expandVint(chunk, offset, offset + sizeLength);
    return { offset: offset + sizeLength, dataLength, sizeLength };
  }

  /**
   * Takes a buffer and attempts to read and process a tag.
   * @private
   * @param {Buffer} chunk the buffer to read from.
   * @param {number} offset the offset in the buffer.
   * @returns {Object|Symbol} contains the new `offset` (number) and optionally the `_skipUntil` property,
   * indicating that the stream should ignore any data until a certain length is reached.
   * Returns the TOO_SHORT symbol if the data wasn't big enough to facilitate the request.
   */
  _readTag(chunk, offset) {
    const idData = this._readEBMLId(chunk, offset);
    if (idData === TOO_SHORT) return TOO_SHORT;
    const ebmlID = idData.id.toString('hex');
    offset = idData.offset;
    const sizeData = this._readTagDataSize(chunk, offset);
    if (sizeData === TOO_SHORT) return TOO_SHORT;
    const { dataLength } = sizeData;
    offset = sizeData.offset;
    // If this tag isn't useful, tell the stream to stop processing data until the tag ends
    if (typeof TAGS[ebmlID] === 'undefined') {
      if (chunk.length > offset + dataLength) {
        return { offset: offset + dataLength };
      }
      return { offset, _skipUntil: this._count + offset + dataLength };
    }

    const tagHasChildren = TAGS[ebmlID];
    if (tagHasChildren) {
      return { offset };
    }

    if (offset + dataLength > chunk.length) return TOO_SHORT;
    const data = chunk.slice(offset, offset + dataLength);
    if (!this._track) {
      if (ebmlID === 'ae') this._incompleteTrack = {};
      if (ebmlID === 'd7') this._incompleteTrack.number = data[0];
      if (ebmlID === '83') this._incompleteTrack.type = data[0];
      if (this._incompleteTrack.type === 2 && typeof this._incompleteTrack.number !== 'undefined') {
        this._track = this._incompleteTrack;
      }
    }
    if (ebmlID === 'a3') {
      if (!this._track) throw Error('No audio _track in this webm!');
      if ((data[0] & 0xF) === this._track.number) {
        this.push(data.slice(4));
      }
    }
    return { offset: offset + dataLength };
  }
}

/**
 * A symbol that is returned by some functions that indicates the buffer it has been provided is not large enough
 * to facilitate a request.
 * @name WebmOpusDemuxer#TOO_SHORT
 * @type {Symbol}
 */
const TOO_SHORT = WebmOpusDemuxer.TOO_SHORT = Symbol('TOO_SHORT');

/**
 * A map that takes a value of an EBML ID in hex string form, with the value being a boolean that indicates whether
 * this tag has children.
 * @name WebmOpusDemuxer#TAGS
 * @type {Object}
 */
const TAGS = WebmOpusDemuxer.TAGS = { // value is true if the element has children
  '1a45dfa3': true, // EBML
  '18538067': true, // Segment
  '1f43b675': true, // Cluster
  '1654ae6b': true, // _tracks
  'ae': true, // _trackEntry
  'd7': false, // _trackNumber
  '83': false, // _trackType
  'a3': false, // Simple Block
};

module.exports = WebmOpusDemuxer;

function vintLength(buffer, index) {
  let i = 0;
  for (; i < 8; i++) if ((1 << (7 - i)) & buffer[index]) break;
  i++;
  if (index + i > buffer.length) {
    return TOO_SHORT;
  }
  return i;
}

function expandVint(buffer, start, end) {
  const length = vintLength(buffer, start);
  if (end > buffer.length || length === TOO_SHORT) return TOO_SHORT;
  let mask = (1 << (8 - length)) - 1;
  let value = buffer[start] & mask;
  for (let i = start + 1; i < end; i++) {
    value = (value << 8) + buffer[i];
  }
  return value;
}
<commit_msg>Check for EBML tag<commit_after>const { Transform } = require('stream');

/**
 * Demuxes a Webm stream (containing Opus audio) to output an Opus stream.
 * @extends {TransformStream}
 */
class WebmOpusDemuxer extends Transform {
  /**
   * Creates a new WebmOpus demuxer.
   * @param {Object} [options] options that you would pass to a regular Transform stream.
   */
  constructor(options = {}) {
    super(Object.assign({ readableObjectMode: true }, options));
    this._remainder = null;
    this._length = 0;
    this._count = 0;
    this._skipUntil = null;
    this._track = null;
    this._incompleteTrack = {};
    this._ebmlFound = false;
  }

  _transform(chunk, encoding, done) {
    this._length += chunk.length;
    if (this._remainder) {
      chunk = Buffer.concat([this._remainder, chunk]);
      this._remainder = null;
    }
    let offset = 0;
    if (this._skipUntil && this._length > this._skipUntil) {
      offset = this._skipUntil - this._count;
      this._skipUntil = null;
    } else if (this._skipUntil) {
      this._count += chunk.length;
      return done();
    }
    let result;
    while (result !== TOO_SHORT) {
      result = this._readTag(chunk, offset);
      if (result === TOO_SHORT) break;
      if (result._skipUntil) {
        this._skipUntil = result._skipUntil;
        break;
      }
      if (result.offset) offset = result.offset;
      else break;
    }
    this._count += offset;
    this._remainder = chunk.slice(offset);
    return done();
  }

  /**
   * Reads an EBML ID from a buffer.
   * @private
   * @param {Buffer} chunk the buffer to read from.
   * @param {number} offset the offset in the buffer.
   * @returns {Object|Symbol} contains an `id` property (buffer) and the new `offset` (number).
   * Returns the TOO_SHORT symbol if the data wasn't big enough to facilitate the request.
   */
  _readEBMLId(chunk, offset) {
    const idLength = vintLength(chunk, offset);
    if (idLength === TOO_SHORT) return TOO_SHORT;
    return {
      id: chunk.slice(offset, offset + idLength),
      offset: offset + idLength,
    };
  }

  /**
   * Reads a size variable-integer to calculate the length of the data of a tag.
   * @private
   * @param {Buffer} chunk the buffer to read from.
   * @param {number} offset the offset in the buffer.
   * @returns {Object|Symbol} contains property `offset` (number), `dataLength` (number) and `sizeLength` (number).
   * Returns the TOO_SHORT symbol if the data wasn't big enough to facilitate the request.
   */
  _readTagDataSize(chunk, offset) {
    const sizeLength = vintLength(chunk, offset);
    if (sizeLength === TOO_SHORT) return TOO_SHORT;
    const dataLength = expandVint(chunk, offset, offset + sizeLength);
    return { offset: offset + sizeLength, dataLength, sizeLength };
  }

  /**
   * Takes a buffer and attempts to read and process a tag.
   * @private
   * @param {Buffer} chunk the buffer to read from.
   * @param {number} offset the offset in the buffer.
   * @returns {Object|Symbol} contains the new `offset` (number) and optionally the `_skipUntil` property,
   * indicating that the stream should ignore any data until a certain length is reached.
   * Returns the TOO_SHORT symbol if the data wasn't big enough to facilitate the request.
   */
  _readTag(chunk, offset) {
    const idData = this._readEBMLId(chunk, offset);
    if (idData === TOO_SHORT) return TOO_SHORT;
    const ebmlID = idData.id.toString('hex');
    if (!this._ebmlFound) {
      if (ebmlID === '1a45dfa3') this._ebmlFound = true;
      else throw Error('Did not find the EBML tag at the start of the stream');
    }
    offset = idData.offset;
    const sizeData = this._readTagDataSize(chunk, offset);
    if (sizeData === TOO_SHORT) return TOO_SHORT;
    const { dataLength } = sizeData;
    offset = sizeData.offset;
    // If this tag isn't useful, tell the stream to stop processing data until the tag ends
    if (typeof TAGS[ebmlID] === 'undefined') {
      if (chunk.length > offset + dataLength) {
        return { offset: offset + dataLength };
      }
      return { offset, _skipUntil: this._count + offset + dataLength };
    }

    const tagHasChildren = TAGS[ebmlID];
    if (tagHasChildren) {
      return { offset };
    }

    if (offset + dataLength > chunk.length) return TOO_SHORT;
    const data = chunk.slice(offset, offset + dataLength);
    if (!this._track) {
      if (ebmlID === 'ae') this._incompleteTrack = {};
      if (ebmlID === 'd7') this._incompleteTrack.number = data[0];
      if (ebmlID === '83') this._incompleteTrack.type = data[0];
      if (this._incompleteTrack.type === 2 && typeof this._incompleteTrack.number !== 'undefined') {
        this._track = this._incompleteTrack;
      }
    }
    if (ebmlID === 'a3') {
      if (!this._track) throw Error('No audio track in this webm!');
      if ((data[0] & 0xF) === this._track.number) {
        this.push(data.slice(4));
      }
    }
    return { offset: offset + dataLength };
  }
}

/**
 * A symbol that is returned by some functions that indicates the buffer it has been provided is not large enough
 * to facilitate a request.
 * @name WebmOpusDemuxer#TOO_SHORT
 * @type {Symbol}
 */
const TOO_SHORT = WebmOpusDemuxer.TOO_SHORT = Symbol('TOO_SHORT');

/**
 * A map that takes a value of an EBML ID in hex string form, with the value being a boolean that indicates whether
 * this tag has children.
 * @name WebmOpusDemuxer#TAGS
 * @type {Object}
 */
const TAGS = WebmOpusDemuxer.TAGS = { // value is true if the element has children
  '1a45dfa3': true, // EBML
  '18538067': true, // Segment
  '1f43b675': true, // Cluster
  '1654ae6b': true, // Tracks
  'ae': true, // TrackEntry
  'd7': false, // TrackNumber
  '83': false, // TrackType
  'a3': false, // SimpleBlock
};

module.exports = WebmOpusDemuxer;

function vintLength(buffer, index) {
  let i = 0;
  for (; i < 8; i++) if ((1 << (7 - i)) & buffer[index]) break;
  i++;
  if (index + i > buffer.length) {
    return TOO_SHORT;
  }
  return i;
}

function expandVint(buffer, start, end) {
  const length = vintLength(buffer, start);
  if (end > buffer.length || length === TOO_SHORT) return TOO_SHORT;
  let mask = (1 << (8 - length)) - 1;
  let value = buffer[start] & mask;
  for (let i = start + 1; i < end; i++) {
    value = (value << 8) + buffer[i];
  }
  return value;
}
<|endoftext|>


<commit_before>/*
 * grunt-aws-lambda
 * https://github.com/Tim-B/grunt-aws-lambda
 *
 * Copyright (c) 2014 Tim-B
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function (grunt) {

    var path = require('path');
    var fs = require('fs');
    var AWS = require('aws-sdk');

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks

    grunt.registerMultiTask('lambda_deploy', 'Uploads a package to lambda', function () {

        grunt.config.requires('lambda_deploy.' + this.target + '.package');

        var options = this.options({
            profile: null,
            region: 'us-east-1',
            timeout: null,
            memory: null
        });

        if (options.profile !== null) {
            var credentials = new AWS.SharedIniFileCredentials({profile: options.profile});
            AWS.config.credentials = credentials;
        }

        var deploy_function = grunt.config.get('lambda_deploy.' + this.target + '.function');
        var deploy_arn = grunt.config.get('lambda_deploy.' + this.target + '.arn');
        var deploy_package = grunt.config.get('lambda_deploy.' + this.target + '.package');

        if(deploy_arn === null && deploy_function === null) {
            grunt.fail.warn('You must specify either an arn or a function name.');
        }

        if(deploy_arn !== null) {
            deploy_function = deploy_arn;
        }

        var done = this.async();

        AWS.config.update({region: options.region});
        var lambda = new AWS.Lambda({
            apiVersion: '2015-03-31'
        });

        lambda.getFunction({FunctionName: deploy_function}, function (err, data) {

            if (err) {
                if(err.statusCode === 404) {
                    grunt.fail.warn('Unable to find lambda function ' + deploy_function + ', verify the lambda function name and AWS region are correct.');
                } else {
                    grunt.fail.warn('AWS API request failed, check your AWS credentials, region and permissions are correct.');
                }
            }

            var current = data.Configuration;
            var configParams = {};

            if (options.timeout !== null) {
                configParams.Timeout = options.timeout;
            }

            if (options.memory !== null) {
                configParams.MemorySize = options.memory;
            }

            var updateConfig = function(func_name, func_options, callback) {
                if(Object.keys(func_options).length > 0) {
                    func_options.FunctionName = func_name;
                    lambda.updateFunctionConfiguration(func_options, function(err, data) {
                        if (err) {
                            grunt.fail.warn('Could not update config, check that values and permissions are valid');
                        }
                        grunt.log.writeln('Config updated.');
                        callback(data);
                    });
                } else {
                    grunt.log.writeln('No config updates to make.');
                    callback(false);
                    return;
                }
            }

            grunt.log.writeln('Uploading...');
            fs.readFile(deploy_package, function (err, data) {
                if (err) {
                    grunt.fail.warn('Could not read package file ('+deploy_package+'), verify the lambda package '+
                        'location is correct, and that you have already created the package using lambda_package.');
                }

                var codeParams = {
                    FunctionName: deploy_function,
                    ZipFile: data
                }

                lambda.updateFunctionCode(codeParams, function (err, data) {
                    if (err) {
                        grunt.fail.warn('Package upload failed, check you have lambda:UpdateFunctionCode permissions.');
                    }
                    grunt.log.writeln('Package deployed.');
                    updateConfig(deploy_function, configParams, function(data){
                        done(true);
                    });
                });
            });
        });
    });
};
<commit_msg>JSHint semicolon fixes for lambda_deploy.js<commit_after>/*
 * grunt-aws-lambda
 * https://github.com/Tim-B/grunt-aws-lambda
 *
 * Copyright (c) 2014 Tim-B
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function (grunt) {

    var path = require('path');
    var fs = require('fs');
    var AWS = require('aws-sdk');

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks

    grunt.registerMultiTask('lambda_deploy', 'Uploads a package to lambda', function () {

        grunt.config.requires('lambda_deploy.' + this.target + '.package');

        var options = this.options({
            profile: null,
            region: 'us-east-1',
            timeout: null,
            memory: null
        });

        if (options.profile !== null) {
            var credentials = new AWS.SharedIniFileCredentials({profile: options.profile});
            AWS.config.credentials = credentials;
        }

        var deploy_function = grunt.config.get('lambda_deploy.' + this.target + '.function');
        var deploy_arn = grunt.config.get('lambda_deploy.' + this.target + '.arn');
        var deploy_package = grunt.config.get('lambda_deploy.' + this.target + '.package');

        if(deploy_arn === null && deploy_function === null) {
            grunt.fail.warn('You must specify either an arn or a function name.');
        }

        if(deploy_arn !== null) {
            deploy_function = deploy_arn;
        }

        var done = this.async();

        AWS.config.update({region: options.region});
        var lambda = new AWS.Lambda({
            apiVersion: '2015-03-31'
        });

        lambda.getFunction({FunctionName: deploy_function}, function (err, data) {

            if (err) {
                if(err.statusCode === 404) {
                    grunt.fail.warn('Unable to find lambda function ' + deploy_function + ', verify the lambda function name and AWS region are correct.');
                } else {
                    grunt.fail.warn('AWS API request failed, check your AWS credentials, region and permissions are correct.');
                }
            }

            var current = data.Configuration;
            var configParams = {};

            if (options.timeout !== null) {
                configParams.Timeout = options.timeout;
            }

            if (options.memory !== null) {
                configParams.MemorySize = options.memory;
            }

            var updateConfig = function(func_name, func_options, callback) {
                if(Object.keys(func_options).length > 0) {
                    func_options.FunctionName = func_name;
                    lambda.updateFunctionConfiguration(func_options, function(err, data) {
                        if (err) {
                            grunt.fail.warn('Could not update config, check that values and permissions are valid');
                        }
                        grunt.log.writeln('Config updated.');
                        callback(data);
                    });
                } else {
                    grunt.log.writeln('No config updates to make.');
                    callback(false);
                    return;
                }
            };

            grunt.log.writeln('Uploading...');
            fs.readFile(deploy_package, function (err, data) {
                if (err) {
                    grunt.fail.warn('Could not read package file ('+deploy_package+'), verify the lambda package '+
                        'location is correct, and that you have already created the package using lambda_package.');
                }

                var codeParams = {
                    FunctionName: deploy_function,
                    ZipFile: data
                };

                lambda.updateFunctionCode(codeParams, function (err, data) {
                    if (err) {
                        grunt.fail.warn('Package upload failed, check you have lambda:UpdateFunctionCode permissions.');
                    }
                    grunt.log.writeln('Package deployed.');
                    updateConfig(deploy_function, configParams, function(data){
                        done(true);
                    });
                });
            });
        });
    });
};
<|endoftext|>


<commit_before>/*
 * grunt
 * http://gruntjs.com/
 *
 * Copyright (c) 2012 "Cowboy" Ben Alman
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 */

// External libs.
var semver = require('semver');
var Tempfile = require('temporary/lib/file');
var EventEmitter2 = require('eventemitter2').EventEmitter2;

exports.init = function(grunt) {
  'use strict';
  var exports = new EventEmitter2({wildcard: true});

  // Call this when everything has finished successfully... or when something
  // horrible happens, and you need to clean up and abort.
  var halted;
  exports.halt = function() {
    halted = true;
  };

  // Start PhantomJS process.
  exports.spawn = function(pageUrl, options) {
    // Create temporary file to be used for grunt-phantom communication.
    var tempfile = new Tempfile();
    // Timeout ID.
    var id;
    // The number of tempfile lines already read.
    var n = 0;
    // Reset halted flag.
    halted = null;

    // All done? Clean up!
    var cleanup = function() {
      clearTimeout(id);
      tempfile.unlink();
    };

    // Internal methods.
    var privates = {
      // Abort if PhantomJS version isn't adequate.
      version: function(version) {
        var current = [version.major, version.minor, version.patch].join('.');
        var required = '>= 1.6.0';
        if (!semver.satisfies(current, required)) {
          exports.halt();
          grunt.log.writeln();
          grunt.log.errorlns(
            'In order for this task to work properly, PhantomJS version ' +
            required + ' must be installed, but version ' + current +
            ' was detected.'
          );
          grunt.warn('The correct version of PhantomJS needs to be installed.', 127);
        }
      }
    };

    // It's simple. As the page running in PhantomJS alerts messages, they
    // are written as JSON to a temporary file. This polling loop checks that
    // file for new lines, and for each one parses its JSON and emits the
    // corresponding event with the specified arguments.
    (function loopy() {
      // Disable logging temporarily.
      grunt.log.muted = true;
      // Read the file, splitting lines on \n, and removing a trailing line.
      var lines = grunt.file.read(tempfile.path).split('\n').slice(0, -1);
      // Re-enable logging.
      grunt.log.muted = false;
      // Iterate over all lines that haven't already been processed.
      var done = lines.slice(n).some(function(line) {
        // Get args and method.
        var args = JSON.parse(line);
        var eventName = args[0];
        // Debugging messages.
        grunt.log.debug(JSON.stringify(['phantomjs'].concat(args)).magenta);
        if (eventName === 'private') {
          // If a private (internal) message is passed, execute the
          // corresponding method.
          privates[args[1]].apply(null, args.slice(2));
        } else {
          // Otherwise, emit the event with its arguments.
          exports.emit.apply(exports, args);
        }
        // If halted, return true. Because the Array#some method was used,
        // this not only sets "done" to true, but stops further iteration
        // from occurring.
        return halted;
      });

      if (done) {
        // All done.
        cleanup();
        options.done(null);
      } else {
        // Update n so previously processed lines are ignored.
        n = lines.length;
        // Check back in a little bit.
        id = setTimeout(loopy, 100);
      }
    }());

    // Process options.
    var failCode = options.failCode || 0;

    // Build an array of optional PhantomJS --args
    var args = [];
    Object.keys(options.options.phantomjs).forEach(function(key) {
      var optionValue = options.options.phantomjs[key];

      if (optionValue === true)       optionValue = 'yes';
      else if (optionValue === false) optionValue = 'no';

      args.push('--' + key + '=' + optionValue);
    });

    var bootstrapOptions = {
      timeout : options.options.timeout
    };

    // Actually spawn PhantomJS.
    return grunt.util.spawn({
      cmd: 'phantomjs',
      args: args.concat([
        // The main PhantomJS script file.
        grunt.task.getFile('lib/phantomjs/bootstrap.js'),
        // The temporary file used for communications.
        tempfile.path,
        // URL or path to the page .html test file to run.
        pageUrl,
        // Additional PhantomJS options.
        JSON.stringify(bootstrapOptions)
      ])
    }, function(err, result, code) {
      if (!err) { return; }
      // Something went horribly wrong.
      cleanup();
      grunt.verbose.or.writeln();
      grunt.log.write('Running PhantomJS...').error();
      if (code === 127) {
        grunt.log.errorlns(
          'In order for this task to work properly, PhantomJS must be ' +
          'installed and in the system PATH (if you can run "phantomjs" at' +
          ' the command line, this task should work). Unfortunately, ' +
          'PhantomJS cannot be installed automatically via npm or grunt. ' +
          'See the grunt FAQ for PhantomJS installation instructions: ' +
          'https://github.com/cowboy/grunt/blob/master/docs/faq.md'
        );
        grunt.warn('PhantomJS not found.', failCode);
      } else {
        String(result).split('\n').forEach(grunt.log.error, grunt.log);
        grunt.warn('PhantomJS exited unexpectedly with exit code ' + code + '.', failCode);
      }
      options.done(code);
    });
  };

  return exports;
};
<commit_msg>refactored phantomjs lib to not require grunt as argument<commit_after>/*
 * grunt
 * http://gruntjs.com/
 *
 * Copyright (c) 2012 "Cowboy" Ben Alman
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 */

// External libs.
var semver = require('semver');
var Tempfile = require('temporary/lib/file');
var EventEmitter2 = require('eventemitter2').EventEmitter2;
var grunt = require('grunt');

var phantomjs = module.exports = new EventEmitter2({wildcard: true});

// Call this when everything has finished successfully... or when something
// horrible happens, and you need to clean up and abort.
var halted;
function halt() {
  halted = true;
}
phantomjs.halt = halt;

// Start PhantomJS process.
phantomjs.spawn = function(pageUrl, options) {
  // Create temporary file to be used for grunt-phantom communication.
  var tempfile = new Tempfile();
  // Timeout ID.
  var id;
  // The number of tempfile lines already read.
  var n = 0;
  // Reset halted flag.
  halted = null;

  // All done? Clean up!
  var cleanup = function() {
    clearTimeout(id);
    tempfile.unlink();
  };

  // Internal methods.
  var privates = {
    // Abort if PhantomJS version isn't adequate.
    version: function(version) {
      var current = [version.major, version.minor, version.patch].join('.');
      var required = '>= 1.6.0';
      if (!semver.satisfies(current, required)) {
        halt();
        grunt.log.writeln();
        grunt.log.errorlns(
          'In order for this task to work properly, PhantomJS version ' +
          required + ' must be installed, but version ' + current +
          ' was detected.'
        );
        grunt.warn('The correct version of PhantomJS needs to be installed.', 127);
      }
    }
  };

  // It's simple. As the page running in PhantomJS alerts messages, they
  // are written as JSON to a temporary file. This polling loop checks that
  // file for new lines, and for each one parses its JSON and emits the
  // corresponding event with the specified arguments.
  (function loopy() {
    // Disable logging temporarily.
    grunt.log.muted = true;
    // Read the file, splitting lines on \n, and removing a trailing line.
    var lines = grunt.file.read(tempfile.path).split('\n').slice(0, -1);
    // Re-enable logging.
    grunt.log.muted = false;
    // Iterate over all lines that haven't already been processed.
    var done = lines.slice(n).some(function(line) {
      // Get args and method.
      var args = JSON.parse(line);
      var eventName = args[0];
      // Debugging messages.
      grunt.log.debug(JSON.stringify(['phantomjs'].concat(args)).magenta);
      if (eventName === 'private') {
        // If a private (internal) message is passed, execute the
        // corresponding method.
        privates[args[1]].apply(null, args.slice(2));
      } else {
        // Otherwise, emit the event with its arguments.
        phantomjs.emit.apply(phantomjs, args);
      }
      // If halted, return true. Because the Array#some method was used,
      // this not only sets "done" to true, but stops further iteration
      // from occurring.
      return halted;
    });

    if (done) {
      // All done.
      cleanup();
      options.done(null);
    } else {
      // Update n so previously processed lines are ignored.
      n = lines.length;
      // Check back in a little bit.
      id = setTimeout(loopy, 100);
    }
  }());

  // Process options.
  var failCode = options.failCode || 0;

  // Build an array of optional PhantomJS --args
  var args = [];
  Object.keys(options.options.phantomjs).forEach(function(key) {
    var optionValue = options.options.phantomjs[key];

    if (optionValue === true)       optionValue = 'yes';
    else if (optionValue === false) optionValue = 'no';

    args.push('--' + key + '=' + optionValue);
  });

  var bootstrapOptions = {
    timeout : options.options.timeout
  };

  // Actually spawn PhantomJS.
  return grunt.util.spawn({
    cmd: 'phantomjs',
    args: args.concat([
      // The main PhantomJS script file.
      grunt.task.getFile('lib/phantomjs/bootstrap.js'),
      // The temporary file used for communications.
      tempfile.path,
      // URL or path to the page .html test file to run.
      pageUrl,
      // Additional PhantomJS options.
      JSON.stringify(bootstrapOptions)
    ])
  }, function(err, result, code) {
    if (!err) { return; }
    // Something went horribly wrong.
    cleanup();
    grunt.verbose.or.writeln();
    grunt.log.write('Running PhantomJS...').error();
    if (code === 127) {
      grunt.log.errorlns(
        'In order for this task to work properly, PhantomJS must be ' +
        'installed and in the system PATH (if you can run "phantomjs" at' +
        ' the command line, this task should work). Unfortunately, ' +
        'PhantomJS cannot be installed automatically via npm or grunt. ' +
        'See the grunt FAQ for PhantomJS installation instructions: ' +
        'https://github.com/cowboy/grunt/blob/master/docs/faq.md'
      );
      grunt.warn('PhantomJS not found.', failCode);
    } else {
      String(result).split('\n').forEach(grunt.log.error, grunt.log);
      grunt.warn('PhantomJS exited unexpectedly with exit code ' + code + '.', failCode);
    }
    options.done(code);
  });
};

<|endoftext|>


<commit_before>L.BingLayer = L.TileLayer.extend({
	options: {
		subdomains: [0, 1, 2, 3],
		attribution: 'Bing'
	},

	initialize: function(key, options) {
		L.Util.setOptions(this, options);

		this._key = key;
		this._url = null;
		this.meta = {};
		this.loadMetadata();
	},

	tile2quad: function(x, y, z) {
		var quad = '';
		for (var i = z; i > 0; i--) {
			var digit = 0;
			var mask = 1 << (i - 1);
			if ((x & mask) != 0) digit += 1;
			if ((y & mask) != 0) digit += 2;
			quad = quad + digit;
		}
		return quad;
	},

	getTileUrl: function(p, z) {
		var subdomains = this.options.subdomains,
			s = this.options.subdomains[(p.x + p.y) % subdomains.length];
		return this._url.replace('{subdomain}', s)
				.replace('{quadkey}', this.tile2quad(p.x, p.y, z))
				.replace('{culture}', '');
	},

	loadMetadata: function() {
		var _this = this;
		var cbid = '_bing_metadata';
		window[cbid] = function (meta) {
			_this.meta = meta;
			window[cbid] = undefined;
			var e = document.getElementById(cbid);
			e.parentNode.removeChild(e);
			if (meta.errorDetails) {
				alert("Got metadata" + meta.errorDetails);
				return;
			}
			_this.initMetadata();
		};
		var url = "http://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&jsonp=" + cbid + "&key=" + this._key;
		var script = document.createElement("script");
		script.type = "text/javascript";
		script.src = url;
		script.id = cbid;
		document.getElementsByTagName("head")[0].appendChild(script);
	},

	initMetadata: function() {
		var r = this.meta.resourceSets[0].resources[0];
		this.options.subdomains = r.imageUrlSubdomains;
		this._url = r.imageUrl;
		this._providers = [];
		for (var i = 0; i < r.imageryProviders.length; i++) {
			var p = r.imageryProviders[i];
			for (var j = 0; j < p.coverageAreas.length; j++) {
				var c = p.coverageAreas[j];
				var coverage = {zoomMin: c.zoomMin, zoomMax: c.zoomMax, active: false};
				var bounds = new L.LatLngBounds(
						new L.LatLng(c.bbox[0]+0.01, c.bbox[1]+0.01),
						new L.LatLng(c.bbox[2]-0.01, c.bbox[3]-0.01)
				);
				coverage.bounds = bounds;
				coverage.attrib = p.attribution;
				this._providers.push(coverage);
			}
		}
		this._update();
	},

	_update: function() {
		if (this._url == null || !this._map) return;
		this._update_attribution();
		L.TileLayer.prototype._update.apply(this, []);
	},

	_update_attribution: function() {
		var bounds = this._map.getBounds();
		var zoom = this._map.getZoom();
		for (var i = 0; i < this._providers.length; i++) {
			var p = this._providers[i];
			if ((zoom <= p.zoomMax && zoom >= p.zoomMin) &&
					bounds.intersects(p.bounds)) {
				if (!p.active)
					this._map.attributionControl.addAttribution(p.attrib);
				p.active = true;
			} else {
				if (p.active)
					this._map.attributionControl.removeAttribution(p.attrib);
				p.active = false;
			}
		}
	},

	onRemove: function(map) {
		for (var i = 0; i < this._providers.length; i++) {
			var p = this._providers[i];
			if (p.active) {
				this._map.attributionControl.removeAttribution(p.attrib);
				p.active = false;
			}
		}
        	L.TileLayer.prototype.onRemove.apply(this, [map]);
	}
});
<commit_msg>bing: Support different Bing layers (see #23)<commit_after>L.BingLayer = L.TileLayer.extend({
	options: {
		subdomains: [0, 1, 2, 3],
		type: 'Aerial',
		attribution: 'Bing'
	},

	initialize: function(key, options) {
		L.Util.setOptions(this, options);

		this._key = key;
		this._url = null;
		this.meta = {};
		this.loadMetadata();
	},

	tile2quad: function(x, y, z) {
		var quad = '';
		for (var i = z; i > 0; i--) {
			var digit = 0;
			var mask = 1 << (i - 1);
			if ((x & mask) != 0) digit += 1;
			if ((y & mask) != 0) digit += 2;
			quad = quad + digit;
		}
		return quad;
	},

	getTileUrl: function(p, z) {
		var subdomains = this.options.subdomains,
			s = this.options.subdomains[(p.x + p.y) % subdomains.length];
		return this._url.replace('{subdomain}', s)
				.replace('{quadkey}', this.tile2quad(p.x, p.y, z))
				.replace('{culture}', '');
	},

	loadMetadata: function() {
		var _this = this;
		var cbid = '_bing_metadata_' + L.Util.stamp(this);
		window[cbid] = function (meta) {
			_this.meta = meta;
			window[cbid] = undefined;
			var e = document.getElementById(cbid);
			e.parentNode.removeChild(e);
			if (meta.errorDetails) {
				alert("Got metadata" + meta.errorDetails);
				return;
			}
			_this.initMetadata();
		};
		var url = "http://dev.virtualearth.net/REST/v1/Imagery/Metadata/" + this.options.type + "?include=ImageryProviders&jsonp=" + cbid + "&key=" + this._key;
		var script = document.createElement("script");
		script.type = "text/javascript";
		script.src = url;
		script.id = cbid;
		document.getElementsByTagName("head")[0].appendChild(script);
	},

	initMetadata: function() {
		var r = this.meta.resourceSets[0].resources[0];
		this.options.subdomains = r.imageUrlSubdomains;
		this._url = r.imageUrl;
		this._providers = [];
		for (var i = 0; i < r.imageryProviders.length; i++) {
			var p = r.imageryProviders[i];
			for (var j = 0; j < p.coverageAreas.length; j++) {
				var c = p.coverageAreas[j];
				var coverage = {zoomMin: c.zoomMin, zoomMax: c.zoomMax, active: false};
				var bounds = new L.LatLngBounds(
						new L.LatLng(c.bbox[0]+0.01, c.bbox[1]+0.01),
						new L.LatLng(c.bbox[2]-0.01, c.bbox[3]-0.01)
				);
				coverage.bounds = bounds;
				coverage.attrib = p.attribution;
				this._providers.push(coverage);
			}
		}
		this._update();
	},

	_update: function() {
		if (this._url == null || !this._map) return;
		this._update_attribution();
		L.TileLayer.prototype._update.apply(this, []);
	},

	_update_attribution: function() {
		var bounds = this._map.getBounds();
		var zoom = this._map.getZoom();
		for (var i = 0; i < this._providers.length; i++) {
			var p = this._providers[i];
			if ((zoom <= p.zoomMax && zoom >= p.zoomMin) &&
					bounds.intersects(p.bounds)) {
				if (!p.active)
					this._map.attributionControl.addAttribution(p.attrib);
				p.active = true;
			} else {
				if (p.active)
					this._map.attributionControl.removeAttribution(p.attrib);
				p.active = false;
			}
		}
	},

	onRemove: function(map) {
		for (var i = 0; i < this._providers.length; i++) {
			var p = this._providers[i];
			if (p.active) {
				this._map.attributionControl.removeAttribution(p.attrib);
				p.active = false;
			}
		}
        	L.TileLayer.prototype.onRemove.apply(this, [map]);
	}
});
<|endoftext|>


<commit_before>import findTabbableElement from './tabbable';

let ancestor = null;
let focusLaterElement = null;

const handleScopedFocus = () => {
	if (!ancestor) {
		return;
	}
	// need to see how jQuery shims document.on('focusin') so we don't need the
	// setTimeout, firefox doesn't support focusin, if it did, we could focus
	// the element outside of a setTimeout. Side-effect of this implementation
	// is that the document.body gets focus, and then we focus our element right
	// after.
	setTimeout(() => {
		if (ancestor && !ancestor.contains(document.activeElement)) {
			const el = (findTabbableElement(ancestor)[0] || ancestor);
			el.focus();
		}
	}, 0);
};

const handleScopedBlur = () => {
	handleScopedFocus();
};

// PUBLIC methods

const focusAncestor = () => {
	ancestor.focus();
};

const hasOrAncestorHasFocus = () =>
	document.activeElement === ancestor
	|| ancestor.contains(document.activeElement);

const returnFocusToStoredElement = () => {
	try {
		focusLaterElement.focus();
	}	catch (e) {
		console.warn(`You tried to return focus to ${focusLaterElement} but it is not in the DOM anymore`); // eslint-disable-line no-console
	}
	focusLaterElement = null;
};

const setupScopedFocus = ({ ancestorElement }) => {
	ancestor = ancestorElement;
	window.addEventListener('blur', handleScopedBlur, false);
	document.addEventListener('focus', handleScopedFocus, true);
};

const storeActiveElement = () => {
	focusLaterElement = document.activeElement;
};

const teardownScopedFocus = () => {
	ancestor = null;
	window.removeEventListener('blur', handleScopedBlur);
	document.removeEventListener('focus', handleScopedFocus);
};

module.exports = {
	focusAncestor,
	hasOrAncestorHasFocus,
	returnFocusToStoredElement,
	setupScopedFocus,
	storeActiveElement,
	teardownScopedFocus
};
<commit_msg>fix popover trap focus<commit_after>import findTabbableElement from './tabbable';

let ancestor = null;
let focusLaterElement = null;

const handleScopedKeyDown = (event) => {
	if (!ancestor) {
		return;
	}
	const tabbableElements = findTabbableElement(ancestor);
	const finalTabbable = tabbableElements[event.shiftKey ? 0 : tabbableElements.length - 1];
	const leavingFinalTabbable = (
		finalTabbable === document.activeElement ||
		// handle immediate shift+tab after opening with mouse
		ancestor === document.activeElement
	);
	if (!leavingFinalTabbable) return;
	event.preventDefault();
	const target = tabbableElements[event.shiftKey ? tabbableElements.length - 1 : 0];
	target.focus();
};

// PUBLIC methods

const focusAncestor = () => {
	ancestor.focus();
};

const hasOrAncestorHasFocus = () =>
	document.activeElement === ancestor
	|| ancestor.contains(document.activeElement);

const returnFocusToStoredElement = () => {
	try {
		focusLaterElement.focus();
	}	catch (e) {
		console.warn(`You tried to return focus to ${focusLaterElement} but it is not in the DOM anymore`); // eslint-disable-line no-console
	}
	focusLaterElement = null;
};

const setupScopedFocus = ({ ancestorElement }) => {
	ancestor = ancestorElement;
	window.addEventListener('keydown', handleScopedKeyDown, false);
};

const storeActiveElement = () => {
	focusLaterElement = document.activeElement;
};

const teardownScopedFocus = () => {
	ancestor = null;
	window.removeEventListener('keydown', handleScopedKeyDown);
};

module.exports = {
	focusAncestor,
	hasOrAncestorHasFocus,
	returnFocusToStoredElement,
	setupScopedFocus,
	storeActiveElement,
	teardownScopedFocus
};
<|endoftext|>


<commit_before>enyo.kind({
        name: "Ares.ErrorPopup",
        kind: "onyx.Popup",
        modal: true,
        centered: true,
        floating: true,
        published: {
        	errorMsg: "unknown error",
        },
        components: [
                {tag: "h3", content: "Oh, no!?"},
                {name: "msg"},
                {tag: "br"},
                {name: "okButton", kind: "onyx.Button", classes: "onyx-affirmative", content: "Ok", ontap: "hideErrorPopup"}
        ],
        create: function() {
                this.inherited(arguments);
        },
        errorMsgChanged: function (oldVal) {
        	this.$.msg.setContent(this.errorMsg);
        },
        hideErrorPopup: function(inSender, inEvent) {
                this.hide();
        }

});
<commit_msg>ENYO-1408: ErrorPopup: added a raise method<commit_after>enyo.kind({
        name: "Ares.ErrorPopup",
        kind: "onyx.Popup",
        modal: true,
        centered: true,
        floating: true,
        published: {
        	errorMsg: "unknown error",
        },
        components: [
                {tag: "h3", content: "Oh, no!?"},
                {name: "msg"},
                {tag: "br"},
                {name: "okButton", kind: "onyx.Button", classes: "onyx-affirmative", content: "Ok", ontap: "hideErrorPopup"}
        ],
        create: function() {
                this.inherited(arguments);
        },
        errorMsgChanged: function (oldVal) {
        	this.$.msg.setContent(this.errorMsg);
        },
        hideErrorPopup: function(inSender, inEvent) {
                this.hide();
        },
        raise: function(msg) {
			this.setErrorMsg(msg);
			this.show();
		}
});
<|endoftext|>