<commit_before>/*
 * Copyright (C) 2015 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

import $ from 'jquery'
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import I18n from 'i18n!react_files'
import filesEnv from 'compiled/react_files/modules/filesEnv'

function omitEmptyValues(obj) {
  Object.keys(obj).forEach(k => {
    if (obj[k] == null) delete obj[k]
  })
  return obj
}

const CONTENT_OPTIONS = [
  {
    display: I18n.t('Choose usage rights...'),
    value: 'choose'
  },
  {
    display: I18n.t('I hold the copyright'),
    value: 'own_copyright'
  },
  {
    display: I18n.t('I have obtained permission to use this file.'),
    value: 'used_by_permission'
  },
  {
    display: I18n.t('The material is in the public domain'),
    value: 'public_domain'
  },
  {
    display: I18n.t('The material is subject to fair use exception'),
    value: 'fair_use'
  },
  {
    display: I18n.t('The material is licensed under Creative Commons'),
    value: 'creative_commons'
  }
]

export default class UsageRightsSelectBox extends React.Component {
  propTypes = {
    use_justification: PropTypes.oneOf(Object.values(CONTENT_OPTIONS).map(o => o.value)),
    copyright: PropTypes.string,
    showMessage: PropTypes.bool,
    contextType: PropTypes.string,
    contextId: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
  }

  state = {
    showTextBox: this.props.use_justification !== 'choose',
    showCreativeCommonsOptions:
      this.props.use_justification === 'creative_commons' && this.props.copyright != null,
    licenseOptions: [],
    showMessage: this.props.showMessage,
    usageRightSelectionValue: this.props.use_justification
      ? this.props.use_justification
      : undefined
  }

  componentDidMount() {
    this.getUsageRightsOptions()
  }

  apiUrl() {
    return `/api/v1/${filesEnv.contextType || this.props.contextType}/${filesEnv.contextId ||
      this.props.contextId}/content_licenses`
  }

  // Exposes the selected values to the outside world.
  getValues() {
    let x
    const obj = {
      use_justification: ReactDOM.findDOMNode(this.refs.usageRightSelection).value,
      copyright: this.state.showTextBox
        ? (x = ReactDOM.findDOMNode(this.refs.copyright)) && x.value
        : undefined,
      cc_license: this.state.showCreativeCommonsOptions
        ? (x = ReactDOM.findDOMNode(this.refs.creativeCommons)) && x.value
        : undefined
    }

    return omitEmptyValues(obj)
  }

  getUsageRightsOptions() {
    return $.get(this.apiUrl(), data => {
      this.setState({
        licenseOptions: data
      })
    })
  }

  handleChange(event) {
    this.setState({
      usageRightSelectionValue: event.target.value,
      showTextBox: event.target.value !== 'choose',
      showCreativeCommonsOptions: event.target.value === 'creative_commons',
      showMessage: this.props.showMessage && event.target.value === 'choose'
    })
  }

  // This method only really applies to firefox which doesn't handle onChange
  // events on select boxes like every other browser.
  handleChooseKeyPress(event) {
    if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
      this.setState(
        {
          usageRightSelectionValue: event.target.value
        },
        this.handleChange(event)
      )
    }
  }

  renderContentOptions() {
    return CONTENT_OPTIONS.map(contentOption => (
      <option key={contentOption.value} value={contentOption.value}>
        {contentOption.display}
      </option>
    ))
  }

  renderCreativeCommonsOptions() {
    const onlyCC = this.state.licenseOptions.filter(license => license.id.indexOf('cc') === 0)

    return onlyCC.map(license => (
      <option key={license.id} value={license.id}>
        {license.name}
      </option>
    ))
  }

  renderShowCreativeCommonsOptions() {
    const renderShowCreativeCommonsOptions = (

          {I18n.t('Creative Commons License:')}

          <select
            id="creativeCommonsSelection"
            className="UsageRightsSelectBox__creativeCommons"
            ref="creativeCommons"
            defaultValue={this.props.cc_value}
          >
            {this.renderCreativeCommonsOptions()}
          </select>

    )
    return this.state.showCreativeCommonsOptions ? renderShowCreativeCommonsOptions : null
  }

  renderShowMessage() {
    const renderShowMessage = (

            {I18n.t(
              "If you do not select usage rights now, this file will be unpublished after it's uploaded."
            )}

    )
    return this.state.showMessage ? renderShowMessage : null
  }

  render() {
    return (

            {I18n.t('Usage Right:')}

            <select
              id="usageRightSelector"
              className="UsageRightsSelectBox__select"
              onChange={e => this.handleChange(e)}
              onKeyUp={e => this.handleChooseKeyPress(e)}
              ref="usageRightSelection"
              value={this.state.usageRightSelectionValue}
            >
              {this.renderContentOptions()}
            </select>

        {this.renderShowCreativeCommonsOptions()}

            {I18n.t('Copyright Holder:')}

            <input
              id="copyrightHolder"
              type="text"
              ref="copyright"
              defaultValue={this.props.copyright}
              placeholder={I18n.t('(c) 2001 Acme Inc.')}
            />

        {this.renderShowMessage()}

    )
  }
}
<commit_msg>Don’t include all react_files strings in usageRights<commit_after>/*
 * Copyright (C) 2015 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

import $ from 'jquery'
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import I18n from 'i18n!usageRightsSelectBox'
import filesEnv from 'compiled/react_files/modules/filesEnv'

function omitEmptyValues(obj) {
  Object.keys(obj).forEach(k => {
    if (obj[k] == null) delete obj[k]
  })
  return obj
}

const CONTENT_OPTIONS = [
  {
    display: I18n.t('Choose usage rights...'),
    value: 'choose'
  },
  {
    display: I18n.t('I hold the copyright'),
    value: 'own_copyright'
  },
  {
    display: I18n.t('I have obtained permission to use this file.'),
    value: 'used_by_permission'
  },
  {
    display: I18n.t('The material is in the public domain'),
    value: 'public_domain'
  },
  {
    display: I18n.t('The material is subject to fair use exception'),
    value: 'fair_use'
  },
  {
    display: I18n.t('The material is licensed under Creative Commons'),
    value: 'creative_commons'
  }
]

export default class UsageRightsSelectBox extends React.Component {
  propTypes = {
    use_justification: PropTypes.oneOf(Object.values(CONTENT_OPTIONS).map(o => o.value)),
    copyright: PropTypes.string,
    showMessage: PropTypes.bool,
    contextType: PropTypes.string,
    contextId: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
  }

  state = {
    showTextBox: this.props.use_justification !== 'choose',
    showCreativeCommonsOptions:
      this.props.use_justification === 'creative_commons' && this.props.copyright != null,
    licenseOptions: [],
    showMessage: this.props.showMessage,
    usageRightSelectionValue: this.props.use_justification
      ? this.props.use_justification
      : undefined
  }

  componentDidMount() {
    this.getUsageRightsOptions()
  }

  apiUrl() {
    return `/api/v1/${filesEnv.contextType || this.props.contextType}/${filesEnv.contextId ||
      this.props.contextId}/content_licenses`
  }

  // Exposes the selected values to the outside world.
  getValues() {
    let x
    const obj = {
      use_justification: ReactDOM.findDOMNode(this.refs.usageRightSelection).value,
      copyright: this.state.showTextBox
        ? (x = ReactDOM.findDOMNode(this.refs.copyright)) && x.value
        : undefined,
      cc_license: this.state.showCreativeCommonsOptions
        ? (x = ReactDOM.findDOMNode(this.refs.creativeCommons)) && x.value
        : undefined
    }

    return omitEmptyValues(obj)
  }

  getUsageRightsOptions() {
    return $.get(this.apiUrl(), data => {
      this.setState({
        licenseOptions: data
      })
    })
  }

  handleChange(event) {
    this.setState({
      usageRightSelectionValue: event.target.value,
      showTextBox: event.target.value !== 'choose',
      showCreativeCommonsOptions: event.target.value === 'creative_commons',
      showMessage: this.props.showMessage && event.target.value === 'choose'
    })
  }

  // This method only really applies to firefox which doesn't handle onChange
  // events on select boxes like every other browser.
  handleChooseKeyPress(event) {
    if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
      this.setState(
        {
          usageRightSelectionValue: event.target.value
        },
        this.handleChange(event)
      )
    }
  }

  renderContentOptions() {
    return CONTENT_OPTIONS.map(contentOption => (
      <option key={contentOption.value} value={contentOption.value}>
        {contentOption.display}
      </option>
    ))
  }

  renderCreativeCommonsOptions() {
    const onlyCC = this.state.licenseOptions.filter(license => license.id.indexOf('cc') === 0)

    return onlyCC.map(license => (
      <option key={license.id} value={license.id}>
        {license.name}
      </option>
    ))
  }

  renderShowCreativeCommonsOptions() {
    const renderShowCreativeCommonsOptions = (

          {I18n.t('Creative Commons License:')}

          <select
            id="creativeCommonsSelection"
            className="UsageRightsSelectBox__creativeCommons"
            ref="creativeCommons"
            defaultValue={this.props.cc_value}
          >
            {this.renderCreativeCommonsOptions()}
          </select>

    )
    return this.state.showCreativeCommonsOptions ? renderShowCreativeCommonsOptions : null
  }

  renderShowMessage() {
    const renderShowMessage = (

            {I18n.t(
              "If you do not select usage rights now, this file will be unpublished after it's uploaded."
            )}

    )
    return this.state.showMessage ? renderShowMessage : null
  }

  render() {
    return (

            {I18n.t('Usage Right:')}

            <select
              id="usageRightSelector"
              className="UsageRightsSelectBox__select"
              onChange={e => this.handleChange(e)}
              onKeyUp={e => this.handleChooseKeyPress(e)}
              ref="usageRightSelection"
              value={this.state.usageRightSelectionValue}
            >
              {this.renderContentOptions()}
            </select>

        {this.renderShowCreativeCommonsOptions()}

            {I18n.t('Copyright Holder:')}

            <input
              id="copyrightHolder"
              type="text"
              ref="copyright"
              defaultValue={this.props.copyright}
              placeholder={I18n.t('(c) 2001 Acme Inc.')}
            />

        {this.renderShowMessage()}

    )
  }
}
<|endoftext|>


<commit_before>global.$ = global.jQuery = require('jquery');
global._ = require('lodash');
require('bootstrap');

require('pui-prismjs');

require('./scale')();
require('@npmcorp/pui-react-back-to-top/jquery-plugin');
require('@npmcorp/pui-css-drop-down-menu');
require('@npmcorp/pui-css-forms');
require('@npmcorp/pui-css-svgeople');
require('@npmcorp/pui-css-dropdowns');
//require('@npmcorp/pui-css-panels');
//require('@npmcorp/pui-css-buttons');
<commit_msg>chore(pui): Add necessary modules to styleguide<commit_after>global.$ = global.jQuery = require('jquery');
global._ = require('lodash');
require('bootstrap');

require('pui-prismjs');

require('./scale')();
require('@npmcorp/pui-react-back-to-top/jquery-plugin');
require('@npmcorp/pui-css-drop-down-menu');
require('@npmcorp/pui-css-forms');
require('@npmcorp/pui-css-svgeople');
require('@npmcorp/pui-css-dropdowns');
require('@npmcorp/pui-css-panels');
require('@npmcorp/pui-css-buttons');
<|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, DomRecycler} from 'base/utils'

import Playback from 'base/playback'
import Styler from 'base/styler'
import Browser from 'components/browser'
import Events from 'base/events'
import tagStyle from './public/style.scss'
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']
}

const KNOWN_AUDIO_MIMETYPES = Object.keys(AUDIO_MIMETYPES).reduce((acc, k) => [...acc, ...AUDIO_MIMETYPES[k]], [])

// 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 isAudioOnly() {
    const resourceUrl = this.options.src
    let mimeTypes = HTML5Video._mimeTypesForUrl(resourceUrl, AUDIO_MIMETYPES, this.options.mimeType)
    return this.options.playback && this.options.playback.audioOnly || this.options.audioOnly || KNOWN_AUDIO_MIMETYPES.indexOf(mimeTypes[0]) >= 0
  }

  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._destroyed = false
    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 || {})
    this.options.playback.disableContextMenu = this.options.playback.disableContextMenu || this.options.disableVideoTagContextMenu

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

    let posterUrl // FIXME: poster plugin should always convert poster to object with expected properties ?
    if (this.options.poster) {
      if (typeof this.options.poster === 'string') {
        posterUrl = this.options.poster
      } else if (typeof this.options.poster.url === 'string') {
        posterUrl = this.options.poster.url
      }
    }

    $.extend(this.el, {
      loop: this.options.loop,
      poster: posterUrl,
      preload: preload || 'metadata',
      controls: (playbackConfig.controls || this.options.useVideoTagDefaultControls) && 'controls',
      crossOrigin: playbackConfig.crossOrigin,
      'x-webkit-playsinline': playbackConfig.playInline
    })

    playbackConfig.playInline && (this.$el.attr({playsinline: 'playsinline'}))

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

    // https://github.com/clappr/clappr/issues/1076
    this.options.autoPlay && process.nextTick(() => !this._destroyed && this.play())
  }

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

  _onLoadedMetadata(e) {
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, {duration: e.target.duration, data: e})
    this._updateSettings()
    const 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
  }

  // On mobile device, HTML5 video element "retains" user action consent if
  // load() method is called. See Player.consent().
  consent() {
    !this.isPlaying() && this.el.load()
  }

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

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

  stop() {
    this.pause()
    this._stopped = true
    // src will be added again in play()
    this.el.removeAttribute('src')
    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() {
    const before = this._playheadMovingTimeOnCheck
    const 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() {
    const playheadShouldBeMoving = !this.el.ended && !this.el.paused
    const 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._destroyed = true
    this.$el.remove()
    this.el.src = ''
    this._src = null
    DomRecycler.garbage(this.$el)
  }

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

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

  _checkInitialSeek() {
    const seekTime = seekStringToSeconds()
    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
    }
    let buffered = []
    let bufferedPos = 0
    for (let i = 0;  i < this.el.buffered.length; i++) {
      buffered = [...buffered, {start: this.el.buffered.start(i), end: this.el.buffered.end(i)}]
      if (this.el.currentTime >= buffered[i].start && this.el.currentTime <= buffered[i].end) {
        bufferedPos = i
      }
    }
    const progress = {
      start: buffered[bufferedPos].start,
      current: buffered[bufferedPos].end,
      total: this.el.duration
    }
    this.trigger(Events.PLAYBACK_PROGRESS, progress, buffered)
  }

  _typeFor(src) {
    let mimeTypes = HTML5Video._mimeTypesForUrl(src, MIMETYPES, this.options.mimeType)
    if (mimeTypes.length == 0) {
      mimeTypes = HTML5Video._mimeTypesForUrl(src, AUDIO_MIMETYPES, this.options.mimeType)
    }
    const mimeType = mimeTypes[0] || ''
    return mimeType.split(';')[0]
  }

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

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

    if (this.options.playback.disableContextMenu) {
      this.$el.on('contextmenu', () => {
        return false
      })
    }

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

HTML5Video._mimeTypesForUrl = function(resourceUrl, mimeTypesByExtension, mimeType) {
  const extension = (resourceUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1]
  let mimeTypes = mimeType || (extension && mimeTypesByExtension[extension.toLowerCase()]) || []
  return (mimeTypes.constructor === Array) ? mimeTypes : [mimeTypes]
}

HTML5Video._canPlay = function(type, mimeTypesByExtension, resourceUrl, mimeType) {
  let mimeTypes = HTML5Video._mimeTypesForUrl(resourceUrl, mimeTypesByExtension, mimeType)
  const media = document.createElement(type)
  return !!(mimeTypes.filter(mediaType => !!media.canPlayType(mediaType).replace(/no/, ''))[0])
}

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

module.exports = HTML5Video
<commit_msg>Handle uncaught DOMException with Chrome in html5_video playback play method.<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, DomRecycler} from 'base/utils'

import Playback from 'base/playback'
import Styler from 'base/styler'
import Browser from 'components/browser'
import Events from 'base/events'
import tagStyle from './public/style.scss'
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']
}

const KNOWN_AUDIO_MIMETYPES = Object.keys(AUDIO_MIMETYPES).reduce((acc, k) => [...acc, ...AUDIO_MIMETYPES[k]], [])

// 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 isAudioOnly() {
    const resourceUrl = this.options.src
    let mimeTypes = HTML5Video._mimeTypesForUrl(resourceUrl, AUDIO_MIMETYPES, this.options.mimeType)
    return this.options.playback && this.options.playback.audioOnly || this.options.audioOnly || KNOWN_AUDIO_MIMETYPES.indexOf(mimeTypes[0]) >= 0
  }

  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._destroyed = false
    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 || {})
    this.options.playback.disableContextMenu = this.options.playback.disableContextMenu || this.options.disableVideoTagContextMenu

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

    let posterUrl // FIXME: poster plugin should always convert poster to object with expected properties ?
    if (this.options.poster) {
      if (typeof this.options.poster === 'string') {
        posterUrl = this.options.poster
      } else if (typeof this.options.poster.url === 'string') {
        posterUrl = this.options.poster.url
      }
    }

    $.extend(this.el, {
      loop: this.options.loop,
      poster: posterUrl,
      preload: preload || 'metadata',
      controls: (playbackConfig.controls || this.options.useVideoTagDefaultControls) && 'controls',
      crossOrigin: playbackConfig.crossOrigin,
      'x-webkit-playsinline': playbackConfig.playInline
    })

    playbackConfig.playInline && (this.$el.attr({playsinline: 'playsinline'}))

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

    // https://github.com/clappr/clappr/issues/1076
    this.options.autoPlay && process.nextTick(() => !this._destroyed && this.play())
  }

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

  _onLoadedMetadata(e) {
    this._handleBufferingEvents()
    this.trigger(Events.PLAYBACK_LOADEDMETADATA, {duration: e.target.duration, data: e})
    this._updateSettings()
    const 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
  }

  // On mobile device, HTML5 video element "retains" user action consent if
  // load() method is called. See Player.consent().
  consent() {
    !this.isPlaying() && this.el.load()
  }

  play() {
    this.trigger(Events.PLAYBACK_PLAY_INTENT)
    this._stopped = false
    this._setupSrc(this._src)
    this._handleBufferingEvents()
    let promise = this.el.play()
    // For more details, see https://developers.google.com/web/updates/2016/03/play-returns-promise
    if (promise && promise.catch) {
      promise.catch(() => {})
    }
  }

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

  stop() {
    this.pause()
    this._stopped = true
    // src will be added again in play()
    this.el.removeAttribute('src')
    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() {
    const before = this._playheadMovingTimeOnCheck
    const 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() {
    const playheadShouldBeMoving = !this.el.ended && !this.el.paused
    const 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._destroyed = true
    this.$el.remove()
    this.el.src = ''
    this._src = null
    DomRecycler.garbage(this.$el)
  }

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

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

  _checkInitialSeek() {
    const seekTime = seekStringToSeconds()
    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
    }
    let buffered = []
    let bufferedPos = 0
    for (let i = 0;  i < this.el.buffered.length; i++) {
      buffered = [...buffered, {start: this.el.buffered.start(i), end: this.el.buffered.end(i)}]
      if (this.el.currentTime >= buffered[i].start && this.el.currentTime <= buffered[i].end) {
        bufferedPos = i
      }
    }
    const progress = {
      start: buffered[bufferedPos].start,
      current: buffered[bufferedPos].end,
      total: this.el.duration
    }
    this.trigger(Events.PLAYBACK_PROGRESS, progress, buffered)
  }

  _typeFor(src) {
    let mimeTypes = HTML5Video._mimeTypesForUrl(src, MIMETYPES, this.options.mimeType)
    if (mimeTypes.length == 0) {
      mimeTypes = HTML5Video._mimeTypesForUrl(src, AUDIO_MIMETYPES, this.options.mimeType)
    }
    const mimeType = mimeTypes[0] || ''
    return mimeType.split(';')[0]
  }

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

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

    if (this.options.playback.disableContextMenu) {
      this.$el.on('contextmenu', () => {
        return false
      })
    }

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

HTML5Video._mimeTypesForUrl = function(resourceUrl, mimeTypesByExtension, mimeType) {
  const extension = (resourceUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1]
  let mimeTypes = mimeType || (extension && mimeTypesByExtension[extension.toLowerCase()]) || []
  return (mimeTypes.constructor === Array) ? mimeTypes : [mimeTypes]
}

HTML5Video._canPlay = function(type, mimeTypesByExtension, resourceUrl, mimeType) {
  let mimeTypes = HTML5Video._mimeTypesForUrl(resourceUrl, mimeTypesByExtension, mimeType)
  const media = document.createElement(type)
  return !!(mimeTypes.filter(mediaType => !!media.canPlayType(mediaType).replace(/no/, ''))[0])
}

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>/**
 * Created by jklingler on 4/1/2014.
 */

