<commit_before>/**
 *
 * @copyright Copyright (c) 2019, Daniel Calviño Sánchez (danxuliu@gmail.com)
 *
 * @license AGPL-3.0-or-later
 *
 * This program 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, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 EmitterMixin from '../../EmitterMixin'
import store from '../../../store/index.js'

/**
 *
 */
export default function LocalMediaModel() {

	this._superEmitterMixin()

	this.attributes = {
		localStreamRequestVideoError: null,
		localStream: null,
		audioAvailable: false,
		audioEnabled: false,
		speaking: false,
		speakingWhileMuted: false,
		currentVolume: -100,
		volumeThreshold: -100,
		videoAvailable: false,
		videoEnabled: false,
		virtualBackgroundAvailable: false,
		virtualBackgroundEnabled: false,
		localScreen: null,
		token: '',
		raisedHand: false,
	}

	this._handleLocalStreamRequestedBound = this._handleLocalStreamRequested.bind(this)
	this._handleLocalStreamBound = this._handleLocalStream.bind(this)
	this._handleLocalStreamRequestFailedRetryNoVideoBound = this._handleLocalStreamRequestFailedRetryNoVideo.bind(this)
	this._handleLocalStreamRequestFailedBound = this._handleLocalStreamRequestFailed.bind(this)
	this._handleLocalStreamChangedBound = this._handleLocalStreamChanged.bind(this)
	this._handleLocalTrackEnabledChangedBound = this._handleLocalTrackEnabledChanged.bind(this)
	this._handleLocalStreamStoppedBound = this._handleLocalStreamStopped.bind(this)
	this._handleVolumeChangeBound = this._handleVolumeChange.bind(this)
	this._handleSpeakingBound = this._handleSpeaking.bind(this)
	this._handleStoppedSpeakingBound = this._handleStoppedSpeaking.bind(this)
	this._handleSpeakingWhileMutedBound = this._handleSpeakingWhileMuted.bind(this)
	this._handleStoppedSpeakingWhileMutedBound = this._handleStoppedSpeakingWhileMuted.bind(this)
	this._handleVirtualBackgroundLoadFailedBound = this._handleVirtualBackgroundLoadFailed.bind(this)
	this._handleVirtualBackgroundOnBound = this._handleVirtualBackgroundOn.bind(this)
	this._handleVirtualBackgroundOffBound = this._handleVirtualBackgroundOff.bind(this)
	this._handleLocalScreenBound = this._handleLocalScreen.bind(this)
	this._handleLocalScreenStoppedBound = this._handleLocalScreenStopped.bind(this)

}

LocalMediaModel.prototype = {

	get(key) {
		return this.attributes[key]
	},

	set(key, value) {
		if (this.attributes[key] === value) {
			return
		}

		this.attributes[key] = value

		this._trigger('change:' + key, [value])
	},

	getWebRtc() {
		return this._webRtc
	},

	setWebRtc(webRtc) {
		if (this._webRtc && this._webRtc.webrtc) {
			this._webRtc.webrtc.off('localStreamRequested', this._handleLocalStreamRequestedBound)
			this._webRtc.webrtc.off('localStream', this._handleLocalStreamBound)
			this._webRtc.webrtc.off('localStreamRequestFailedRetryNoVideo', this._handleLocalStreamRequestFailedBound)
			this._webRtc.webrtc.off('localStreamRequestFailed', this._handleLocalStreamRequestFailedBound)
			this._webRtc.webrtc.off('localStreamChanged', this._handleLocalStreamChangedBound)
			this._webRtc.webrtc.off('localTrackEnabledChanged', this._handleLocalTrackEnabledChangedBound)
			this._webRtc.webrtc.off('localStreamStopped', this._handleLocalStreamStoppedBound)
			this._webRtc.webrtc.off('volumeChange', this._handleVolumeChangeBound)
			this._webRtc.webrtc.off('speaking', this._handleSpeakingBound)
			this._webRtc.webrtc.off('stoppedSpeaking', this._handleStoppedSpeakingBound)
			this._webRtc.webrtc.off('speakingWhileMuted', this._handleSpeakingWhileMutedBound)
			this._webRtc.webrtc.off('stoppedSpeakingWhileMuted', this._handleStoppedSpeakingWhileMutedBound)
			this._webRtc.webrtc.off('virtualBackgroundLoadFailed', this._handleVirtualBackgroundLoadFailedBound)
			this._webRtc.webrtc.off('virtualBackgroundOn', this._handleVirtualBackgroundOnBound)
			this._webRtc.webrtc.off('virtualBackgroundOff', this._handleVirtualBackgroundOffBound)
			this._webRtc.webrtc.off('localScreen', this._handleLocalScreenBound)
			this._webRtc.webrtc.off('localScreenStopped', this._handleLocalScreenStoppedBound)
		}

		this._webRtc = webRtc

		this.set('localStream', null)
		this.set('audioAvailable', false)
		this.set('audioEnabled', false)
		this.set('speaking', false)
		this.set('speakingWhileMuted', false)
		this.set('currentVolume', -100)
		this.set('volumeThreshold', -100)
		this.set('videoAvailable', false)
		this.set('videoEnabled', false)
		this.set('virtualBackgroundAvailable', this._webRtc.webrtc.isVirtualBackgroundAvailable())
		this.set('virtualBackgroundEnabled', this._webRtc.webrtc.isVirtualBackgroundEnabled())
		this.set('localScreen', null)

		this._webRtc.webrtc.on('localStreamRequested', this._handleLocalStreamRequestedBound)
		this._webRtc.webrtc.on('localStream', this._handleLocalStreamBound)
		this._webRtc.webrtc.on('localStreamRequestFailedRetryNoVideo', this._handleLocalStreamRequestFailedRetryNoVideoBound)
		this._webRtc.webrtc.on('localStreamRequestFailed', this._handleLocalStreamRequestFailedBound)
		this._webRtc.webrtc.on('localStreamChanged', this._handleLocalStreamChangedBound)
		this._webRtc.webrtc.on('localTrackEnabledChanged', this._handleLocalTrackEnabledChangedBound)
		this._webRtc.webrtc.on('localStreamStopped', this._handleLocalStreamStoppedBound)
		this._webRtc.webrtc.on('volumeChange', this._handleVolumeChangeBound)
		this._webRtc.webrtc.on('speaking', this._handleSpeakingBound)
		this._webRtc.webrtc.on('stoppedSpeaking', this._handleStoppedSpeakingBound)
		this._webRtc.webrtc.on('speakingWhileMuted', this._handleSpeakingWhileMutedBound)
		this._webRtc.webrtc.on('stoppedSpeakingWhileMuted', this._handleStoppedSpeakingWhileMutedBound)
		this._webRtc.webrtc.on('virtualBackgroundLoadFailed', this._handleVirtualBackgroundLoadFailedBound)
		this._webRtc.webrtc.on('virtualBackgroundOn', this._handleVirtualBackgroundOnBound)
		this._webRtc.webrtc.on('virtualBackgroundOff', this._handleVirtualBackgroundOffBound)
		this._webRtc.webrtc.on('localScreen', this._handleLocalScreenBound)
		this._webRtc.webrtc.on('localScreenStopped', this._handleLocalScreenStoppedBound)
	},

	_handleLocalStreamRequested(constraints, context) {
		if (context !== 'retry-no-video') {
			this.set('localStreamRequestVideoError', null)
		}
	},

	_handleLocalStream(configuration, localStream) {
		// Although there could be several local streams active at the same
		// time (if the local media is started again before stopping it
		// first) the methods to control them ("mute", "unmute",
		// "pauseVideo" and "resumeVideo") act on all the streams, it is not
		// possible to control them individually. Also all local streams
		// are transmitted when a Peer is created, but if another local
		// stream is then added it will not be automatically added to the
		// Peer. As it is not well supported and there is also no need to
		// use several local streams for now it is assumed that only one
		// local stream will be active at the same time.
		this.set('localStream', localStream)

		this.set('token', store.getters.getToken())

		this._setInitialMediaState(localStream)
	},

	_handleLocalStreamRequestFailedRetryNoVideo(constraints, error) {
		if (!error || error.name === 'NotFoundError') {
			return
		}

		this.set('localStreamRequestVideoError', error)
	},

	_handleLocalStreamRequestFailed() {
		this.set('localStream', null)

		this._setInitialMediaState(null)
	},

	_setInitialMediaState(localStream) {
		if (localStream && localStream.getAudioTracks().length > 0) {
			this.set('audioAvailable', true)
			this.set('audioEnabled', localStream.getAudioTracks()[0].enabled)
		} else {
			this.set('audioEnabled', false)
			this.set('audioAvailable', false)
		}

		if (localStream && localStream.getVideoTracks().length > 0) {
			this.set('videoAvailable', true)
			this.set('videoEnabled', localStream.getVideoTracks()[0].enabled)
		} else {
			this.set('videoEnabled', false)
			this.set('videoAvailable', false)
		}

		this.set('raisedHand', { state: false, timestamp: Date.now() })
	},

	_handleLocalStreamChanged(localStream) {
		// Only a single local stream is assumed to be active at the same time.
		this.set('localStream', localStream)

		this._updateMediaAvailability(localStream)
	},

	_updateMediaAvailability(localStream) {
		if (localStream && localStream.getAudioTracks().length > 0) {
			this.set('audioAvailable', true)
			this.set('audioEnabled', localStream.getAudioTracks()[0].enabled)
		} else {
			this.disableAudio()
			// "audioEnabled" needs to be explicitly set to false, as there is
			// no audio track and thus disabling the audio will not trigger the
			// handler for "localTrackEnabledChanged"; calling "disableAudio()"
			// just ensures that the audio will be initially disabled if it
			// becomes available again later.
			this.set('audioEnabled', false)
			this.set('audioAvailable', false)
		}

		if (localStream && localStream.getVideoTracks().length > 0) {
			this.set('videoAvailable', true)
			this.set('videoEnabled', localStream.getVideoTracks()[0].enabled)
		} else {
			this.disableVideo()
			// "videoEnabled" needs to be explicitly set to false, as there is
			// no video track and thus disabling the video will not trigger the
			// handler for "localTrackEnabledChanged"; calling "disableVideo()"
			// just ensures that the video will be initially disabled if it
			// becomes available again later.
			this.set('videoEnabled', false)
			this.set('videoAvailable', false)
		}
	},

	_handleLocalTrackEnabledChanged(track, stream) {
		if (track.kind === 'audio') {
			this.set('audioEnabled', track.enabled)
		} else if (track.kind === 'video') {
			this.set('videoEnabled', track.enabled)
		}
	},

	_handleLocalStreamStopped(localStream) {
		if (this.get('localStream') !== localStream) {
			return
		}

		this.set('localStream', null)

		this.set('audioEnabled', false)
		this.set('audioAvailable', false)
		this.set('videoEnabled', false)
		this.set('videoAvailable', false)
	},

	_handleVolumeChange(currentVolume, volumeThreshold) {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('currentVolume', currentVolume)
		this.set('volumeThreshold', volumeThreshold)
	},

	_handleSpeaking() {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('speaking', true)
	},

	_handleStoppedSpeaking() {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('speaking', false)
	},

	_handleSpeakingWhileMuted() {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('speakingWhileMuted', true)
	},

	_handleStoppedSpeakingWhileMuted() {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('speakingWhileMuted', false)
	},

	_handleVirtualBackgroundLoadFailed() {
		this.set('virtualBackgroundAvailable', false)
	},

	_handleVirtualBackgroundOn() {
		this.set('virtualBackgroundEnabled', true)
	},

	_handleVirtualBackgroundOff() {
		this.set('virtualBackgroundEnabled', false)
	},

	_handleLocalScreen(screen) {
		this.set('localScreen', screen)
	},

	_handleLocalScreenStopped() {
		this.set('localScreen', null)
	},

	enableAudio() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.removeItem('audioDisabled_' + this.get('token'))
		if (!this.get('audioAvailable')) {
			return
		}

		this._webRtc.unmute()
	},

	disableAudio() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.setItem('audioDisabled_' + this.get('token'), 'true')
		if (!this.get('audioAvailable')) {
			return
		}

		this._webRtc.mute()
	},

	enableVideo() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.removeItem('videoDisabled_' + this.get('token'))
		if (!this.get('videoAvailable')) {
			return
		}

		this._webRtc.resumeVideo()
	},

	disableVideo() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.setItem('videoDisabled_' + this.get('token'), 'true')
		if (!this.get('videoAvailable')) {
			return
		}

		this._webRtc.pauseVideo()
	},

	enableVirtualBackground() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.setItem('virtualBackgroundEnabled_' + this.get('token'), 'true')

		this._webRtc.enableVirtualBackground()
	},

	disableVirtualBackground() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.removeItem('virtualBackgroundEnabled_' + this.get('token'))

		this._webRtc.disableVirtualBackground()
	},

	shareScreen(mode, callback) {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		this._webRtc.shareScreen(mode, callback)
	},

	stopSharingScreen() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		this._webRtc.stopScreenShare()
	},

	/**
	 * Toggles hand raised mode for the local participant
	 *
	 * @param {boolean} raised true for raised, false for lowered
	 */
	toggleHandRaised(raised) {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		const raisedHand = {
			state: raised,
			timestamp: Date.now(),
		}

		this._webRtc.sendToAll('raiseHand', raisedHand)

		// Set state locally too, as even when sending to all the sender will not
		// receive the message.
		this.set('raisedHand', raisedHand)
	},

}

EmitterMixin.apply(LocalMediaModel.prototype)
<commit_msg>Fix media not disabled when not available<commit_after>/**
 *
 * @copyright Copyright (c) 2019, Daniel Calviño Sánchez (danxuliu@gmail.com)
 *
 * @license AGPL-3.0-or-later
 *
 * This program 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, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 EmitterMixin from '../../EmitterMixin'
import store from '../../../store/index.js'

/**
 *
 */
export default function LocalMediaModel() {

	this._superEmitterMixin()

	this.attributes = {
		localStreamRequestVideoError: null,
		localStream: null,
		audioAvailable: false,
		audioEnabled: false,
		speaking: false,
		speakingWhileMuted: false,
		currentVolume: -100,
		volumeThreshold: -100,
		videoAvailable: false,
		videoEnabled: false,
		virtualBackgroundAvailable: false,
		virtualBackgroundEnabled: false,
		localScreen: null,
		token: '',
		raisedHand: false,
	}

	this._handleLocalStreamRequestedBound = this._handleLocalStreamRequested.bind(this)
	this._handleLocalStreamBound = this._handleLocalStream.bind(this)
	this._handleLocalStreamRequestFailedRetryNoVideoBound = this._handleLocalStreamRequestFailedRetryNoVideo.bind(this)
	this._handleLocalStreamRequestFailedBound = this._handleLocalStreamRequestFailed.bind(this)
	this._handleLocalStreamChangedBound = this._handleLocalStreamChanged.bind(this)
	this._handleLocalTrackEnabledChangedBound = this._handleLocalTrackEnabledChanged.bind(this)
	this._handleLocalStreamStoppedBound = this._handleLocalStreamStopped.bind(this)
	this._handleVolumeChangeBound = this._handleVolumeChange.bind(this)
	this._handleSpeakingBound = this._handleSpeaking.bind(this)
	this._handleStoppedSpeakingBound = this._handleStoppedSpeaking.bind(this)
	this._handleSpeakingWhileMutedBound = this._handleSpeakingWhileMuted.bind(this)
	this._handleStoppedSpeakingWhileMutedBound = this._handleStoppedSpeakingWhileMuted.bind(this)
	this._handleVirtualBackgroundLoadFailedBound = this._handleVirtualBackgroundLoadFailed.bind(this)
	this._handleVirtualBackgroundOnBound = this._handleVirtualBackgroundOn.bind(this)
	this._handleVirtualBackgroundOffBound = this._handleVirtualBackgroundOff.bind(this)
	this._handleLocalScreenBound = this._handleLocalScreen.bind(this)
	this._handleLocalScreenStoppedBound = this._handleLocalScreenStopped.bind(this)

}