define(['plugin/PluginConfig',
        'plugin/PluginBase',
        'plugin/ImportFMUs/ImportFMUs/FMU',
        'plugin/ImportFMUs/ImportFMUs/resources/ModelicaBlocks'],
    function (PluginConfig, PluginBase, FmuMetaTypes, FmuImportList) {
    'use strict';

    var ImportFMUsPlugin = function () {
        // Call base class's constructor
        PluginBase.call(this);
    };

    ImportFMUsPlugin.prototype = Object.create(PluginBase.prototype);

    ImportFMUsPlugin.prototype.constructor = ImportFMUsPlugin;

    ImportFMUsPlugin.prototype.getName = function () {
        return "Import FMUs";
    };

    ImportFMUsPlugin.prototype.main = function (callback) {
        var self = this,
            core = this.core,
            rootNode = this.rootNode,
            fmuList = FmuImportList;

        // get all 'possible' object types from the MetaModel
        this.updateMETA(FmuMetaTypes);

        var flatFolderMap = {}; // key is dot-seperated path in project, value is the corresponding node

        // create an FCO within the rootNode, which is an instance of FMU.FMU_Library
        var newFmuLib = core.createNode({parent: rootNode, base: FmuMetaTypes.FMU_Library});
        // set the name attribute of the new FCO to 'NewImportedFMUs'
        var newImportsFolderName = 'NewImportedFMUs';
        core.setAttribute(newFmuLib, 'name', newImportsFolderName);

        flatFolderMap[newImportsFolderName] = newFmuLib;

        var index;
        var numberOfFmusToImport = fmuList.length;

        for (index = 0; index < numberOfFmusToImport; index += 1){
            var fmuData = fmuList[index],
                newFMU,
                modelicaClass = fmuData.ModelicaClass,
                fmuFilePath = fmuData.FMU_package,
                splitModelicaClass = modelicaClass.split('.'),
                parentPackagePath = splitModelicaClass.slice(0, -1).join('.'),  // get the parent folder path
                fmuName = splitModelicaClass.slice(-1)[0];                      // get the new FMU name

            if (splitModelicaClass.length == 0) {
                fmuName = fmuFilePath.split('\\').slice(-1)[0].split('.')[0];

                // create an FCO within the the newFmuLib, which is an instance of FMU.FMU
                newFMU = core.createNode({parent: newFmuLib, base: FmuMetaTypes.FMU});
                // set the name attribute of the new FCO to 'fmuName'
                core.setAttribute(newFMU, 'name', fmuName);

                ImportFMUsPlugin.buildFmuFromJson(core, newFMU, fmuData, FmuMetaTypes)

            } else {
                var fullPackagePathWithinProject = newImportsFolderName + '.' + parentPackagePath;
                var parentFolder = ImportFMUsPlugin.makeFolders(core, fullPackagePathWithinProject, flatFolderMap, FmuMetaTypes);

                // create an FCO within the the newFmuLib, which is an instance of FMU.FMU
                newFMU = core.createNode({parent: parentFolder, base: FmuMetaTypes.FMU});
                // set the name attribute of the new FCO to 'fmuName'
                core.setAttribute(newFMU, 'name', fmuName);

                ImportFMUsPlugin.buildFmuFromJson(core, newFMU, fmuData, FmuMetaTypes)
            }
        }

        // Commit changes to the database.
        this.save('Committing changes to database for ImportFMUs plugin', function (err) {
            // FIXME: on error?

            if (callback) {
                // TODO: we need a function to set/update success
                self.result.success = true;
                callback(null, self.result);
            }
        });
        // End Commit NOTE: You should not have any code here!!!
        // this.save(commit_msg, ______) should be the last statement
    };

    // Recursively create FmuLibrary objects
    ImportFMUsPlugin.makeFolders = function (core, modelicaPackagePath, existingFolderMap, FmuTypes) {
        var desiredFolderNode;

        if (modelicaPackagePath in existingFolderMap) {
            // the desired folder already exists; return it
            desiredFolderNode = existingFolderMap[modelicaPackagePath];
            return desiredFolderNode;

        } else {
            // the desired folder does not exist; create and return it

            // get the parent package and see if it exists (recursion)

            var parentPackagePath = modelicaPackagePath.split('.').slice(0, -1).join('.');
            var thisPackageName = modelicaPackagePath.split('.').slice(-1)[0];

            var parentFolder = ImportFMUsPlugin.makeFolders(core, parentPackagePath, existingFolderMap, FmuTypes);

            var newFmuLibNode = core.createNode({parent: parentFolder, base: FmuMetaTypes.FMU_Library});
            core.setAttribute(newFmuLibNode, 'name', thisPackageName);

            existingFolderMap[modelicaPackagePath] = newFmuLibNode;

            return newFmuLibNode;
        }
    };

    ImportFMUsPlugin.buildFmuFromJson = function (core, newFmuObject, fmuData, FmuTypes) {
        var parameters = fmuData.Parameters,
            inputs = fmuData.Inputs,
            outputs = fmuData.Outputs,
            index,
            paramX = 400,
            paramY = 100,
            inputX = 100,
            inputY = 100,
            outputX = 700,
            outputY = 100,
            offsetY = 60;

        core.setAttribute(newFmuObject, 'fmu_path', fmuData.FMU_package);

        for (index = 0; index < parameters.length; index += 1){
            var paramData = parameters[index];

            var newParamObject = core.createNode({parent: newFmuObject, base: FmuTypes.Parameter});
            core.setAttribute(newParamObject, 'name', paramData.name);

            if (paramData.description) {
                core.setAttribute(newParamObject, 'description', paramData.description);
            }

            if (paramData.startValue) {
                core.setAttribute(newParamObject, 'value', paramData.startValue);
                core.setAttribute(newParamObject, 'default_value', paramData.startValue);
            }

            // TODO: put the parameters in the middle of the canvas
            core.setRegistry(newParamObject, 'position', {x: paramX, y: paramY});
            paramY += offsetY;
        }

        for (index = 0; index < inputs.length; index += 1){
            var inputData = inputs[index];

            var newInputPortObject = core.createNode({parent: newFmuObject, base: FmuTypes.Input});
            core.setAttribute(newInputPortObject, 'name', inputData.name);

            if (inputData.description) {
                core.setAttribute(newInputPortObject, 'description', inputData.description);
            }

            // TODO: put the inputs on the left-hand side of the canvas
            core.setRegistry(newInputPortObject, 'position', {x: inputX, y: inputY});
            inputY += offsetY;
        }

        for (index = 0; index < outputs.length; index += 1){
            var outputData = outputs[index];

            var newOutputPortObject = core.createNode({parent: newFmuObject, base: FmuTypes.Input});
            core.setAttribute(newOutputPortObject, 'name', outputData.name);

            if (outputData.description) {
                core.setAttribute(newOutputPortObject, 'description', outputData.description);
            }

            // TODO: put the outputs on the righthand side of the canvas
            core.setRegistry(newOutputPortObject, 'position', {x: outputX, y: outputY});
            outputY += offsetY;
        }
    };

    return ImportFMUsPlugin;
});<commit_msg>add some logging to FMU Plugin<commit_after>/**
 * Created by jklingler on 4/1/2014.
 */