LocalMediaModel.prototype = {

	get(key) {
		return this.attributes[key]
	},

	set(key, value) {
		if (this.attributes[key] === value) {
			return
		}

		this.attributes[key] = value

		this._trigger('change:' + key, [value])
	},

	getWebRtc() {
		return this._webRtc
	},

	setWebRtc(webRtc) {
		if (this._webRtc && this._webRtc.webrtc) {
			this._webRtc.webrtc.off('localStreamRequested', this._handleLocalStreamRequestedBound)
			this._webRtc.webrtc.off('localStream', this._handleLocalStreamBound)
			this._webRtc.webrtc.off('localStreamRequestFailedRetryNoVideo', this._handleLocalStreamRequestFailedBound)
			this._webRtc.webrtc.off('localStreamRequestFailed', this._handleLocalStreamRequestFailedBound)
			this._webRtc.webrtc.off('localStreamChanged', this._handleLocalStreamChangedBound)
			this._webRtc.webrtc.off('localTrackEnabledChanged', this._handleLocalTrackEnabledChangedBound)
			this._webRtc.webrtc.off('localStreamStopped', this._handleLocalStreamStoppedBound)
			this._webRtc.webrtc.off('volumeChange', this._handleVolumeChangeBound)
			this._webRtc.webrtc.off('speaking', this._handleSpeakingBound)
			this._webRtc.webrtc.off('stoppedSpeaking', this._handleStoppedSpeakingBound)
			this._webRtc.webrtc.off('speakingWhileMuted', this._handleSpeakingWhileMutedBound)
			this._webRtc.webrtc.off('stoppedSpeakingWhileMuted', this._handleStoppedSpeakingWhileMutedBound)
			this._webRtc.webrtc.off('virtualBackgroundLoadFailed', this._handleVirtualBackgroundLoadFailedBound)
			this._webRtc.webrtc.off('virtualBackgroundOn', this._handleVirtualBackgroundOnBound)
			this._webRtc.webrtc.off('virtualBackgroundOff', this._handleVirtualBackgroundOffBound)
			this._webRtc.webrtc.off('localScreen', this._handleLocalScreenBound)
			this._webRtc.webrtc.off('localScreenStopped', this._handleLocalScreenStoppedBound)
		}

		this._webRtc = webRtc

		this.set('localStream', null)
		this.set('audioAvailable', false)
		this.set('audioEnabled', false)
		this.set('speaking', false)
		this.set('speakingWhileMuted', false)
		this.set('currentVolume', -100)
		this.set('volumeThreshold', -100)
		this.set('videoAvailable', false)
		this.set('videoEnabled', false)
		this.set('virtualBackgroundAvailable', this._webRtc.webrtc.isVirtualBackgroundAvailable())
		this.set('virtualBackgroundEnabled', this._webRtc.webrtc.isVirtualBackgroundEnabled())
		this.set('localScreen', null)

		this._webRtc.webrtc.on('localStreamRequested', this._handleLocalStreamRequestedBound)
		this._webRtc.webrtc.on('localStream', this._handleLocalStreamBound)
		this._webRtc.webrtc.on('localStreamRequestFailedRetryNoVideo', this._handleLocalStreamRequestFailedRetryNoVideoBound)
		this._webRtc.webrtc.on('localStreamRequestFailed', this._handleLocalStreamRequestFailedBound)
		this._webRtc.webrtc.on('localStreamChanged', this._handleLocalStreamChangedBound)
		this._webRtc.webrtc.on('localTrackEnabledChanged', this._handleLocalTrackEnabledChangedBound)
		this._webRtc.webrtc.on('localStreamStopped', this._handleLocalStreamStoppedBound)
		this._webRtc.webrtc.on('volumeChange', this._handleVolumeChangeBound)
		this._webRtc.webrtc.on('speaking', this._handleSpeakingBound)
		this._webRtc.webrtc.on('stoppedSpeaking', this._handleStoppedSpeakingBound)
		this._webRtc.webrtc.on('speakingWhileMuted', this._handleSpeakingWhileMutedBound)
		this._webRtc.webrtc.on('stoppedSpeakingWhileMuted', this._handleStoppedSpeakingWhileMutedBound)
		this._webRtc.webrtc.on('virtualBackgroundLoadFailed', this._handleVirtualBackgroundLoadFailedBound)
		this._webRtc.webrtc.on('virtualBackgroundOn', this._handleVirtualBackgroundOnBound)
		this._webRtc.webrtc.on('virtualBackgroundOff', this._handleVirtualBackgroundOffBound)
		this._webRtc.webrtc.on('localScreen', this._handleLocalScreenBound)
		this._webRtc.webrtc.on('localScreenStopped', this._handleLocalScreenStoppedBound)
	},

	_handleLocalStreamRequested(constraints, context) {
		if (context !== 'retry-no-video') {
			this.set('localStreamRequestVideoError', null)
		}
	},

	_handleLocalStream(configuration, localStream) {
		// Although there could be several local streams active at the same
		// time (if the local media is started again before stopping it
		// first) the methods to control them ("mute", "unmute",
		// "pauseVideo" and "resumeVideo") act on all the streams, it is not
		// possible to control them individually. Also all local streams
		// are transmitted when a Peer is created, but if another local
		// stream is then added it will not be automatically added to the
		// Peer. As it is not well supported and there is also no need to
		// use several local streams for now it is assumed that only one
		// local stream will be active at the same time.
		this.set('localStream', localStream)

		this.set('token', store.getters.getToken())

		this._setInitialMediaState(localStream)
	},

	_handleLocalStreamRequestFailedRetryNoVideo(constraints, error) {
		if (!error || error.name === 'NotFoundError') {
			return
		}

		this.set('localStreamRequestVideoError', error)
	},

	_handleLocalStreamRequestFailed() {
		this.set('localStream', null)

		this._setInitialMediaState(null)
	},

	_setInitialMediaState(localStream) {
		if (localStream && localStream.getAudioTracks().length > 0) {
			this.set('audioAvailable', true)
			this.set('audioEnabled', localStream.getAudioTracks()[0].enabled)
		} else {
			this.disableAudio()
			this.set('audioEnabled', false)
			this.set('audioAvailable', false)
		}

		if (localStream && localStream.getVideoTracks().length > 0) {
			this.set('videoAvailable', true)
			this.set('videoEnabled', localStream.getVideoTracks()[0].enabled)
		} else {
			this.disableVideo()
			this.set('videoEnabled', false)
			this.set('videoAvailable', false)
		}

		this.set('raisedHand', { state: false, timestamp: Date.now() })
	},

	_handleLocalStreamChanged(localStream) {
		// Only a single local stream is assumed to be active at the same time.
		this.set('localStream', localStream)

		this._updateMediaAvailability(localStream)
	},

	_updateMediaAvailability(localStream) {
		if (localStream && localStream.getAudioTracks().length > 0) {
			this.set('audioAvailable', true)
			this.set('audioEnabled', localStream.getAudioTracks()[0].enabled)
		} else {
			this.disableAudio()
			// "audioEnabled" needs to be explicitly set to false, as there is
			// no audio track and thus disabling the audio will not trigger the
			// handler for "localTrackEnabledChanged"; calling "disableAudio()"
			// just ensures that the audio will be initially disabled if it
			// becomes available again later.
			this.set('audioEnabled', false)
			this.set('audioAvailable', false)
		}

		if (localStream && localStream.getVideoTracks().length > 0) {
			this.set('videoAvailable', true)
			this.set('videoEnabled', localStream.getVideoTracks()[0].enabled)
		} else {
			this.disableVideo()
			// "videoEnabled" needs to be explicitly set to false, as there is
			// no video track and thus disabling the video will not trigger the
			// handler for "localTrackEnabledChanged"; calling "disableVideo()"
			// just ensures that the video will be initially disabled if it
			// becomes available again later.
			this.set('videoEnabled', false)
			this.set('videoAvailable', false)
		}
	},

	_handleLocalTrackEnabledChanged(track, stream) {
		if (track.kind === 'audio') {
			this.set('audioEnabled', track.enabled)
		} else if (track.kind === 'video') {
			this.set('videoEnabled', track.enabled)
		}
	},

	_handleLocalStreamStopped(localStream) {
		if (this.get('localStream') !== localStream) {
			return
		}

		this.set('localStream', null)

		this.set('audioEnabled', false)
		this.set('audioAvailable', false)
		this.set('videoEnabled', false)
		this.set('videoAvailable', false)
	},

	_handleVolumeChange(currentVolume, volumeThreshold) {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('currentVolume', currentVolume)
		this.set('volumeThreshold', volumeThreshold)
	},

	_handleSpeaking() {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('speaking', true)
	},

	_handleStoppedSpeaking() {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('speaking', false)
	},

	_handleSpeakingWhileMuted() {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('speakingWhileMuted', true)
	},

	_handleStoppedSpeakingWhileMuted() {
		if (!this.get('audioAvailable')) {
			return
		}

		this.set('speakingWhileMuted', false)
	},

	_handleVirtualBackgroundLoadFailed() {
		this.set('virtualBackgroundAvailable', false)
	},

	_handleVirtualBackgroundOn() {
		this.set('virtualBackgroundEnabled', true)
	},

	_handleVirtualBackgroundOff() {
		this.set('virtualBackgroundEnabled', false)
	},

	_handleLocalScreen(screen) {
		this.set('localScreen', screen)
	},

	_handleLocalScreenStopped() {
		this.set('localScreen', null)
	},

	enableAudio() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.removeItem('audioDisabled_' + this.get('token'))

		this._webRtc.unmute()
	},

	disableAudio() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.setItem('audioDisabled_' + this.get('token'), 'true')

		this._webRtc.mute()
	},

	enableVideo() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.removeItem('videoDisabled_' + this.get('token'))

		this._webRtc.resumeVideo()
	},

	disableVideo() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.setItem('videoDisabled_' + this.get('token'), 'true')

		this._webRtc.pauseVideo()
	},

	enableVirtualBackground() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.setItem('virtualBackgroundEnabled_' + this.get('token'), 'true')

		this._webRtc.enableVirtualBackground()
	},

	disableVirtualBackground() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		localStorage.removeItem('virtualBackgroundEnabled_' + this.get('token'))

		this._webRtc.disableVirtualBackground()
	},

	shareScreen(mode, callback) {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		this._webRtc.shareScreen(mode, callback)
	},

	stopSharingScreen() {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		this._webRtc.stopScreenShare()
	},

	/**
	 * Toggles hand raised mode for the local participant
	 *
	 * @param {boolean} raised true for raised, false for lowered
	 */
	toggleHandRaised(raised) {
		if (!this._webRtc) {
			throw new Error('WebRtc not initialized yet')
		}

		const raisedHand = {
			state: raised,
			timestamp: Date.now(),
		}

		this._webRtc.sendToAll('raiseHand', raisedHand)

		// Set state locally too, as even when sending to all the sender will not
		// receive the message.
		this.set('raisedHand', raisedHand)
	},

}

EmitterMixin.apply(LocalMediaModel.prototype)
<|endoftext|>


<commit_before>Router.map( function () {
  this.route('home', {
    path: '/',
    template: 'home'
  });
  this.route('about', {
    path: '/about',
    template: 'about'
  });
  this.route('cesium', {
    path: '/cesium',
    template: 'cesium'
  });
  this.route('lightstreamer', {
    path: '/lightstreamer',
    template: 'lightstreamer'
  });
});<commit_msg>Add tracking to all pages<commit_after>Router.configure({
  trackPageView: true
});

Router.map( function () {
  this.route('home', {
    path: '/',
    template: 'home'
  });
  this.route('about', {
    path: '/about',
    template: 'about'
  });
  this.route('cesium', {
    path: '/cesium',
    template: 'cesium'
  });
  this.route('lightstreamer', {
    path: '/lightstreamer',
    template: 'lightstreamer'
  });
});
<|endoftext|>


<commit_before>var Value = require('./value')

module.exports = Struct

var blackList = {
  'length': 'Clashes with `Function.prototype.length`.\n',
  'name': 'Clashes with `Function.prototype.name`\n',
  'destroy': '`destroy` is a reserved key of struct\n'
}

function Struct (properties) {
  var object = Object.create({})
  var observable = Value(object)
  var broadcast = observable.set
  var keys = Object.keys(properties)
  var suspendBroadcast = false

  var releases = keys.forEach(function (key) {
    if (blackList.hasOwnProperty(key)) {
      throw new Error("Cannot create a struct with a key named '" + key + "'.\n" + blackList[key])
    }

    var obs = typeof properties[key] === 'function'
      ? properties[key]
      : Value(properties[key])

    object[key] = obs()
    observable[key] = obs

    return obs(function (val) {
      object[key] = val
      if (!suspendBroadcast) {
        broadcast(object)
      }
    })
  })

  observable.destroy = function () {
    while (releases.length) {
      releases.pop()()
    }
  }

  observable.set = function (values) {
    var lastValue = suspendBroadcast
    suspendBroadcast = true
    values = values || {}

    // update inner observables
    keys.forEach(function (key) {
      if (observable[key]() !== values[key]) {
        observable[key].set(values[key])
      }
    })

    // store additional keys (but don't create observables)
    Object.keys(values).forEach(function (key) {
      if (!(key in properties)) {
        object[key] = values[key]
      }
    })

    suspendBroadcast = lastValue
    if (!suspendBroadcast) {
      broadcast(object)
    }
  }

  return observable
}
<commit_msg>struct: fix destroy<commit_after>var Value = require('./value')

module.exports = Struct

var blackList = {
  'length': 'Clashes with `Function.prototype.length`.\n',
  'name': 'Clashes with `Function.prototype.name`\n',
  'destroy': '`destroy` is a reserved key of struct\n'
}

function Struct (properties) {
  var object = Object.create({})
  var observable = Value(object)
  var broadcast = observable.set
  var keys = Object.keys(properties)
  var suspendBroadcast = false

  var releases = keys.map(function (key) {
    if (blackList.hasOwnProperty(key)) {
      throw new Error("Cannot create a struct with a key named '" + key + "'.\n" + blackList[key])
    }

    var obs = typeof properties[key] === 'function'
      ? properties[key]
      : Value(properties[key])

    object[key] = obs()
    observable[key] = obs

    return obs(function (val) {
      object[key] = val
      if (!suspendBroadcast) {
        broadcast(object)
      }
    })
  })

  observable.destroy = function () {
    while (releases.length) {
      releases.pop()()
    }
  }

  observable.set = function (values) {
    var lastValue = suspendBroadcast
    suspendBroadcast = true
    values = values || {}

    // update inner observables
    keys.forEach(function (key) {
      if (observable[key]() !== values[key]) {
        observable[key].set(values[key])
      }
    })

    // store additional keys (but don't create observables)
    Object.keys(values).forEach(function (key) {
      if (!(key in properties)) {
        object[key] = values[key]
      }
    })

    suspendBroadcast = lastValue
    if (!suspendBroadcast) {
      broadcast(object)
    }
  }

  return observable
}
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import InputBase from './InputBase';

export default class Input extends PureComponent {
  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.value !== undefined) {
      const newValue = nextProps.value || '';

      if (newValue !== prevState.value) {
        return {
          value: newValue,
        };
      }
    }

    return null;
  }

  state = {
    value: '',
  };

  render() {
    const { onChange, ...others } = this.props;

    return (
      <InputBase
        value={this.state.value}
        onChange={event => {
          this.setState({ value: event.currentTarget.value });
          onChange(event, event.currentTarget.value);
        }}
        {...others}
      />
    );
  }
}
<commit_msg>Display warning when using Input for number input by not adding it as a possible prop type for type<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

import InputBase from './InputBase';

export default class Input extends PureComponent {
  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.value !== undefined) {
      const newValue = nextProps.value || '';

      if (newValue !== prevState.value) {
        return {
          value: newValue,
        };
      }
    }

    return null;
  }

  state = {
    value: '',
  };

  render() {
    const { onChange, ...others } = this.props;

    return (
      <InputBase
        value={this.state.value}
        onChange={event => {
          this.setState({ value: event.currentTarget.value });
          onChange(event, event.currentTarget.value);
        }}
        {...others}
      />
    );
  }
}

Input.propTypes = {
  /** The passed down type of the input element. It can be a valid HTML5 input type, except 'number' use a NumericInput in this case. */
  type: PropTypes.oneOf([
    'button',
    'checkbox',
    'color',
    'date',
    'datetime-local',
    'email',
    'file',
    'hidden',
    'image',
    'month',
    'password',
    'radio',
    'range',
    'reset',
    'search',
    'submit',
    'tel',
    'text',
    'time',
    'url',
    'week',
  ]),
};

Input.defaultProps = {
  type: 'text',
};
<|endoftext|>


<commit_before>module.exports = function(app) {
  var createRouter = require('../helpers/createrouter.js');
  var models = [
    'aamcMethods',
    'aamcPcrs',
    'alertChangeTypes',
    'alerts',
    'cohorts',
    'competencies',
    'courseLearningMaterials',
    'courses',
    'curriculumInventoryAcademicLevels',
    'curriculumInventoryExports',
    'curriculumInventoryInstitutions',
    'curriculumInventoryReports',
    'curriculumInventorySequenceBlocks',
    'curriculumInventorySequences',
    'departments',
    'disciplines',
    'educationalYears',
    'ilmSessions',
    'instructionHours',
    'instructorGroups',
    'learnerGroups',
    'learningMaterialStatuses',
    'learningMaterialUserRoles',
    'learningMaterials',
    'meshConcepts',
    'meshDescriptors',
    'meshQualifiers',
    'objectives',
    'offerings',
    'programYears',
    'programs',
    'publishEvents',
    'recurringEvents',
    'reports',
    'schools',
    'sessionDescriptions',
    'sessionLearningMaterials',
    'sessionTypes',
    'sessions',
    'userRoles',
    'users',
  ];

  for(var i = 0; i < models.length; i++){
    var str = models[i];
    var fixtures = require ('../fixtures/' + str + '.js');
    var router = createRouter(str, fixtures);
    app.use('/api/' + str, router);
  }

};
<commit_msg>added mock users and user filtering functionality, refs #54<commit_after>module.exports = function(app) {
  var createRouter = require('../helpers/createrouter.js');
  var models = [
    'aamcMethods',
    'aamcPcrs',
    'alertChangeTypes',
    'alerts',
    'cohorts',
    'competencies',
    'courseLearningMaterials',
    'courses',
    'curriculumInventoryAcademicLevels',
    'curriculumInventoryExports',
    'curriculumInventoryInstitutions',
    'curriculumInventoryReports',
    'curriculumInventorySequenceBlocks',
    'curriculumInventorySequences',
    'departments',
    'disciplines',
    'educationalYears',
    'ilmSessions',
    'instructionHours',
    'instructorGroups',
    'learnerGroups',
    'learningMaterialStatuses',
    'learningMaterialUserRoles',
    'learningMaterials',
    'meshConcepts',
    'meshDescriptors',
    'meshQualifiers',
    'objectives',
    'offerings',
    'programYears',
    'programs',
    'publishEvents',
    'recurringEvents',
    'reports',
    'schools',
    'sessionDescriptions',
    'sessionLearningMaterials',
    'sessionTypes',
    'sessions',
    'userRoles',
  ];

  for(var i = 0; i < models.length; i++){
    var str = models[i];
    var fixtures = require ('../fixtures/' + str + '.js');
    var router = createRouter(str, fixtures);
    app.use('/api/' + str, router);
  }

};
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Corpuslinguistic working group Humboldt University Berlin.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
window.annis_gui_components_codemirror_AqlCodeEditor = function() {

    var connector = this;
    var rootDiv = this.getElement(this.getConnectorId());

    var changeDelayTimerID = null;

    var changeDelayTime = 500;

    var lastServerRequestCounter = 0;

    var errorList = [];

    CodeMirror.registerHelper("lint", "aql", function(text) {
      return errorList;
    });

    var cmTextArea = CodeMirror(rootDiv,
    {
      mode: {
        name : 'aql',
        nodeMappings : {}
      },
      lineNumbers: false,
      lineWrapping: true,
      matchBrackets: true,
      gutters: ["CodeMirror-lint-markers"],
      lint: true,
      placeholder: "",
      inputStyle: 'textarea'
    });

    this.sendTextIfNecessary = function()
    {
      var current = cmTextArea.getValue();

      if(changeDelayTimerID)
      {
        window.clearTimeout(changeDelayTimerID);
      }

      if(connector.getState().text !== current)
      {
        var cursor = cmTextArea.getCursor();
        // calculate the absolute cursor position
        var absPos = 0;
        for(var i=0; i < cursor.line; i++)
        {
          absPos += cmTextArea.getLine(i).length;
          absPos++; // add one for the newline
        }
        absPos += cursor.ch;

        connector.textChanged(current, absPos);
      }
    };

    this.onStateChange = function()
    {
      var cursor = cmTextArea.getCursor();

      //test changes on current text
      var current = cmTextArea.getValue();

      if (current.charAt(current.length - 1) == "\"")
      {
       var isBorder = true;
       var modifiedText = current.substring(0, current.length - 1).concat('\u200E', "\"");

      }

      //end test

      var newMode = {
        name: 'aql',
        nodeMappings : connector.getState().nodeMappings
      };

      cmTextArea.setOption('mode', newMode);
      cmTextArea.setOption("placeholder", connector.getState().inputPrompt);

      // set the text from the server defined state if a new request was made
      if(lastServerRequestCounter < connector.getState().serverRequestCounter)
      {
        lastServerRequestCounter = connector.getState().serverRequestCounter;
        cmTextArea.setValue(connector.getState().text);

        // restore the cursor position
        cmTextArea.setCursor(cursor);
      }

      // apply parent code class
      if(connector.getState().textareaClass && connector.getState().textareaClass !== "") {
        var c = connector.getState().textareaClass;
        if(!$(cmTextArea.getWrapperElement()).find("pre").hasClass(c)) {
          $(cmTextArea.getWrapperElement()).find("pre").addClass(c);
        }
      }

      // copy all error messages
      errorList = [];
      for(var i=0; i < connector.getState().errors.length; i++)
      {
        var err = connector.getState().errors[i];
        var endColumn = err.endColumn+1;
        errorList.push({
          from: CodeMirror.Pos(err.startLine-1, err.startColumn),
          to: CodeMirror.Pos(err.endLine-1, endColumn),
          message: err.message
        });
      }
      // hack: re-initialize the lint by re-setting the option
      cmTextArea.setOption("lint", false);
      cmTextArea.setOption("lint", true);
    };

    this.setChangeDelayTime = function(newDelayTime) {
      changeDelayTime = newDelayTime;
    };

    cmTextArea.on("change", function(instance, changeObj)
    {
      if(changeDelayTimerID)
      {
        window.clearTimeout(changeDelayTimerID);
      }
      changeDelayTimerID = window.setTimeout(connector.sendTextIfNecessary, changeDelayTime);
    });

    // While the text changing event has a timeout before it is send
    // to the server we must be sure it has always the current text
    // whenever the user leaves the textfield, otherwise the query might be old.
    cmTextArea.on("blur", function(instance)
    {
      connector.sendTextIfNecessary();
    });

};