define(['plugin/PluginConfig',
        'plugin/PluginBase',
        'plugin/ImportFMUs/ImportFMUs/FMU',
        'plugin/ImportFMUs/ImportFMUs/resources/ModelicaBlocks'],
    function (PluginConfig, PluginBase, FmuMetaTypes, FmuImportList) {
    'use strict';

    var ImportFMUsPlugin = function () {
        // Call base class's constructor
        PluginBase.call(this);
    };

    ImportFMUsPlugin.prototype = Object.create(PluginBase.prototype);

    ImportFMUsPlugin.prototype.constructor = ImportFMUsPlugin;

    ImportFMUsPlugin.prototype.getName = function () {
        return "Import FMUs";
    };

    ImportFMUsPlugin.prototype.main = function (callback) {
        var self = this,
            core = this.core,
            rootNode = this.rootNode,
            fmuList = FmuImportList;

        self.logger.info('Running ImportFMUs Plugin using ');

        // get all 'possible' object types from the MetaModel
        this.updateMETA(FmuMetaTypes);

        var flatFolderMap = {}; // key is dot-seperated path in project, value is the corresponding node

        // create an FCO within the rootNode, which is an instance of FMU.FMU_Library
        var newFmuLib = core.createNode({parent: rootNode, base: FmuMetaTypes.FMU_Library});
        // set the name attribute of the new FCO to 'NewImportedFMUs'
        var newImportsFolderName = 'NewImportedFMUs';
        core.setAttribute(newFmuLib, 'name', newImportsFolderName);

        flatFolderMap[newImportsFolderName] = newFmuLib;

        var index;
        var numberOfFmusToImport = fmuList.length;

        for (index = 0; index < numberOfFmusToImport; index += 1){
            var fmuData = fmuList[index],
                newFMU,
                modelicaClass = fmuData.ModelicaClass,
                fmuFilePath = fmuData.FMU_package,
                splitModelicaClass = modelicaClass.split('.'),
                parentPackagePath = splitModelicaClass.slice(0, -1).join('.'),  // get the parent folder path
                fmuName = splitModelicaClass.slice(-1)[0];                      // get the new FMU name

            if (splitModelicaClass.length == 0) {
                fmuName = fmuFilePath.split('\\').slice(-1)[0].split('.')[0];

                // create an FCO within the the newFmuLib, which is an instance of FMU.FMU
                newFMU = core.createNode({parent: newFmuLib, base: FmuMetaTypes.FMU});
                // set the name attribute of the new FCO to 'fmuName'
                core.setAttribute(newFMU, 'name', fmuName);

                ImportFMUsPlugin.buildFmuFromJson(core, newFMU, fmuData, FmuMetaTypes)

            } else {
                var fullPackagePathWithinProject = newImportsFolderName + '.' + parentPackagePath;
                var parentFolder = ImportFMUsPlugin.makeFolders(core, fullPackagePathWithinProject, flatFolderMap, FmuMetaTypes);

                // create an FCO within the the newFmuLib, which is an instance of FMU.FMU
                newFMU = core.createNode({parent: parentFolder, base: FmuMetaTypes.FMU});
                // set the name attribute of the new FCO to 'fmuName'
                core.setAttribute(newFMU, 'name', fmuName);

                ImportFMUsPlugin.buildFmuFromJson(core, newFMU, fmuData, FmuMetaTypes)
            }
        }

        // Commit changes to the database.
        this.save('Committing changes to database for ImportFMUs plugin', function (err) {
            // FIXME: on error?

            if (callback) {
                // TODO: we need a function to set/update success
                self.result.success = true;
                callback(null, self.result);
            }
        });
        // End Commit NOTE: You should not have any code here!!!
        // this.save(commit_msg, ______) should be the last statement
    };

    // Recursively create FmuLibrary objects
    ImportFMUsPlugin.makeFolders = function (core, modelicaPackagePath, existingFolderMap, FmuTypes) {
        var desiredFolderNode;

        if (modelicaPackagePath in existingFolderMap) {
            // the desired folder already exists; return it
            desiredFolderNode = existingFolderMap[modelicaPackagePath];
            return desiredFolderNode;

        } else {
            // the desired folder does not exist; create and return it

            // get the parent package and see if it exists (recursion)

            var parentPackagePath = modelicaPackagePath.split('.').slice(0, -1).join('.');
            var thisPackageName = modelicaPackagePath.split('.').slice(-1)[0];

            var parentFolder = ImportFMUsPlugin.makeFolders(core, parentPackagePath, existingFolderMap, FmuTypes);

            var newFmuLibNode = core.createNode({parent: parentFolder, base: FmuMetaTypes.FMU_Library});
            core.setAttribute(newFmuLibNode, 'name', thisPackageName);

            existingFolderMap[modelicaPackagePath] = newFmuLibNode;

            return newFmuLibNode;
        }
    };

    ImportFMUsPlugin.buildFmuFromJson = function (core, newFmuObject, fmuData, FmuTypes) {
        var parameters = fmuData.Parameters,
            inputs = fmuData.Inputs,
            outputs = fmuData.Outputs,
            index,
            paramX = 400,
            paramY = 100,
            inputX = 100,
            inputY = 100,
            outputX = 700,
            outputY = 100,
            offsetY = 60;

        core.setAttribute(newFmuObject, 'fmu_path', fmuData.FMU_package);

        for (index = 0; index < parameters.length; index += 1){
            var paramData = parameters[index];

            var newParamObject = core.createNode({parent: newFmuObject, base: FmuTypes.Parameter});
            core.setAttribute(newParamObject, 'name', paramData.name);

            if (paramData.description) {
                core.setAttribute(newParamObject, 'description', paramData.description);
            }

            if (paramData.startValue) {
                core.setAttribute(newParamObject, 'value', paramData.startValue);
                core.setAttribute(newParamObject, 'default_value', paramData.startValue);
            }

            // TODO: put the parameters in the middle of the canvas
            core.setRegistry(newParamObject, 'position', {x: paramX, y: paramY});
            paramY += offsetY;
        }

        for (index = 0; index < inputs.length; index += 1){
            var inputData = inputs[index];

            var newInputPortObject = core.createNode({parent: newFmuObject, base: FmuTypes.Input});
            core.setAttribute(newInputPortObject, 'name', inputData.name);

            if (inputData.description) {
                core.setAttribute(newInputPortObject, 'description', inputData.description);
            }

            // TODO: put the inputs on the left-hand side of the canvas
            core.setRegistry(newInputPortObject, 'position', {x: inputX, y: inputY});
            inputY += offsetY;
        }

        for (index = 0; index < outputs.length; index += 1){
            var outputData = outputs[index];

            var newOutputPortObject = core.createNode({parent: newFmuObject, base: FmuTypes.Input});
            core.setAttribute(newOutputPortObject, 'name', outputData.name);

            if (outputData.description) {
                core.setAttribute(newOutputPortObject, 'description', outputData.description);
            }

            // TODO: put the outputs on the righthand side of the canvas
            core.setRegistry(newOutputPortObject, 'position', {x: outputX, y: outputY});
            outputY += offsetY;
        }
    };

    return ImportFMUsPlugin;
});<|endoftext|>


<commit_before>var pull = require('pull-stream')
var defer = require('pull-defer')
var { Value, onceTrue, watch, Set: MutantSet } = require('mutant')
var ref = require('ssb-ref')
var Reconnect = require('pull-reconnect')
var createClient = require('ssb-client')
var createFeed = require('ssb-feed')
var nest = require('depnest')
var ssbKeys = require('ssb-keys')
var flat = require('flat')

exports.needs = nest({
  'config.sync.load': 'first',
  'keys.sync.load': 'first',
  'sbot.obs.connectionStatus': 'first',
  'sbot.hook.publish': 'map'
})

exports.gives = {
  sbot: {
    sync: {
      cache: true
    },
    async: {
      get: true,
      publish: true,
      addBlob: true,
      gossipConnect: true,
      friendsGet: true
    },
    pull: {
      log: true,
      userFeed: true,
      messagesByType: true,
      feed: true,
      links: true,
      backlinks: true,
      stream: true
    },
    obs: {
      connectionStatus: true,
      connection: true,
      connectedPeers: true,
      localPeers: true
    }
  }
}

exports.create = function (api) {
  const config = api.config.sync.load()
  const keys = api.keys.sync.load()
  var cache = {}

  var sbot = null
  var connection = Value()
  var connectionStatus = Value()
  var connectedPeers = MutantSet()
  var localPeers = MutantSet()

  var rec = Reconnect(function (isConn) {
    function notify (value) {
      isConn(value); connectionStatus.set(value)
    }

    var opts = {
      path: config.path,
      remote: config.remote,
      host: config.host,
      port: config.port,
      key: config.key,
      appKey: config.caps.shs,
      timers: config.timers
    }

    createClient(keys, opts, function (err, _sbot) {
      if (err) {
        return notify(err)
      }

      sbot = _sbot
      sbot.on('closed', function () {
        sbot = null
        connection.set(null)
        notify(new Error('closed'))
      })

      connection.set(sbot)
      notify()
    })
  })

  var internal = {
    getLatest: rec.async(function (id, cb) {
      sbot.getLatest(id, cb)
    }),
    add: rec.async(function (msg, cb) {
      sbot.add(msg, cb)
    })
  }

  watch(connection, (sbot) => {
    if (sbot) {
      sbot.gossip.peers((err, peers) => {
        if (err) return console.error(err)
        connectedPeers.set(peers.filter(x => x.state === 'connected').map(x => x.key))
        localPeers.set(peers.filter(x => x.source === 'local').map(x => x.key))
      })
      pull(
        sbot.gossip.changes(),
        pull.drain(data => {
          if (data.peer) {
            if (data.type === 'remove') {
              connectedPeers.delete(data.peer.key)
              localPeers.delete(data.peer.key)
            } else {
              if (data.peer.source === 'local') {
                localPeers.add(data.peer.key)
              }
              if (data.peer.state === 'connected') {
                connectedPeers.add(data.peer.key)
              } else {
                connectedPeers.delete(data.peer.key)
              }
            }
          }
        })
      )
    }
  })

  var feed = createFeed(internal, keys, {remote: true})

  return {
    sbot: {
      sync: {
        cache: () => cache
      },
      async: {
        get: rec.async(function (key, cb) {
          if (typeof cb !== 'function') {
            throw new Error('cb must be function')
          }
          if (cache[key]) cb(null, cache[key])
          else {
            sbot.get(key, function (err, value) {
              if (err) return cb(err)
              runHooks({key, value})
              cb(null, value)
            })
          }
        }),
        publish: rec.async((content, cb) => {
          if (content.recps) {
            content = ssbKeys.box(content, content.recps.map(e => {
              return ref.isFeed(e) ? e : e.link
            }))
          } else {
            var flatContent = flat(content)
            Object.keys(flatContent).forEach(key => {
              var val = flatContent[key]
              if (ref.isBlob(val)) {
                sbot.blobs.push(val, err => {
                  if (err) console.error(err)
                })
              }
            })
          }

          if (sbot) {
            // instant updating of interface (just incase sbot is busy)
            runHooks({
              publishing: true,
              timestamp: Date.now(),
              value: {
                timestamp: Date.now(),
                author: keys.id,
                content
              }
            })
          }

          feed.add(content, (err, msg) => {
            if (err) console.error(err)
            else if (!cb) console.log(msg)
            cb && cb(err, msg)
          })
        }),
        addBlob: rec.async((stream, cb) => {
          return pull(
            stream,
            sbot.blobs.add(cb)
          )
        }),
        gossipConnect: rec.async(function (opts, cb) {
          sbot.gossip.connect(opts, cb)
        }),
        friendsGet: rec.async(function (opts, cb) {
          sbot.friends.get(opts, cb)
        })
      },
      pull: {
        backlinks: rec.source(query => {
          return sbot.backlinks.read(query)
        }),
        userFeed: rec.source(opts => {
          return sbot.createUserStream(opts)
        }),
        messagesByType: rec.source(opts => {
          return sbot.messagesByType(opts)
        }),
        feed: rec.source(function (opts) {
          return pull(
            sbot.createFeedStream(opts),
            pull.through(runHooks)
          )
        }),
        log: rec.source(opts => {
          return pull(
            sbot.createLogStream(opts),
            pull.through(runHooks)
          )
        }),
        links: rec.source(function (query) {
          return sbot.links(query)
        }),
        stream: function (fn) {
          var stream = defer.source()
          onceTrue(connection, function (connection) {
            stream.resolve(fn(connection))
          })
          return stream
        }
      },
      obs: {
        connectionStatus: (listener) => connectionStatus(listener),
        connection,
        connectedPeers: () => connectedPeers,
        localPeers: () => localPeers
      }
    }
  }

  // scoped

  function runHooks (msg) {
    if (msg.publishing) {
      api.sbot.hook.publish(msg)
    } else if (!cache[msg.key]) {
      // cache[msg.key] = msg.value
      // api.sbot.hook.feed(msg)
    }
  }
}
<commit_msg>remove from local peers list on disconnect<commit_after>var pull = require('pull-stream')
var defer = require('pull-defer')
var { Value, onceTrue, watch, Set: MutantSet } = require('mutant')
var ref = require('ssb-ref')
var Reconnect = require('pull-reconnect')
var createClient = require('ssb-client')
var createFeed = require('ssb-feed')
var nest = require('depnest')
var ssbKeys = require('ssb-keys')
var flat = require('flat')