<commit_msg>added a LRM<commit_after>/*
 * Copyright 2013 Corpuslinguistic working group Humboldt University Berlin.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
window.annis_gui_components_codemirror_AqlCodeEditor = function() {

    var connector = this;
    var rootDiv = this.getElement(this.getConnectorId());

    var changeDelayTimerID = null;

    var changeDelayTime = 500;

    var lastServerRequestCounter = 0;

    var errorList = [];

    CodeMirror.registerHelper("lint", "aql", function(text) {
      return errorList;
    });

    var cmTextArea = CodeMirror(rootDiv,
    {
      mode: {
        name : 'aql',
        nodeMappings : {}
      },
      lineNumbers: false,
      lineWrapping: true,
      matchBrackets: true,
      gutters: ["CodeMirror-lint-markers"],
      lint: true,
      placeholder: "",
      inputStyle: 'textarea'
    });

    this.sendTextIfNecessary = function()
    {
      var current = cmTextArea.getValue();

      if(changeDelayTimerID)
      {
        window.clearTimeout(changeDelayTimerID);
      }

      if(connector.getState().text !== current)
      {
        var cursor = cmTextArea.getCursor();
        // calculate the absolute cursor position
        var absPos = 0;
        for(var i=0; i < cursor.line; i++)
        {
          absPos += cmTextArea.getLine(i).length;
          absPos++; // add one for the newline
        }
        absPos += cursor.ch;

        connector.textChanged(current, absPos);
      }
    };

    this.onStateChange = function()
    {

      // test
      // TODO set direction parameter to cmTextArea

      var current = cmTextArea.getValue();
      if (current.charAt(current.length - 1) == "\"" & current.charAt(current.length - 2 ) != '\u200E')
      {
       var modifiedText = current.substring(0, current.length - 1).concat('\u200E', "\"");
       // add the LRM control character before \"
       cmTextArea.setValue(modifiedText);

       // TODO get last line anstead of current cursor
       var currCursor = cmTextArea.getCursor();
       var cursorPos = cmTextArea.getLine(currCursor.line).length;
       var lastLine  = currCursor.line;
       cmTextArea.setCursor({line: lastLine, ch: cursorPos});

   // test ende
      }

       var cursor = cmTextArea.getCursor();

      var newMode = {
        name: 'aql',
        nodeMappings : connector.getState().nodeMappings
      };

      cmTextArea.setOption('mode', newMode);
      cmTextArea.setOption("placeholder", connector.getState().inputPrompt);

      // set the text from the server defined state if a new request was made
      if(lastServerRequestCounter < connector.getState().serverRequestCounter)
      {
        lastServerRequestCounter = connector.getState().serverRequestCounter;
        cmTextArea.setValue(connector.getState().text);

        // restore the cursor position
        cmTextArea.setCursor(cursor);
      }

      // apply parent code class
      if(connector.getState().textareaClass && connector.getState().textareaClass !== "") {
        var c = connector.getState().textareaClass;
        if(!$(cmTextArea.getWrapperElement()).find("pre").hasClass(c)) {
          $(cmTextArea.getWrapperElement()).find("pre").addClass(c);
        }
      }

      // copy all error messages
      errorList = [];
      for(var i=0; i < connector.getState().errors.length; i++)
      {
        var err = connector.getState().errors[i];
        var endColumn = err.endColumn+1;
        errorList.push({
          from: CodeMirror.Pos(err.startLine-1, err.startColumn),
          to: CodeMirror.Pos(err.endLine-1, endColumn),
          message: err.message
        });
      }
      // hack: re-initialize the lint by re-setting the option
      cmTextArea.setOption("lint", false);
      cmTextArea.setOption("lint", true);
    };

    this.setChangeDelayTime = function(newDelayTime) {
      changeDelayTime = newDelayTime;
    };

    cmTextArea.on("change", function(instance, changeObj)
    {
      if(changeDelayTimerID)
      {
        window.clearTimeout(changeDelayTimerID);
      }
      changeDelayTimerID = window.setTimeout(connector.sendTextIfNecessary, changeDelayTime);
    });

    // While the text changing event has a timeout before it is send
    // to the server we must be sure it has always the current text
    // whenever the user leaves the textfield, otherwise the query might be old.
    cmTextArea.on("blur", function(instance)
    {
      connector.sendTextIfNecessary();
    });

};

<|endoftext|>


<commit_before>var app = angular.module('CBEcalc', []);

app.factory('classList', [function(){
  var o = {
    classList: []
  };
  return o;
}]);

app.factory('classPrefixes', [function(){
  var c = {
    classPrefixes: []
  };
  return c;
}]);

app.controller('MainCtrl', [
  '$scope',
  'classList',
  'classPrefixes',
  function($scope, classList, classPrefixes){
    $scope.classList = classList.classList;
    $scope.previousGPA = [];
    $scope.classPrefixes = classPrefixes.classPrefixes;
    $scope.gpa = (0.0).toFixed(2);
    $scope.totalCredits = 0;

    $scope.addClass = function(){
      if(!$scope.name || $scope.name === ''){
        return;
      }
      if(!$scope.grade || $scope.grade === ''){
        return;
      }
      if(!$scope.credits || $scope.credits === '' || $scope.credits != parseInt($scope.credits, 10)){
        return;
      }

      var gpa = 0;
      var tempGrade = $scope.grade;
      var letter = tempGrade.substring(0,1);
      var mod = '';
      if(tempGrade.length >= 2){
        mod = tempGrade.substring(1,2);
        if(!(mod === '+' || mod ==='-')){
          mod = '';
        }
      }
      if(letter === "a" || letter === 'A'){
        gpa = 4;
      }else if(letter === "b" || letter === 'B'){
        gpa = 3;
      }else if(letter === "c" || letter === 'C'){
        gpa = 2;
      }else if(letter === "d" || letter === 'D'){
        gpa = 1;
      }else if(letter === "f" || letter === 'F'){
        gpa = 0;
      }else{
        return;
      }

      if(mod === '+' && gpa < 4){
        gpa += 0.3;
      }else if(mod === '-'){
        gpa -= 0.3;
      }

      $scope.classList.push({
        name: $scope.name,
        grade: letter.toUpperCase() + mod,
        gpa: gpa.toFixed(2),
        credits: $scope.credits
      });

      $scope.name = '';
      $scope.grade = '';
      $scope.credits = '';

      $scope.setGpa();

      return;
    };

    $scope.updatePrevious = function() {
      console.log("made it into function");
      console.log($scope.prevGPA);
      console.log($scope.prevCredits);
      if(!$scope.prevGPA || $scope.prevGPA === ''){
        return;
      }
      if(parseInt($scope.prevGPA) > 4){
        return;
      }
      if(!$scope.prevCredits || $scope.prevCredits === ''){
        return;
      }
      if($scope.prevCredits != parseInt($scope.prevCredits, 10)){
        return;
      }
      if($scope.previousGPA.length > 0){
        $scope.previousGPA.splice(0, $scope.previousGPA.length);
      }

      $scope.previousGPA.push({
        gpa: parseFloat($scope.prevGPA).toFixed(2),
        prevCredits: parseInt($scope.prevCredits)
      });

      $scope.prevGPA = '';
      $scope.prevCredits = '';

      $scope.setGpa();

      return;
    };

    $scope.setGpa = function() {
      var gpa = 0.00;
      var credits = 0.00;

      if($scope.previousGPA.length > 0){
        gpa = $scope.previousGPA[0].gpa * $scope.previousGPA[0].prevCredits;
        credits = $scope.previousGPA[0].prevCredits;
      }

      for(var i = 0 ; i < $scope.classList.length ; i++){
        gpa += (+$scope.classList[i].gpa * +$scope.classList[i].credits);
        credits += +$scope.classList[i].credits;
      }
      if(gpa != 0){
        gpa = gpa / credits;
      }
      $scope.totalCredits = credits;
      $scope.gpa = gpa.toFixed(2);
    };

    $scope.removeClass = function(item) {
      var index = $scope.classList.indexOf(item);
      $scope.classList.splice(index, 1);
      $scope.setGpa();
    };
    $scope.updateDOMInfo = function(info){
      document.getElementById('total').textContent   = info.total;
      document.getElementById('inputs').textContent  = info.inputs;
      document.getElementById('buttons').textContent = info.buttons;
      document.getElementById('data').textContent = info.data;
    }
  }
]);

// Update the relevant fields with the new data
function setDOMInfo(info) {
  var scope = angular.element(document.getElementById("main")).scope();
  scope.$apply(function(){
    scope.updateDOMInfo(info);
  });
}

// Once the DOM is ready...
window.addEventListener('DOMContentLoaded', function () {
  // ...query for the active tab...
  chrome.tabs.query({
    active: true,
    currentWindow: true
  }, function (tabs) {
    // ...and send a request for the DOM info...
    chrome.tabs.sendMessage(
        tabs[0].id,
        {from: 'popup', subject: 'DOMInfo'},
        // ...also specifying a callback to be called
        //    from the receiving end (content script)
        setDOMInfo);
  });
});<commit_msg>started working on function to parse grade data from unnoficial transcript<commit_after>var app = angular.module('CBEcalc', []);

app.factory('classList', [function(){
  var o = {
    classList: []
  };
  return o;
}]);

app.factory('classPrefixes', [function(){
  var c = {
    classPrefixes: []
  };
  return c;
}]);

app.controller('MainCtrl', [
  '$scope',
  'classList',
  'classPrefixes',
  function($scope, classList, classPrefixes){
    $scope.classList = classList.classList;
    $scope.previousGPA = [];
    $scope.classPrefixes = classPrefixes.classPrefixes;
    $scope.gpa = (0.0).toFixed(2);
    $scope.totalCredits = 0;

    $scope.addClass = function(){
      if(!$scope.name || $scope.name === ''){
        return;
      }
      if(!$scope.grade || $scope.grade === ''){
        return;
      }
      if(!$scope.credits || $scope.credits === '' || $scope.credits != parseInt($scope.credits, 10)){
        return;
      }

      var gpa = 0;
      var tempGrade = $scope.grade;
      var letter = tempGrade.substring(0,1);
      var mod = '';
      if(tempGrade.length >= 2){
        mod = tempGrade.substring(1,2);
        if(!(mod === '+' || mod ==='-')){
          mod = '';
        }
      }
      if(letter === "a" || letter === 'A'){
        gpa = 4;
      }else if(letter === "b" || letter === 'B'){
        gpa = 3;
      }else if(letter === "c" || letter === 'C'){
        gpa = 2;
      }else if(letter === "d" || letter === 'D'){
        gpa = 1;
      }else if(letter === "f" || letter === 'F'){
        gpa = 0;
      }else{
        return;
      }

      if(mod === '+' && gpa < 4){
        gpa += 0.3;
      }else if(mod === '-'){
        gpa -= 0.3;
      }

      $scope.classList.push({
        name: $scope.name,
        grade: letter.toUpperCase() + mod,
        gpa: gpa.toFixed(2),
        credits: $scope.credits
      });

      $scope.name = '';
      $scope.grade = '';
      $scope.credits = '';

      $scope.setGpa();

      return;
    };

    $scope.updatePrevious = function() {
      console.log("made it into function");
      console.log($scope.prevGPA);
      console.log($scope.prevCredits);
      if(!$scope.prevGPA || $scope.prevGPA === ''){
        return;
      }
      if(parseInt($scope.prevGPA) > 4){
        return;
      }
      if(!$scope.prevCredits || $scope.prevCredits === ''){
        return;
      }
      if($scope.prevCredits != parseInt($scope.prevCredits, 10)){
        return;
      }
      if($scope.previousGPA.length > 0){
        $scope.previousGPA.splice(0, $scope.previousGPA.length);
      }

      $scope.previousGPA.push({
        gpa: parseFloat($scope.prevGPA).toFixed(2),
        prevCredits: parseInt($scope.prevCredits)
      });

      $scope.prevGPA = '';
      $scope.prevCredits = '';

      $scope.setGpa();

      return;
    };

    $scope.setGpa = function() {
      var gpa = 0.00;
      var credits = 0.00;

      if($scope.previousGPA.length > 0){
        gpa = $scope.previousGPA[0].gpa * $scope.previousGPA[0].prevCredits;
        credits = $scope.previousGPA[0].prevCredits;
      }

      for(var i = 0 ; i < $scope.classList.length ; i++){
        gpa += (+$scope.classList[i].gpa * +$scope.classList[i].credits);
        credits += +$scope.classList[i].credits;
      }
      if(gpa != 0){
        gpa = gpa / credits;
      }
      $scope.totalCredits = credits;
      $scope.gpa = gpa.toFixed(2);
    };

    $scope.removeClass = function(item) {
      var index = $scope.classList.indexOf(item);
      $scope.classList.splice(index, 1);
      $scope.setGpa();
    };
    /* Proof of concept to fetch page content */
    $scope.updateDOMInfo = function(info){
      document.getElementById('total').textContent = info.total;
      document.getElementById('inputs').textContent = info.inputs;
      document.getElementById('buttons').textContent = info.buttons;
      document.getElementById('data').textContent = info.data; //Actual text
    };

    /* ---- In progress ----
    $scope.addPrevClasses = function(info){
      var data = info.data;
      var lines = [];
      for(){
        lines.push({

        });
      }
      $scope.classList.push({
        name: $scope.name,
        grade: letter.toUpperCase() + mod,
        gpa: gpa.toFixed(2),
        credits: $scope.credits
      });
    };
    */
  }
]);

// Update the relevant fields with the new data
function setDOMInfo(info) {
  var scope = angular.element(document.getElementById("main")).scope();
  scope.$apply(function(){
    scope.addPrevClasses(info);
  });
}

// Once the DOM is ready...
window.addEventListener('DOMContentLoaded', function () {
  // ...query for the active tab...
  chrome.tabs.query({
    active: true,
    currentWindow: true
  }, function (tabs) {
    // ...and send a request for the DOM info...
    chrome.tabs.sendMessage(
        tabs[0].id,
        {from: 'popup', subject: 'DOMInfo'},
        // ...also specifying a callback to be called
        //    from the receiving end (content script)
        setDOMInfo);
  });
});
<|endoftext|>


<commit_before>var e = module.exports = {};

a.type = "basic";
a.command = true;
a.help = "Help !";

a.run = (m) => {

};
<commit_msg>Update help.js<commit_after>var cmd = module.exports = {};

cmd.type = "basic";
cmd.command = true;
cmd.help = "Help !";
cmd.args = '';

cmd.run = (m) => {

};
<|endoftext|>


<commit_before>import React from "react";
import PropTypes from "prop-types";
import CustomPropTypes from "../victory-util/prop-types";
import { assign, omit, defaults, uniqueId, isObject } from "lodash";
import Portal from "../victory-portal/portal";
import Timer from "../victory-util/timer";

export default class VictoryContainer extends React.Component {
  static displayName = "VictoryContainer";
  static role = "container";
  static propTypes = {
    children: PropTypes.oneOfType([
      PropTypes.arrayOf(PropTypes.node),
      PropTypes.node
    ]),
    className: PropTypes.string,
    containerId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    desc: PropTypes.string,
    events: PropTypes.object,
    height: CustomPropTypes.nonNegative,
    origin: PropTypes.shape({ x: CustomPropTypes.nonNegative, y: CustomPropTypes.nonNegative }),
    polar: PropTypes.bool,
    portalComponent: PropTypes.element,
    portalZIndex: CustomPropTypes.integer,
    responsive: PropTypes.bool,
    style: PropTypes.object,
    theme: PropTypes.object,
    title: PropTypes.string,
    width: CustomPropTypes.nonNegative
  }

  static defaultProps = {
    portalComponent: <Portal/>,
    portalZIndex: 99,
    responsive: true
  }

  static contextTypes = {
    getTimer: PropTypes.func
  }

  static childContextTypes = {
    portalUpdate: PropTypes.func,
    portalRegister: PropTypes.func,
    portalDeregister: PropTypes.func,
    getTimer: PropTypes.func
  }

  constructor(props) {
    super(props);
    this.getTimer = this.getTimer.bind(this);
    this.containerId = !isObject(props) || typeof props.containerId === "undefined" ?
      uniqueId("victory-container-") : props.containerId;
  }

  getChildContext() {
    return {
      portalUpdate: this.portalUpdate,
      portalRegister: this.portalRegister,
      portalDeregister: this.portalDeregister,
      getTimer: this.getTimer
    };
  }

  componentWillMount() {
    this.savePortalRef = (portal) => {
      this.portalRef = portal;
      return portal;
    };
    this.portalUpdate = (key, el) => this.portalRef.portalUpdate(key, el);
    this.portalRegister = () => this.portalRef.portalRegister();
    this.portalDeregister = (key) => this.portalRef.portalDeregister(key);
  }

  componentWillUnmount() {
    if (!this.context.getTimer) {
      this.getTimer().stop();
    }
  }

  getTimer() {
    if (this.context.getTimer) {
      return this.context.getTimer();
    }
    if (!this.timer) {
      this.timer = new Timer();
    }
    return this.timer;
  }

  getIdForElement(elementName) {
    return `${this.containerId}-${elementName}`;
  }

  // overridden in custom containers
  getChildren(props) {
    return props.children;
  }

  renderContainer(props, svgProps, style) {
    const { title, desc, portalComponent, className, width, height, portalZIndex } = props;
    const children = this.getChildren(props);
    const divStyle = { pointerEvents: "none", touchAction: "none" };
    const svgStyle = { width: "100%", height: "100%" };
    //eslint-disable-next-line no-magic-numbers
    const marginTop = `-${Math.round(100 * height / width)}%`;
    const portalProps = {
      width, height, viewBox: svgProps.viewBox, style: assign({}, svgStyle, { overflow: "visible" })
    };
    return (

        <svg {...svgProps} style={{ ...svgStyle, pointerEvents: "all" }}>
          {title ? <title id={this.getIdForElement("title")}>{title}</title> : null}
          {desc ? <desc id={this.getIdForElement("desc")}>{desc}</desc> : null}
          {children}
        </svg>

            {React.cloneElement(portalComponent, { ...portalProps, ref: this.savePortalRef })}

    );
  }

  render() {
    const { width, height, responsive, events } = this.props;
    const style = responsive ? this.props.style : omit(this.props.style, ["height", "width"]);
    const svgProps = assign(
      {
        width, height, role: "img",
        "aria-labelledby": `${this.getIdForElement("title")} ${this.getIdForElement("desc")}`,
        viewBox: responsive ? `0 0 ${width} ${height}` : undefined
      },
      events
    );
    return this.renderContainer(this.props, svgProps, style);
  }
}
<commit_msg>positioning experiment<commit_after>import React from "react";
import PropTypes from "prop-types";
import CustomPropTypes from "../victory-util/prop-types";
import { assign, omit, defaults, uniqueId, isObject } from "lodash";
import Portal from "../victory-portal/portal";
import Timer from "../victory-util/timer";

export default class VictoryContainer extends React.Component {
  static displayName = "VictoryContainer";
  static role = "container";
  static propTypes = {
    children: PropTypes.oneOfType([
      PropTypes.arrayOf(PropTypes.node),
      PropTypes.node
    ]),
    className: PropTypes.string,
    containerId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    desc: PropTypes.string,
    events: PropTypes.object,
    height: CustomPropTypes.nonNegative,
    origin: PropTypes.shape({ x: CustomPropTypes.nonNegative, y: CustomPropTypes.nonNegative }),
    polar: PropTypes.bool,
    portalComponent: PropTypes.element,
    portalZIndex: CustomPropTypes.integer,
    responsive: PropTypes.bool,
    style: PropTypes.object,
    theme: PropTypes.object,
    title: PropTypes.string,
    width: CustomPropTypes.nonNegative
  }

  static defaultProps = {
    portalComponent: <Portal/>,
    portalZIndex: 99,
    responsive: true
  }

  static contextTypes = {
    getTimer: PropTypes.func
  }

  static childContextTypes = {
    portalUpdate: PropTypes.func,
    portalRegister: PropTypes.func,
    portalDeregister: PropTypes.func,
    getTimer: PropTypes.func
  }

  constructor(props) {
    super(props);
    this.getTimer = this.getTimer.bind(this);
    this.containerId = !isObject(props) || typeof props.containerId === "undefined" ?
      uniqueId("victory-container-") : props.containerId;
  }

  getChildContext() {
    return {
      portalUpdate: this.portalUpdate,
      portalRegister: this.portalRegister,
      portalDeregister: this.portalDeregister,
      getTimer: this.getTimer
    };
  }

  componentWillMount() {
    this.savePortalRef = (portal) => {
      this.portalRef = portal;
      return portal;
    };
    this.portalUpdate = (key, el) => this.portalRef.portalUpdate(key, el);
    this.portalRegister = () => this.portalRef.portalRegister();
    this.portalDeregister = (key) => this.portalRef.portalDeregister(key);
  }

  componentWillUnmount() {
    if (!this.context.getTimer) {
      this.getTimer().stop();
    }
  }

  getTimer() {
    if (this.context.getTimer) {
      return this.context.getTimer();
    }
    if (!this.timer) {
      this.timer = new Timer();
    }
    return this.timer;
  }

  getIdForElement(elementName) {
    return `${this.containerId}-${elementName}`;
  }

  // overridden in custom containers
  getChildren(props) {
    return props.children;
  }

  renderContainer(props, svgProps, style) {
    const { title, desc, portalComponent, className, width, height, portalZIndex } = props;
    const children = this.getChildren(props);
    const divStyle = { pointerEvents: "none", touchAction: "none", position: "relative" };
    const svgStyle = { width: "100%", height: "100%", top: 0, left: 0 };
    const portalProps = {
      width, height, viewBox: svgProps.viewBox, style: assign({}, svgStyle, { overflow: "visible" })
    };
    return (

        <svg {...svgProps} style={{ ...svgStyle, pointerEvents: "all" }}>
          {title ? <title id={this.getIdForElement("title")}>{title}</title> : null}
          {desc ? <desc id={this.getIdForElement("desc")}>{desc}</desc> : null}
          {children}
        </svg>

            {React.cloneElement(portalComponent, { ...portalProps, ref: this.savePortalRef })}

    );
  }

  render() {
    const { width, height, responsive, events } = this.props;
    const style = responsive ? this.props.style : omit(this.props.style, ["height", "width"]);
    const svgProps = assign(
      {
        width, height, role: "img",
        "aria-labelledby": `${this.getIdForElement("title")} ${this.getIdForElement("desc")}`,
        viewBox: responsive ? `0 0 ${width} ${height}` : undefined
      },
      events
    );
    return this.renderContainer(this.props, svgProps, style);
  }
}
<|endoftext|>


<commit_before>const fs = require('fs');
const bot = require('../bot.js');
const path = require('path');
const knex = require('knex')(require('../knexfile.js').development);

function addUser (msg) {
	console.log("Adduser fired.");
	knex('user_data').insert({
		"user_id":   msg.author.id,
		"username":  msg.author.username,
		"server_id": msg.guild.id,
		"xp":        0,
		"last_msg":  new Date()
	})
	.then(
		() => {
			console.log(`${bot.timestamp()} New user ${msg.author.username} added.`)
		})
	.catch(
		(reason) => {
			console.log(`${bot.timestamp()} Error adding new user to table.`, reason);
		});
}

//input level integer, output base xp amount
function xpCost(n) {
	return 25*(3*n+2)*(n-1);
}

//input xp amount, return level
function quadratic(y){
	let a = 75;
	let b = -25;
	let c = -50 - y;
	return Math.floor((-(b)+(Math.pow((Math.pow(b,2)- 4*a*c),0.5))) / (2*a));
}

//returns amount of XP remainder over lvl
function diff(xp) {
	return xp - xpCost(quadratic(xp));
}

//Retrieve info based on your character
var info = function (msg) {
	knex.select('*').from('user_data').where({
		'user_id': msg.author.id,
		'server_id': msg.guild.id
	}).then((rows)=>{
		if (rows.length > 0) {
			let entry = rows[0];
			let xp = entry.xp;
			let level = quadratic(xp);
			msg.channel.sendMessage(`${msg.member}: **Level ${level}** - **${diff(xp)}/${xpCost(level+1) - xpCost(level)} XP**`);
		}  else {
			addUser(msg);
		}
	}).catch((reason)=>{
		console.log(`Error pulling user data for !level`, reason);
	})
}