exports.needs = nest({
  'config.sync.load': 'first',
  'keys.sync.load': 'first',
  'sbot.obs.connectionStatus': 'first',
  'sbot.hook.publish': 'map'
})

exports.gives = {
  sbot: {
    sync: {
      cache: true
    },
    async: {
      get: true,
      publish: true,
      addBlob: true,
      gossipConnect: true,
      friendsGet: true
    },
    pull: {
      log: true,
      userFeed: true,
      messagesByType: true,
      feed: true,
      links: true,
      backlinks: true,
      stream: true
    },
    obs: {
      connectionStatus: true,
      connection: true,
      connectedPeers: true,
      localPeers: true
    }
  }
}

exports.create = function (api) {
  const config = api.config.sync.load()
  const keys = api.keys.sync.load()
  var cache = {}

  var sbot = null
  var connection = Value()
  var connectionStatus = Value()
  var connectedPeers = MutantSet()
  var localPeers = MutantSet()

  var rec = Reconnect(function (isConn) {
    function notify (value) {
      isConn(value); connectionStatus.set(value)
    }

    var opts = {
      path: config.path,
      remote: config.remote,
      host: config.host,
      port: config.port,
      key: config.key,
      appKey: config.caps.shs,
      timers: config.timers
    }

    createClient(keys, opts, function (err, _sbot) {
      if (err) {
        return notify(err)
      }

      sbot = _sbot
      sbot.on('closed', function () {
        sbot = null
        connection.set(null)
        notify(new Error('closed'))
      })

      connection.set(sbot)
      notify()
    })
  })

  var internal = {
    getLatest: rec.async(function (id, cb) {
      sbot.getLatest(id, cb)
    }),
    add: rec.async(function (msg, cb) {
      sbot.add(msg, cb)
    })
  }

  watch(connection, (sbot) => {
    if (sbot) {
      sbot.gossip.peers((err, peers) => {
        if (err) return console.error(err)
        connectedPeers.set(peers.filter(x => x.state === 'connected').map(x => x.key))
        localPeers.set(peers.filter(x => x.source === 'local').map(x => x.key))
      })
      pull(
        sbot.gossip.changes(),
        pull.drain(data => {
          if (data.peer) {
            if (data.type === 'remove' || data.type === 'disconnect') {
              connectedPeers.delete(data.peer.key)
              localPeers.delete(data.peer.key)
            } else {
              if (data.peer.source === 'local') {
                localPeers.add(data.peer.key)
              }
              if (data.peer.state === 'connected') {
                connectedPeers.add(data.peer.key)
              } else {
                connectedPeers.delete(data.peer.key)
              }
            }
          }
        })
      )
    }
  })

  var feed = createFeed(internal, keys, {remote: true})

  return {
    sbot: {
      sync: {
        cache: () => cache
      },
      async: {
        get: rec.async(function (key, cb) {
          if (typeof cb !== 'function') {
            throw new Error('cb must be function')
          }
          if (cache[key]) cb(null, cache[key])
          else {
            sbot.get(key, function (err, value) {
              if (err) return cb(err)
              runHooks({key, value})
              cb(null, value)
            })
          }
        }),
        publish: rec.async((content, cb) => {
          if (content.recps) {
            content = ssbKeys.box(content, content.recps.map(e => {
              return ref.isFeed(e) ? e : e.link
            }))
          } else {
            var flatContent = flat(content)
            Object.keys(flatContent).forEach(key => {
              var val = flatContent[key]
              if (ref.isBlob(val)) {
                sbot.blobs.push(val, err => {
                  if (err) console.error(err)
                })
              }
            })
          }

          if (sbot) {
            // instant updating of interface (just incase sbot is busy)
            runHooks({
              publishing: true,
              timestamp: Date.now(),
              value: {
                timestamp: Date.now(),
                author: keys.id,
                content
              }
            })
          }

          feed.add(content, (err, msg) => {
            if (err) console.error(err)
            else if (!cb) console.log(msg)
            cb && cb(err, msg)
          })
        }),
        addBlob: rec.async((stream, cb) => {
          return pull(
            stream,
            sbot.blobs.add(cb)
          )
        }),
        gossipConnect: rec.async(function (opts, cb) {
          sbot.gossip.connect(opts, cb)
        }),
        friendsGet: rec.async(function (opts, cb) {
          sbot.friends.get(opts, cb)
        })
      },
      pull: {
        backlinks: rec.source(query => {
          return sbot.backlinks.read(query)
        }),
        userFeed: rec.source(opts => {
          return sbot.createUserStream(opts)
        }),
        messagesByType: rec.source(opts => {
          return sbot.messagesByType(opts)
        }),
        feed: rec.source(function (opts) {
          return pull(
            sbot.createFeedStream(opts),
            pull.through(runHooks)
          )
        }),
        log: rec.source(opts => {
          return pull(
            sbot.createLogStream(opts),
            pull.through(runHooks)
          )
        }),
        links: rec.source(function (query) {
          return sbot.links(query)
        }),
        stream: function (fn) {
          var stream = defer.source()
          onceTrue(connection, function (connection) {
            stream.resolve(fn(connection))
          })
          return stream
        }
      },
      obs: {
        connectionStatus: (listener) => connectionStatus(listener),
        connection,
        connectedPeers: () => connectedPeers,
        localPeers: () => localPeers
      }
    }
  }

  // scoped

  function runHooks (msg) {
    if (msg.publishing) {
      api.sbot.hook.publish(msg)
    } else if (!cache[msg.key]) {
      // cache[msg.key] = msg.value
      // api.sbot.hook.feed(msg)
    }
  }
}
<|endoftext|>