//Give small amount of XP every amount of time
var msgXp = function (msg,minutes,amount) {
	console.log(`Giving msg Xp to ${msg.author}`)
	knex.select('*').from('user_data').where({
		'user_id': msg.author.id,
		'server_id': msg.guild.id
	})
	.then(
		(rows) => {
			console.log(rows.length);
			if (rows.length>0) {
				let entry = rows[0];
				if ((new Date() - new Date(entry.last_msg)) > (60000*minutes)) {
					let newXp = entry.xp + amount;

					if (quadratic(entry.xp) < quadratic(newXp)) {
						msg.channel.sendMessage(`${msg.author} increased to **Level ${quadratic(newXp)}!**`);
						console.log(`${bot.timestamp()} ${msg.member.nickname} grew to level ${quadratic(newXp)}`);
					}
					knex('user_data').where('id',entry.id).update({
						xp: newXp,
						last_msg: new Date()
					}).then().catch((reason)=> {
						console.log(reason);
					});
				} else return;
			}  else addUser(msg);
		})
	.catch(
		(reason) => {
			console.log(`Error fetching user data.`,reason);
		})
}

// !level add @Mcnamara 400
var giveXp = function (msg, argument) {
	let target = msg.mentions.users.first();
	if (target) {
		knex('user_data').select('*').where({
			'user_id':   target.id,
			'server_id': msg.guild.id
		})
		.then(
			function(rows) {
				if (rows.length > 0) {
					let entry = rows[0];
					let tempArr = msg.content.trim().split(" ");
					let xpAmount = parseInt(tempArr[tempArr.length-1]);
					let newXp = entry.xp + xpAmount;

					if (quadratic(entry.xp) < quadratic(newXp)) {
						msg.channel.sendMessage(`${target} increased to **Level ${quadratic(newXp)}!**`);
						console.log(`${bot.timestamp()} ${msg.guild.member(target).nickname} grew to level ${quadratic(newXp)}`);
					}

					knex('user_data').where('id', entry.id).update({
						xp: entry.xp+xpAmount
					}).then(()=>{
						msg.channel.sendMessage(`${xpAmount}xp given to ${msg.mentions.users.first().username}`).then((msg)=>{
							setTimeout(()=>{
								msg.delete();
							}, 1000);
						})
					});

				}  else msg.channel.sendMessage("User data not found.");

			})
		.catch(
			function(reason) {
				console.log(`Error querying database`,reason);
			})
	}
}

function existsUser(user){

}

const lookUpID = (msg, argument) => {
	knex.select('xp').from('user_data').where({
		'user_id':argument,
		'server_id': msg.guild.id
	}).then((rows)=> {
		if (rows.length > 0) {
			let entry = rows[0];
			let xp = entry.xp;
			let level = quadratic(xp);
			msg.channel.sendMessage(`**Level ${level}** - **${diff(xp)}/${xpCost(level+1) - xpCost(level)} XP**`);
		}else {
			msg.channel.sendMessage("User not found.")
		}
	}).catch((err)=>{
		console.log(err);
	})
}

const forceAdd = (user_id,server_id,username)=> {
	knex.select('id').from('user_data').where({'user_id':user_id,'server_id': server_id})
	.then((rows)=> {
		console.log(rows);
		if (rows.length<1) {
			knex('user_data').insert({
			"user_id":   user_id,
			"username":  username,
			"server_id": server_id,
			"xp":        0,
			"last_msg":  new Date()
			}).then(()=> {
				console.log("User Added")
				return true;
			});
		} else {
			console.log("Failed to forceadd " + user_id);
			return false;
		}
	})
};

module.exports = function(bot,knex)  {
	return {
		get:info,
		give:giveXp,
		msgXp:msgXp,
		addUser:addUser,
		lookUpID: lookUpID,
		forceAdd: forceAdd
	}
}<commit_msg>Increased time of XP message<commit_after>const fs = require('fs');
const bot = require('../bot.js');
const path = require('path');
const knex = require('knex')(require('../knexfile.js').development);

function addUser (msg) {
	console.log("Adduser fired.");
	knex('user_data').insert({
		"user_id":   msg.author.id,
		"username":  msg.author.username,
		"server_id": msg.guild.id,
		"xp":        0,
		"last_msg":  new Date()
	})
	.then(
		() => {
			console.log(`${bot.timestamp()} New user ${msg.author.username} added.`)
		})
	.catch(
		(reason) => {
			console.log(`${bot.timestamp()} Error adding new user to table.`, reason);
		});
}

//input level integer, output base xp amount
function xpCost(n) {
	return 25*(3*n+2)*(n-1);
}

//input xp amount, return level
function quadratic(y){
	let a = 75;
	let b = -25;
	let c = -50 - y;
	return Math.floor((-(b)+(Math.pow((Math.pow(b,2)- 4*a*c),0.5))) / (2*a));
}

//returns amount of XP remainder over lvl
function diff(xp) {
	return xp - xpCost(quadratic(xp));
}

//Retrieve info based on your character
var info = function (msg) {
	knex.select('*').from('user_data').where({
		'user_id': msg.author.id,
		'server_id': msg.guild.id
	}).then((rows)=>{
		if (rows.length > 0) {
			let entry = rows[0];
			let xp = entry.xp;
			let level = quadratic(xp);
			msg.channel.sendMessage(`${msg.member}: **Level ${level}** - **${diff(xp)}/${xpCost(level+1) - xpCost(level)} XP**`);
		}  else {
			addUser(msg);
		}
	}).catch((reason)=>{
		console.log(`Error pulling user data for !level`, reason);
	})
}

//Give small amount of XP every amount of time
var msgXp = function (msg,minutes,amount) {
	console.log(`Giving msg Xp to ${msg.author}`)
	knex.select('*').from('user_data').where({
		'user_id': msg.author.id,
		'server_id': msg.guild.id
	})
	.then(
		(rows) => {
			console.log(rows.length);
			if (rows.length>0) {
				let entry = rows[0];
				if ((new Date() - new Date(entry.last_msg)) > (60000*minutes)) {
					let newXp = entry.xp + amount;

					if (quadratic(entry.xp) < quadratic(newXp)) {
						msg.channel.sendMessage(`${msg.author} increased to **Level ${quadratic(newXp)}!**`);
						console.log(`${bot.timestamp()} ${msg.member.nickname} grew to level ${quadratic(newXp)}`);
					}
					knex('user_data').where('id',entry.id).update({
						xp: newXp,
						last_msg: new Date()
					}).then().catch((reason)=> {
						console.log(reason);
					});
				} else return;
			}  else addUser(msg);
		})
	.catch(
		(reason) => {
			console.log(`Error fetching user data.`,reason);
		})
}

// !level add @Mcnamara 400
var giveXp = function (msg, argument) {
	let target = msg.mentions.users.first();
	if (target) {
		knex('user_data').select('*').where({
			'user_id':   target.id,
			'server_id': msg.guild.id
		})
		.then(
			function(rows) {
				if (rows.length > 0) {
					let entry = rows[0];
					let tempArr = msg.content.trim().split(" ");
					let xpAmount = parseInt(tempArr[tempArr.length-1]);
					let newXp = entry.xp + xpAmount;

					if (quadratic(entry.xp) < quadratic(newXp)) {
						msg.channel.sendMessage(`${target} increased to **Level ${quadratic(newXp)}!**`);
						console.log(`${bot.timestamp()} ${msg.guild.member(target).nickname} grew to level ${quadratic(newXp)}`);
					}

					knex('user_data').where('id', entry.id).update({
						xp: entry.xp+xpAmount
					}).then(()=>{
						msg.channel.sendMessage(`${xpAmount}xp given to ${msg.mentions.users.first().username}`).then((msg)=>{
							setTimeout(()=>{
								msg.delete();
							}, 3000);
						})
					});

				}  else msg.channel.sendMessage("User data not found.");

			})
		.catch(
			function(reason) {
				console.log(`Error querying database`,reason);
			})
	}
}

function existsUser(user){

}

const lookUpID = (msg, argument) => {
	knex.select('xp').from('user_data').where({
		'user_id':argument,
		'server_id': msg.guild.id
	}).then((rows)=> {
		if (rows.length > 0) {
			let entry = rows[0];
			let xp = entry.xp;
			let level = quadratic(xp);
			msg.channel.sendMessage(`**Level ${level}** - **${diff(xp)}/${xpCost(level+1) - xpCost(level)} XP**`);
		}else {
			msg.channel.sendMessage("User not found.")
		}
	}).catch((err)=>{
		console.log(err);
	})
}

const forceAdd = (user_id,server_id,username)=> {
	knex.select('id').from('user_data').where({'user_id':user_id,'server_id': server_id})
	.then((rows)=> {
		console.log(rows);
		if (rows.length<1) {
			knex('user_data').insert({
			"user_id":   user_id,
			"username":  username,
			"server_id": server_id,
			"xp":        0,
			"last_msg":  new Date()
			}).then(()=> {
				console.log("User Added")
				return true;
			});
		} else {
			console.log("Failed to forceadd " + user_id);
			return false;
		}
	})
};

module.exports = function(bot,knex)  {
	return {
		get:info,
		give:giveXp,
		msgXp:msgXp,
		addUser:addUser,
		lookUpID: lookUpID,
		forceAdd: forceAdd
	}
}<|endoftext|>