<commit_before>import { Map as ImmutableMap } from 'immutable';

import React from 'react';
import { connect } from 'react-redux';

import PageTitle from '../../../../shared/js/components/gironde.fr/PageTitle';

import TotalAppetizer from '../TotalAppetizer';
import Appetizer from '../Appetizer';

import {flattenTree} from '../../../../shared/js/finance/visitHierarchical.js';
import {m52ToAggregated, hierarchicalAggregated}  from '../../../../shared/js/finance/memoized';

import { SOLIDARITES, INVEST, PRESENCE } from '../../constants/pages';
import { EXPENDITURES } from '../../../../shared/js/finance/constants';

export function Home({
    expenditures,
    currentYear,
    urls: {
        explore,
        solidarity, invest, presence
    }
}) {

    return React.createElement('article', {className: 'home'},
        React.createElement('div', {},
            React.createElement(PageTitle, {text: "Un budget au service d'une solidarité humaine et territoriale"}),
            React.createElement('p', {}, `Collèges, transport scolaire, insertion, aides aux personnes âgées, équipement des zones rurales, environnement Les domaines d’intervention du Département sont vastes mais respectent tous un même objectif : assurer la mission d’aide sociale et de solidarité pour accompagner au mieux les Girondins et les territoires. A ces compétences obligatoires s’ajoutent des actions volontaristes dans de nombreux domaines. Le Département intervient au quotidien pour répondre à une demande de solidarité et de services publics grandissante.`)
        ),

        React.createElement('section', {className: 'appetizers-container'},
            React.createElement('div', {className: 'appetizers'},

                React.createElement(TotalAppetizer, {
                    total: expenditures, // (May 29th) different than what was hardcoded (1.616*Math.pow(10, 9))
                    year: currentYear,
                    exploreUrl: explore
                }),
                React.createElement(Appetizer, {
                    h1: "Solidarités",
                    numberMain: "120 000",
                    numberSecundary: "prestations allouées",
                    description: `Le Département affirme sa vocation sociale et déploie près de 845 millions d’euros pour aider et accompagner les personnes fragilisées.
    Il emploie 1 751 agents au service de l’action sociale soit près de 75 millions par an en frais de personnel pour assurer l’efficience et la proximité du service rendus aux publics les plus fragiles. A cela s’ajoute 800 assistants familiaux (et 35 hors Gironde) qui accueillent des enfants faisant l’objet de mesures de placement.`,
                    moreUrl: solidarity
                }),
                React.createElement(Appetizer, {
                    h1: "Investissements",
                    numberMain: "1 milliard",
                    numberSecundary: "à l’horizon 2020",
                    description: `Avec une moyenne de 200 millions d’euros investis chaque année durant la mandature, le Département adopte une stratégie volontariste dans une période de réduction budgétaire majeure.`,
                    moreUrl: invest
                }),
                React.createElement(Appetizer, {
                    h1: "Présence sur le territoire",
                    numberMain: "125 métiers",
                    numberSecundary: "425 sites",
                    description: `Puéricultrice, travailleur social, agent d’exploitation et de voirie, manager, chargé de mission… 6000 agents occupant 125 métiers différents mènent leur mission dans tout le territoire de la Gironde. Il compte 425 lieux de travail et d’accueil du public. Malgré une croissance démographique constante (+ 15 000 nouveaux Girondins en moyenne chaque année) qui entraîne une augmentent des besoins, le Département accorde une vigilance particulière au maintien de ses frais de personnel et de fonctionnement.`,
                    moreUrl: presence
                })
            )
        )
    );
}

export default connect(
    state => {
        const { m52InstructionByYear, currentYear } = state;
        const m52Instruction = m52InstructionByYear.get(currentYear);

        const aggregated = m52Instruction && m52ToAggregated(m52Instruction);
        const hierAgg = m52Instruction && hierarchicalAggregated(aggregated);

        let elementById = new ImmutableMap();

        if(m52Instruction){
            flattenTree(hierAgg).forEach(aggHierNode => {
                elementById = elementById.set(aggHierNode.id, aggHierNode);
            });
        }

        const totalById = elementById.map(e => e.total);

        return {
            currentYear,
            urls: {
                explore: '#!/explorer',
                solidarity: '#!/focus/'+SOLIDARITES,
                invest: '#!/focus/'+INVEST,
                presence: '#!/focus/'+PRESENCE
            },
            expenditures: totalById.get(EXPENDITURES)
        }

    },
    () => ({})
)(Home);
<commit_msg>CORRECTION TYPO<commit_after>import { Map as ImmutableMap } from 'immutable';

import React from 'react';
import { connect } from 'react-redux';

import PageTitle from '../../../../shared/js/components/gironde.fr/PageTitle';

import TotalAppetizer from '../TotalAppetizer';
import Appetizer from '../Appetizer';

import {flattenTree} from '../../../../shared/js/finance/visitHierarchical.js';
import {m52ToAggregated, hierarchicalAggregated}  from '../../../../shared/js/finance/memoized';

import { SOLIDARITES, INVEST, PRESENCE } from '../../constants/pages';
import { EXPENDITURES } from '../../../../shared/js/finance/constants';

export function Home({
    expenditures,
    currentYear,
    urls: {
        explore,
        solidarity, invest, presence
    }
}) {

    return React.createElement('article', {className: 'home'},
        React.createElement('div', {},
            React.createElement(PageTitle, {text: "Un budget au service d'une solidarité humaine et territoriale"}),
            React.createElement('p', {}, `Collèges, transport scolaire, insertion, aides aux personnes âgées, équipement des zones rurales, environnement, les domaines d’intervention du Département sont vastes mais respectent tous un même objectif : assurer la mission d’aide sociale et de solidarité pour accompagner au mieux les Girondins et les territoires. À ces compétences obligatoires s’ajoutent des actions volontaristes dans de nombreux domaines. Le Département intervient au quotidien pour répondre à une demande de solidarité et de services publics grandissante.`)
        ),

        React.createElement('section', {className: 'appetizers-container'},
            React.createElement('div', {className: 'appetizers'},

                React.createElement(TotalAppetizer, {
                    total: expenditures, // (May 29th) different than what was hardcoded (1.616*Math.pow(10, 9))
                    year: currentYear,
                    exploreUrl: explore
                }),
                React.createElement(Appetizer, {
                    h1: "Solidarités",
                    numberMain: "120 000",
                    numberSecundary: "prestations allouées",
                    description: `Le Département affirme sa vocation sociale et déploie près de 845 millions d’euros pour aider et accompagner les personnes fragilisées.
    Il emploie 1 751 agents au service de l’action sociale soit près de 75 millions par an en frais de personnel pour assurer l’efficience et la proximité du service rendus aux publics les plus fragiles. A cela s’ajoute 800 assistants familiaux (et 35 hors Gironde) qui accueillent des enfants faisant l’objet de mesures de placement.`,
                    moreUrl: solidarity
                }),
                React.createElement(Appetizer, {
                    h1: "Investissements",
                    numberMain: "1 milliard",
                    numberSecundary: "à l’horizon 2020",
                    description: `Avec une moyenne de 200 millions d’euros investis chaque année durant la mandature, le Département adopte une stratégie volontariste dans une période de réduction budgétaire majeure.`,
                    moreUrl: invest
                }),
                React.createElement(Appetizer, {
                    h1: "Présence sur le territoire",
                    numberMain: "125 métiers",
                    numberSecundary: "425 sites",
                    description: `Puéricultrice, travailleur social, agent d’exploitation et de voirie, manager, chargé de mission… 6000 agents occupant 125 métiers différents mènent leur mission dans tout le territoire de la Gironde. Il compte 425 lieux de travail et d’accueil du public. Malgré une croissance démographique constante (+ 15 000 nouveaux Girondins en moyenne chaque année) qui entraîne une augmentent des besoins, le Département accorde une vigilance particulière au maintien de ses frais de personnel et de fonctionnement.`,
                    moreUrl: presence
                })
            )
        )
    );
}

export default connect(
    state => {
        const { m52InstructionByYear, currentYear } = state;
        const m52Instruction = m52InstructionByYear.get(currentYear);

        const aggregated = m52Instruction && m52ToAggregated(m52Instruction);
        const hierAgg = m52Instruction && hierarchicalAggregated(aggregated);

        let elementById = new ImmutableMap();

        if(m52Instruction){
            flattenTree(hierAgg).forEach(aggHierNode => {
                elementById = elementById.set(aggHierNode.id, aggHierNode);
            });
        }

        const totalById = elementById.map(e => e.total);

        return {
            currentYear,
            urls: {
                explore: '#!/explorer',
                solidarity: '#!/focus/'+SOLIDARITES,
                invest: '#!/focus/'+INVEST,
                presence: '#!/focus/'+PRESENCE
            },
            expenditures: totalById.get(EXPENDITURES)
        }

    },
    () => ({})
)(Home);
<|endoftext|>


<commit_before>//p5.play

var wallTop, wallBottom, wallLeft, wallRight, player;
var WALL_THICKNESS = 30;
//var playerImg, backgroundImg;

// player variables
var playerInitialX = 340;
var playerInitialY = 260;
var playerInitialDirection = 270;

var playerX = playerInitialX;
var playerY = playerInitialY;
var playerDirection = playerInitialDirection;

// target variables
var targetX = 220;
var targetY = 60;

function preload(){

	playerLeft = loadImage("/assets/pokeballs/pokeball-left.png");

	playerRight = loadImage("/assets/pokeballs/pokeball-right.png");

	playerTop = loadImage("/assets/pokeballs/pokeball-top.png");

	playerBottom = loadImage("/assets/pokeballs/pokeball-bottom.png");

	shipImg = loadImage("/assets/objects/shipwreck.png")

	targetImg = loadImage("/assets/pokemons/gengar.png");

	backgroundImg = loadImage('/assets/background/bg8.png'); //carrega imagem de fundo
}

function setup() {
	var canvasp5 = createCanvas(400, 400);

	canvasp5.parent('sketch-holder');

	//deixa o jogo mais devagar
	frameRate(1);

	//paredes
	wallTop = createSprite(width/2, -WALL_THICKNESS/2, width+WALL_THICKNESS*2, WALL_THICKNESS);
	wallTop.immovable = true;

	wallBottom = createSprite(width/2, height+WALL_THICKNESS/2, width+WALL_THICKNESS*2, WALL_THICKNESS);
	wallBottom.immovable = true;

	wallLeft = createSprite(-WALL_THICKNESS/2, height/2, WALL_THICKNESS, height);
	wallLeft.immovable = true;

	wallRight = createSprite(width+WALL_THICKNESS/2, height/2, WALL_THICKNESS, height);
	wallRight.immovable = true;

	//criando objetos na tela
	//primeiro objeto
	object1 = createSprite(190, 255, 10, 10);
	object1.addImage("ship", shipImg);
	object1.immovable = true;

	//Criando player
	player = createSprite(playerX, playerY, 40 ,40);
	player.addAnimation("bottom", playerBottom);
	/*player.addAnimation("top", playerTop);
	player.addAnimation("bottom", playerBottom);*/

	//Criando alvo
	target = createSprite(targetX, targetY, 40, 40);
	target.addImage("pokemon", targetImg);
}

function draw() {

	background(backgroundImg);

	player.addAnimation("right", playerRight);

	target.changeAnimation("pokemon");

	player.collide(object1);

	// immovable não esta funcionando
	player.collide(wallTop);
	player.collide(wallBottom);
	player.collide(wallRight);
	player.collide(wallLeft);

	drawSprites();
}

//avanca uma casa no jogo
function setNewPosition() {

	//soma ou subtrai 40px da posicao atual do jogador
	//somente altera se a nova posicao estiver dentro dos limites do jogo
	switch (playerDirection){
		case 0:
			if(player.position.x - 40 >= 0){
				playerX = player.position.x - 40;
			}
		break;
		case 90:
			if(player.position.y - 40 >= 0) {
				playerY = player.position.y - 40;
			}
		break;
		case 180:
			if(player.position.x + 40 <= 400){
				playerX = player.position.x + 40;
			}
		break;
		case 270:
			if(player.position.y + 40 <= 400){
				playerY = player.position.y + 40;
			}
		break;
	}

	//console.log(playerX + '/'+ playerY);

	setAnimation();

	checkChallenge();
}

//verifica se o player esta na mesma posicao do target
function checkChallenge() {

	if(playerX == targetX && playerY == targetY){
		target.remove();
	}
}

//implementado dentro do bloco WHILE
function checkChallengeBlock() {
	var result = false;
	if(playerX == targetX && playerY == targetY){
		result = false;
	}else{
		result = true;
	}
	return result;
}

//verifica se o player esta na mesma posicao do target
function checkAnswer() {

	if(playerX == targetX && playerY == targetY){
		correctAnswer();
	} else {
		wrongAnswer();
	}
}

//gira o player para a direita
function setDirectionRIGHT() {

	if(playerDirection + 90 <= 270){
		playerDirection += 90;
	} else{
		playerDirection = 0;
	}
	setAnimation();
}

//gira o player para a esquerda
function setDirectionLEFT() {

	if(playerDirection - 90 >= 0){
		playerDirection -= 90;
	} else {
		playerDirection = 270;
	}
	setAnimation();
}

//altera animacao conforme a rotação do player
function setAnimation(){

	player.remove();

	switch (playerDirection){
		case 0:
			player = createSprite(playerX, playerY, 100 ,100);
			player.addAnimation("left", playerLeft);
		break;
		case 90:
			player = createSprite(playerX, playerY, 100 ,100);
			player.addAnimation("top", playerTop);
		break;
		case 180:
			player = createSprite(playerX, playerY, 100 ,100);
			player.addAnimation("right", playerRight);
		break;
		case 270:
			player = createSprite(playerX, playerY, 100 ,100);
			player.addAnimation("bottom", playerBottom);
		break;
	}
}

//reinica o jogo colocando o player na posição inicial
function resetGame() {
	player.remove();

	playerX = playerInitialX;
	playerY = playerInitialY;

	playerDirection = playerInitialDirection;

	//desenha o player novamente
	player = createSprite(playerX, playerY, 100 ,100);
	player.addAnimation("bottom", playerBottom);

	target.remove();

	//desenha o alvo
	target = createSprite(targetX, targetY, 100, 100);
	target.addImage("pokemon",targetImg);
}
<commit_msg>added new objetcs to challenge 8<commit_after>//p5.play

var wallTop, wallBottom, wallLeft, wallRight, player;
var WALL_THICKNESS = 30;
//var playerImg, backgroundImg;

// player variables
var playerInitialX = 340;
var playerInitialY = 260;
var playerInitialDirection = 270;

var playerX = playerInitialX;
var playerY = playerInitialY;
var playerDirection = playerInitialDirection;

// target variables
var targetX = 220;
var targetY = 60;

function preload(){

	playerLeft = loadImage("/assets/pokeballs/pokeball-left.png");

	playerRight = loadImage("/assets/pokeballs/pokeball-right.png");

	playerTop = loadImage("/assets/pokeballs/pokeball-top.png");

	playerBottom = loadImage("/assets/pokeballs/pokeball-bottom.png");

	shipImg = loadImage("/assets/objects/shipwreck.png")

	targetImg = loadImage("/assets/pokemons/gengar.png");

	backgroundImg = loadImage('/assets/background/bg8.png'); //carrega imagem de fundo
}

function setup() {
	var canvasp5 = createCanvas(400, 400);

	canvasp5.parent('sketch-holder');

	//deixa o jogo mais devagar
	frameRate(1);

	//paredes
	wallTop = createSprite(width/2, -WALL_THICKNESS/2, width+WALL_THICKNESS*2, WALL_THICKNESS);
	wallTop.immovable = true;

	wallBottom = createSprite(width/2, height+WALL_THICKNESS/2, width+WALL_THICKNESS*2, WALL_THICKNESS);
	wallBottom.immovable = true;

	wallLeft = createSprite(-WALL_THICKNESS/2, height/2, WALL_THICKNESS, height);
	wallLeft.immovable = true;

	wallRight = createSprite(width+WALL_THICKNESS/2, height/2, WALL_THICKNESS, height);
	wallRight.immovable = true;

	//criando objetos na tela
	//primeiro objeto
	object1 = createSprite(190, 255, 10, 10);
	object1.addImage("ship", shipImg);
	object1.immovable = true;

	//segundo objeto
	object2 = createSprite(320, 190, 145, 65);
	object2.immovable = true;

	//terceiro objeto
	object3 = createSprite(140, 120, 105, 65);
	object3.immovable = true;

	//Criando player
	player = createSprite(playerX, playerY, 40 ,40);
	player.addAnimation("bottom", playerBottom);
	/*player.addAnimation("top", playerTop);
	player.addAnimation("bottom", playerBottom);*/

	//Criando alvo
	target = createSprite(targetX, targetY, 40, 40);
	target.addImage("pokemon", targetImg);
}

function draw() {

	background(backgroundImg);

	player.addAnimation("right", playerRight);

	target.changeAnimation("pokemon");

	//desenha os objetos transparentes
	object2.draw = function(){}
	object3.draw = function(){}

	player.collide(object1);
	player.collide(object2);
	player.collide(object3);

	// immovable não esta funcionando
	player.collide(wallTop);
	player.collide(wallBottom);
	player.collide(wallRight);
	player.collide(wallLeft);

	drawSprites();
}

//avanca uma casa no jogo
function setNewPosition() {

	//soma ou subtrai 40px da posicao atual do jogador
	//somente altera se a nova posicao estiver dentro dos limites do jogo
	switch (playerDirection){
		case 0:
			if(player.position.x - 40 >= 0){
				playerX = player.position.x - 40;
			}
		break;
		case 90:
			if(player.position.y - 40 >= 0) {
				playerY = player.position.y - 40;
			}
		break;
		case 180:
			if(player.position.x + 40 <= 400){
				playerX = player.position.x + 40;
			}
		break;
		case 270:
			if(player.position.y + 40 <= 400){
				playerY = player.position.y + 40;
			}
		break;
	}

	//console.log(playerX + '/'+ playerY);

	setAnimation();

	checkChallenge();
}

//verifica se o player esta na mesma posicao do target
function checkChallenge() {

	if(playerX == targetX && playerY == targetY){
		target.remove();
	}
}

//implementado dentro do bloco WHILE
function checkChallengeBlock() {
	var result = false;
	if(playerX == targetX && playerY == targetY){
		result = false;
	}else{
		result = true;
	}
	return result;
}

//verifica se o player esta na mesma posicao do target
function checkAnswer() {

	if(playerX == targetX && playerY == targetY){
		correctAnswer();
	} else {
		wrongAnswer();
	}
}