<commit_before>ym.modules.define('system.supports.graphics', [], function (provide) {

    var webGlContextSettings = {
            failIfMajorPerformanceCaveat: true, // just to be sure
            antialias: false                    // Firefox does not like offscreen canvas with AA
        },
        tests = {};

    function isWebGlCapable () {
        // Test system support
        if (window.WebGLRenderingContext) {
            // test blacklists
            var browser = ym.env.browser,
                webglBrowserBlacklist = {
                    'Samsung Internet': true, // unstable
                    'AndroidBrowser': true    // unstable
                },
                isOldAndroid = browser.engine == "Webkit" && (+browser.engineVersion < +537), // unstable
                isOldOperatingSystem = /^Windows (XP|Vista|Server 2003)/.test(browser.osName); // deprecated

            if (isOldAndroid || isOldOperatingSystem || webglBrowserBlacklist[browser.name]) {
                return false;
            }
        } else {
            // No system support
            return false;
        }
        return true;
    }

    function detectWebGl () {
        if (!isWebGlCapable()) {
            return null;
        }

        var contextName;
        try {
            var canvas = document.createElement("canvas"),
                context = canvas.getContext(contextName = "webgl", webGlContextSettings);
            if (!context) {
                context = canvas.getContext(contextName = "experimental-webgl", webGlContextSettings); // IE
                if (!context) {
                    contextName = null;
                }
            }
        } catch (e) {
            // suppress warnings at FF
            contextName = null;
        }

        return contextName ? {
            contextName: contextName
        } : null;

    }

    // Test globalCompositeOperation to work properly
    function testCanvas (sandbox, ctx) {
        sandbox.width = 226;
        sandbox.height = 256;

        ctx.fillStyle = "#fff";
        ctx.fillRect(0, 0, 150, 150);

        ctx.globalCompositeOperation = "xor";

        ctx.fillStyle = "#f00";
        ctx.fillRect(10, 10, 100, 100);

        ctx.fillStyle = "#0f0";
        ctx.fillRect(50, 50, 100, 100);

        var data = ctx.getImageData(49, 49, 2, 2),
            test = [];
        for (var i = 0; i < 16; i++) {
            test.push(data.data[i]);
        }
        return test.join('x') == '0x0x0x0x0x0x0x0x0x0x0x0x0x255x0x255';
    }

    provide({
        hasSvg: function () {
            if (!('svg' in tests)) {
                tests.svg = document.implementation &&
                    document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1");
            }
            return tests.svg;
        },

        hasCanvas: function () {
            if (!('canvas' in tests)) {
                var sandbox = document.createElement('canvas'),
                    canvas = ('getContext' in sandbox) ? sandbox.getContext('2d') : null;
                tests.canvas = canvas ? testCanvas(sandbox, canvas) : false;
            }
            return tests.canvas;
        },

        hasWebGl: function () {
            if (!('webgl' in tests)) {
                tests.webgl = detectWebGl(true);
            }
            return tests.webgl;
        },

        hasVml: function () {
            if (!('vml' in tests)) {
                var supported = false,
                    topElement = document.createElement('div'),
                    testElement;
                topElement.innerHTML = '<v:shape id="yamaps_testVML"  adj="1" />';
                testElement = topElement.firstChild;
                if (testElement && testElement.style) {
                    testElement.style.behavior = 'url(#default#VML)';
                    supported = testElement ? typeof testElement.adj == 'object' : true;
                    topElement.removeChild(testElement);
                }
                tests.vml = supported;
            }
            return tests.vml;
        },

        redetect: function () {
            tests = {};
        },

        getWebGlContextName: function () {
            return tests.webgl && tests.webgl.contextName;
        }
    });
});<commit_msg>Temporarily remove XP from WebGL blacklist<commit_after>ym.modules.define('system.supports.graphics', [], function (provide) {

    var webGlContextSettings = {
            failIfMajorPerformanceCaveat: true, // just to be sure
            antialias: false                    // Firefox does not like offscreen canvas with AA
        },
        tests = {};

    function isWebGlCapable () {
        // Test system support
        if (window.WebGLRenderingContext) {
            // test blacklists
            var browser = ym.env.browser,
                webglBrowserBlacklist = {
                    'Samsung Internet': true, // unstable
                    'AndroidBrowser': true    // unstable
                },
                isOldAndroid = browser.engine == "Webkit" && (+browser.engineVersion < +537); // unstable

            if (isOldAndroid || webglBrowserBlacklist[browser.name]) {
                return false;
            }
        } else {
            // No system support
            return false;
        }
        return true;
    }

    function detectWebGl () {
        if (!isWebGlCapable()) {
            return null;
        }

        var contextName;
        try {
            var canvas = document.createElement("canvas"),
                context = canvas.getContext(contextName = "webgl", webGlContextSettings);
            if (!context) {
                context = canvas.getContext(contextName = "experimental-webgl", webGlContextSettings); // IE
                if (!context) {
                    contextName = null;
                }
            }
        } catch (e) {
            // suppress warnings at FF
            contextName = null;
        }

        return contextName ? {
            contextName: contextName
        } : null;

    }

    // Test globalCompositeOperation to work properly
    function testCanvas (sandbox, ctx) {
        sandbox.width = 226;
        sandbox.height = 256;

        ctx.fillStyle = "#fff";
        ctx.fillRect(0, 0, 150, 150);

        ctx.globalCompositeOperation = "xor";

        ctx.fillStyle = "#f00";
        ctx.fillRect(10, 10, 100, 100);

        ctx.fillStyle = "#0f0";
        ctx.fillRect(50, 50, 100, 100);

        var data = ctx.getImageData(49, 49, 2, 2),
            test = [];
        for (var i = 0; i < 16; i++) {
            test.push(data.data[i]);
        }
        return test.join('x') == '0x0x0x0x0x0x0x0x0x0x0x0x0x255x0x255';
    }

    provide({
        hasSvg: function () {
            if (!('svg' in tests)) {
                tests.svg = document.implementation &&
                    document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1");
            }
            return tests.svg;
        },

        hasCanvas: function () {
            if (!('canvas' in tests)) {
                var sandbox = document.createElement('canvas'),
                    canvas = ('getContext' in sandbox) ? sandbox.getContext('2d') : null;
                tests.canvas = canvas ? testCanvas(sandbox, canvas) : false;
            }
            return tests.canvas;
        },

        hasWebGl: function () {
            if (!('webgl' in tests)) {
                tests.webgl = detectWebGl();
            }
            return tests.webgl;
        },

        hasVml: function () {
            if (!('vml' in tests)) {
                var supported = false,
                    topElement = document.createElement('div'),
                    testElement;
                topElement.innerHTML = '<v:shape id="yamaps_testVML"  adj="1" />';
                testElement = topElement.firstChild;
                if (testElement && testElement.style) {
                    testElement.style.behavior = 'url(#default#VML)';
                    supported = testElement ? typeof testElement.adj == 'object' : true;
                    topElement.removeChild(testElement);
                }
                tests.vml = supported;
            }
            return tests.vml;
        },

        redetect: function () {
            tests = {};
        },

        getWebGlContextName: function () {
            return tests.webgl && tests.webgl.contextName;
        }
    });
});
<|endoftext|>


<commit_before>var Controller = plugin('controllers/controller');
var WintersmithController = require('./controller');

module.exports = function(event) {
    var router = new event.express.Router();
    router.get('/preview', Controller.handle('preview', WintersmithController));
    router.get('/publish', Controller.handle('publish', WintersmithController));
    return router;
};
<commit_msg>Updated router code to work with new factory<commit_after>var Controller = plugin('controllers/controller');
var WintersmithController = require('./controller');

module.exports = function(event) {
    var router  = new event.express.Router();
    var factory = new Controller.Factory(WintersmithController, event.app);
    router.get('/preview', factory.handle('preview'));
    router.get('/publish', factory.handle('publish'));
    return router;
};
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash'),
    path = require('path'),
    fs = require('fs'),
    slash = require('slash')
;

function createFileObject(file, inDir, outDir, cfgFiles) {
    var joinedPath = path.join(inDir, file);
    var joinedPathExists = fs.existsSync(joinedPath);
    if (joinedPathExists) {
        var files = {
            src: [joinedPath],
            dest: path.join(outDir,path.basename(file))
        };
        cfgFiles.push(files);
    }
    // return the source file existence
    return joinedPathExists;
}

// exports step and blocReplacement variables,
// They will be used in the useminPrepare and usemin grunt plugins.
var step = {
    name:'copy',
    createConfig: function (context, block) {
        var cfg = {
            files: []
        };

        // warning : block.dest should be a directory
        var outDir = path.join(context.outDir || '', block.dest || '.','/');
        var outFiles = [];

        if (_.isArray(context.inFiles)) {
            context.inFiles.forEach(function (f) {
                if (_.isArray(context.inDir)) {
                    context.inDir.every(function (d) {
                        return !createFileObject(f, d, outDir, cfg.files);
                    });
                } else {
                    createFileObject(f, context.inDir, outDir, cfg.files);
                }
            });
        }

        context.outFiles = cfg.files.map(function(f){
            return f.dest;
        });

        return cfg;
    }
};

var blockReplacement = function (block) {
    var clone = _.initial(_.rest(_.cloneDeep(block.raw))),
        result,
        dest
    ;

    if (block.conditionalStart) {
        clone = _.rest(clone);
    }
    if (block.conditionalEnd) {
        clone = _.initial(clone);
    }

    result = clone.join('\n').trim();

    if (_.isArray(block.src)) {
        block.src.forEach(function(src){
            dest = path.join(block.dest, path.basename(src));
            result = result.replace(src, slash(dest));
        });
    }
    return result;
};

module.exports = {
    step: step,
    blockReplacement: blockReplacement
};<commit_msg>Add possibility to use multiple source directories (syntax: <!-- build:flatcopy({dir1,dir2,**/dir3}) dest/folder -->)<commit_after>'use strict';

var _ = require('lodash'),
    path = require('path'),
    fs = require('fs'),
    slash = require('slash')
;

// exports step and blocReplacement variables,
// They will be used in the useminPrepare and usemin grunt plugins.
var step = {
    name:'copy',
    createConfig: function (context, block) {

        var cfg = {
            files: []
        };

        // warning : block.dest should be a directory
        var outDir = path.join(context.outDir || '', block.dest || '.','/');
        var outFiles = [];

        if (_.isArray(context.inFiles)) {
            context.inFiles.forEach(function (f) {
                if (_.isArray(context.inDir)) {
                    context.inDir.every(function (d) {
                        var joinedPath = path.join(d, f);
                        var joinedPathExists = fs.existsSync(joinedPath);
                        if (joinedPathExists) {
                            var files = {
                                src: [joinedPath],
                                dest: path.join(outDir,path.basename(f))
                            };
                            cfg.files.push(files);
                        }
                        // return the source file existence
                        return !joinedPathExists;
                    });
                } else {
                    cfg.files.push({
                        src: path.join(context.inDir, f),
                        dest: path.join(outDir,path.basename(f))
                    });
                }
            });
        }

        context.outFiles = cfg.files.map(function(f){
            return f.dest;
        });

        return cfg;
    }
};

var blockReplacement = function (block) {
    var clone = _.initial(_.rest(_.cloneDeep(block.raw))),
        result,
        dest
    ;

    if (block.conditionalStart) {
        clone = _.rest(clone);
    }
    if (block.conditionalEnd) {
        clone = _.initial(clone);
    }

    result = clone.join('\n').trim();

    if (_.isArray(block.src)) {
        block.src.forEach(function(src){
            dest = path.join(block.dest, path.basename(src));
            result = result.replace(src, slash(dest));
        });
    }
    return result;
};

module.exports = {
    step: step,
    blockReplacement: blockReplacement
};<|endoftext|>