//gira o player para a direita
function setDirectionRIGHT() {

	if(playerDirection + 90 <= 270){
		playerDirection += 90;
	} else{
		playerDirection = 0;
	}
	setAnimation();
}

//gira o player para a esquerda
function setDirectionLEFT() {

	if(playerDirection - 90 >= 0){
		playerDirection -= 90;
	} else {
		playerDirection = 270;
	}
	setAnimation();
}

//altera animacao conforme a rotação do player
function setAnimation(){

	player.remove();

	switch (playerDirection){
		case 0:
			player = createSprite(playerX, playerY, 100 ,100);
			player.addAnimation("left", playerLeft);
		break;
		case 90:
			player = createSprite(playerX, playerY, 100 ,100);
			player.addAnimation("top", playerTop);
		break;
		case 180:
			player = createSprite(playerX, playerY, 100 ,100);
			player.addAnimation("right", playerRight);
		break;
		case 270:
			player = createSprite(playerX, playerY, 100 ,100);
			player.addAnimation("bottom", playerBottom);
		break;
	}
}

//reinica o jogo colocando o player na posição inicial
function resetGame() {
	player.remove();

	playerX = playerInitialX;
	playerY = playerInitialY;

	playerDirection = playerInitialDirection;

	//desenha o player novamente
	player = createSprite(playerX, playerY, 100 ,100);
	player.addAnimation("bottom", playerBottom);

	target.remove();

	//desenha o alvo
	target = createSprite(targetX, targetY, 100, 100);
	target.addImage("pokemon",targetImg);
}
<|endoftext|>


<commit_before>const bcrypt = require('bcrypt');
const convert = require('../../../utils/inputConverter').convert;

class AuthController {
    constructor(data) {
        this.data = data;
    }

    getRegisterForm(req, res) {
        return res.render('auth/register');
    }

    getLogInForm(req, res) {
        return res.render('auth/login');
    }

    getProfileForm(req, res) {
        return res.render('auth/profile');
    }

    getMyBookings(req, res) {
        return res.render('auth/bookings');
    }

    getReviewForm(req, res) {
        return res.render('auth/review');
    }

    getAddCarForm(req, res) {
        return res.render('auth/admin/addcar');
    }

    getEditCarForm(req, res) {
        return res.render('auth/admin/editcar');
    }

    getViewBookings(req, res) {
        return res.render('auth/admin/viewbookings');
    }

    getViewCars(req, res) {
        return res.render('auth/admin/viewcars');
    }

    getViewUsers(req, res) {
        return res.render('auth/admin/viewusers');
    }

    getViewDeals(req, res) {
        return res.render('auth/admin/viewdeals');
    }

    logOut(req, res) {
        req.logout();
        return res.redirect('/');
    }

    addCar(req, res) {
        const bodyCar = req.body;
        if (!req.file) {
            return res.status(400).send('No files were uploaded.');
        }

        const carPhotoFileName = req.file.originalname;

        return res.status(200)
            .redirect('/auth/addcar');
}

    updateProfile(req, res) {
        const bodyUser = req.body;
        const convertedUser = this._convertStrings(bodyUser);
        this.data.users.findByUsername(convertedUser.username)
            .then((dbUser) => {
                if (dbUser) {
                    convertedUser._id = dbUser._id;
                    convertedUser.username = dbUser.username;

                    if (convertedUser.password === '' ||
                        typeof convertedUser.password === 'undefined') {
                        delete convertedUser.password;
                        delete convertedUser['repeat-password'];
                        convertedUser.passHash = dbUser.passHash;
                        return Promise.resolve(convertedUser);
                    }
                    if (convertedUser.password !== convertedUser['repeat-password']) {
                        throw new Error(`Passwords do not match!`);
                    }

                    return this._generateHash(convertedUser);
                }
                throw new Error(`User ${bodyUser.username} not found!`);
            })
            .then((updatedUser) => {
                return this.data.users.updateById(updatedUser);
            })
            .then((dbUser) => {
                return res.redirect('/');
            })
            .catch((err) => {
                req.flash('error', err.message);
                return res.redirect('/auth/profile');
            });
    }

    register(req, res) {
        const bodyUser = req.body;
        const convertedUser = this._convertStrings(bodyUser);
        this.data.users.findByUsername(convertedUser.username)
            .then((dbUser) => {
                if (dbUser) {
                    throw new Error('User already exists');
                }
                return this._generateHash(convertedUser);
            })
            .then((newUser) => {
                return this.data.users.create(newUser);
            })
            .then((dbUser) => {
                return res.redirect('/auth/login');
            })
            .catch((err) => {
                req.flash('error', err.message);
                return res.redirect('/auth/register');
            });
    }

    _convertStrings(bodyUser) {
        const converted = {};
        Object.keys(bodyUser)
            .forEach((prop) => {
                converted[prop] = convert(bodyUser[prop]);
            });

        return converted;
    }

    _generateHash(bodyUser) {
        const promise = new Promise((res, rej) => {
            bcrypt.genSalt(10, (err, salt) => {
                if (err) {
                    return rej(err);
                }
                return bcrypt.hash(bodyUser.password, salt, (error, hash) => {
                    if (err) {
                        return rej(error);
                    }

                    bodyUser.passHash = hash;
                    delete bodyUser.password;
                    if (bodyUser['repeat-password']) {
                        delete bodyUser['repeat-password'];
                    }
                    return res(bodyUser);
                });
            });
        });
        return promise;
    }
}

const init = (data) => {
    return new AuthController(data);
};

module.exports = { init };
<commit_msg>added user role functionality<commit_after>const bcrypt = require('bcrypt');
const convert = require('../../../utils/inputConverter').convert;

class AuthController {
    constructor(data) {
        this.data = data;
    }

    getRegisterForm(req, res) {
        return res.render('auth/register');
    }

    getLogInForm(req, res) {
        return res.render('auth/login');
    }

    getProfileForm(req, res) {
        return res.render('auth/profile');
    }

    getMyBookings(req, res) {
        return res.render('auth/bookings');
    }

    getReviewForm(req, res) {
        return res.render('auth/review');
    }

    getAddCarForm(req, res) {
        return res.render('auth/admin/addcar');
    }

    getEditCarForm(req, res) {
        return res.render('auth/admin/editcar');
    }

    getViewBookings(req, res) {
        return res.render('auth/admin/viewbookings');
    }

    getViewCars(req, res) {
        return res.render('auth/admin/viewcars');
    }

    getViewUsers(req, res) {
        return res.render('auth/admin/viewusers');
    }

    getViewDeals(req, res) {
        return res.render('auth/admin/viewdeals');
    }

    logOut(req, res) {
        req.logout();
        return res.redirect('/');
    }

    addCar(req, res) {
        const bodyCar = req.body;
        if (!req.file) {
            return res.status(400).send('No files were uploaded.');
        }

        const carPhotoFileName = req.file.originalname;

        return res.status(200)
            .redirect('/auth/addcar');
}

    updateProfile(req, res) {
        const bodyUser = req.body;
        const convertedUser = this._convertStrings(bodyUser);
        this.data.users.findByUsername(convertedUser.username)
            .then((dbUser) => {
                if (dbUser) {
                    convertedUser._id = dbUser._id;
                    convertedUser.username = dbUser.username;

                    if (convertedUser.password === '' ||
                        typeof convertedUser.password === 'undefined') {
                        delete convertedUser.password;
                        delete convertedUser['repeat-password'];
                        convertedUser.passHash = dbUser.passHash;
                        return Promise.resolve(convertedUser);
                    }
                    if (convertedUser.password !== convertedUser['repeat-password']) {
                        throw new Error(`Passwords do not match!`);
                    }

                    return this._generateHash(convertedUser);
                }
                throw new Error(`User ${bodyUser.username} not found!`);
            })
            .then((updatedUser) => {
                return this.data.users.updateById(updatedUser);
            })
            .then((dbUser) => {
                return res.redirect('/');
            })
            .catch((err) => {
                req.flash('error', err.message);
                return res.redirect('/auth/profile');
            });
    }

    register(req, res) {
        const bodyUser = req.body;
        const convertedUser = this._convertStrings(bodyUser);
        this.data.users.findByUsername(convertedUser.username)
            .then((dbUser) => {
                if (dbUser) {
                    throw new Error('User already exists');
                }
                return this._generateHash(convertedUser);
            })
            .then((newUser) => {
                return this.data.users.create(newUser);
            })
            .then((dbUser) => {
                return res.redirect('/auth/login');
            })
            .catch((err) => {
                req.flash('error', err.message);
                return res.redirect('/auth/register');
            });
    }

    _convertStrings(bodyUser) {
        const converted = {};
        Object.keys(bodyUser)
            .forEach((prop) => {
                converted[prop] = convert(bodyUser[prop]);
            });

        converted.role = 'user';

        return converted;
    }

    _generateHash(bodyUser) {
        const promise = new Promise((res, rej) => {
            bcrypt.genSalt(10, (err, salt) => {
                if (err) {
                    return rej(err);
                }
                return bcrypt.hash(bodyUser.password, salt, (error, hash) => {
                    if (err) {
                        return rej(error);
                    }

                    bodyUser.passHash = hash;
                    delete bodyUser.password;
                    if (bodyUser['repeat-password']) {
                        delete bodyUser['repeat-password'];
                    }
                    return res(bodyUser);
                });
            });
        });
        return promise;
    }
}

const init = (data) => {
    return new AuthController(data);
};

module.exports = { init };
<|endoftext|>