<commit_before>import { throttle } from "lodash"
import { ImageCapture } from "../ImageCapture"
import React, { Component } from 'react'
import Slider from 'material-ui/Slider';

import Message from './message'
import Devices from './devices'
import Shutter from './shutter'
import CaptureButton from './captureButton'

const shutterSound = new Audio("./camera-shutter-click-01.wav")
const MAX_SCALE = 10
const MIN_SCALE = 1
const ZOOM_INCREMENT = .25

const cameraControlStyle = {
    width: 150,
    backgroundColor: "black"
}

export default class Camera extends Component {

    constructor(props) {

        super(props)

        this.canvas = document.createElement('canvas')

        this.canvas2dContext = this.canvas.getContext('2d')

        this.msgSpan = null;
        this.video = null;
        this.state = {
            scale: this.validateScale(this.props.scale),
            showDevices: this.props.showDevices,
            devices: [],
            selectedDeviceId: null,
            width: this.props.style.width - cameraControlStyle.width,
            height: this.props.style.height,
            emulation: this.props.emulation,
            emulationSrc: this.props.emulationSrc,
            isCapturing: false

        } // using react state to track ui state; should stay here even after introducing redux?

        this._onCapture = throttle(this._onCapture.bind(this), 1000)
        this._onError = this._onError.bind(this)

        this.changeDevice = this.changeDevice.bind(this)
        this.zoomIn = this.zoomIn.bind(this)
        this.zoomOut = this.zoomOut.bind(this)
        this.zoomChange = this.zoomChange.bind(this)

        this.getUserMedia = this.getUserMedia.bind(this)
    }

    render() {

        let cameraStyle = {
            width: this.state.width,
            height: this.state.height,
            overflow: "hidden",
            display: "flex",
            position: "relative",
            backgroundColor: "black"
        }

        let videoStyle = Object.assign({}, {
            position: "absolute",
            margin: 'auto',
            top: '50%',
            left: '50%'
        }, { WebkitTransform: "translate(-50%,-50%)scale(" + this.state.scale + ")", width: this.state.width, height: this.state.height })

        let sliderValue = (this.state.scale - MIN_SCALE) / (this.props.maxScale - MIN_SCALE)
        let sliderHeight = (this.state.height - 80)

        return (

                            <video style={videoStyle}
                                ref={vid => { this.video = vid }}

                            />

                            {
                                this.state.showDevices && <Devices devices={this.state.devices} style={{ margin: 20 }} onClick={this.changeDevice} />
                            }

                                {this.state.emulation && <Message msg="Emulation Mode" permanent={true} />}
                                <Message msg={Math.round(this.state.scale * 100) / 100 + "X"} />

                            <Shutter display={this.state.isCapturing} style={{ width: this.state.width, height: this.state.height }} />

                            <CaptureButton onClick={this._onCapture} />

                                <button onClick={this.zoomIn}>+</button>
                                <Slider style={{ height: sliderHeight, marginTop: 10, marginBottom: 10, display: "flex", justifyContent: "center" }} sliderStyle={{ marginTop: 0, marginBottom: 0 }} axis="y" value={sliderValue} defaultValue={sliderValue} onChange={this.zoomChange} />
                                <button onClick={this.zoomOut}>-</button>

        )
    }

    componentWillReceiveProps(props) {
        if (this.video && this.video.videoHeight > 0) {
            let dimension = this.adjustAspectRatio(this.video.videoWidth, this.video.videoHeight, props.style.width)
            this.setState(dimension)
        }

    }
    componentWillMount() {

    }

    componentDidMount() {

        let ctx = this;
        this.getDeviceList().then(deviceList => {
            ctx.setState({ devices: deviceList || [] })
            ctx.loadDefaultDevice(deviceList)

        })

    }

    _onCapture(e) {

        let ctx = this;

        //calculate image dimension based on scale

        let dx = (this.video.videoWidth / this.state.scale)
        let dy = (this.video.videoHeight / this.state.scale)

        let x1 = (this.video.videoWidth - dx) / 2;
        let y1 = (this.video.videoHeight - dy) / 2;

        this.canvas2dContext.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.canvas2dContext.drawImage(this.video, x1, y1, dx, dy, 0, 0, this.canvas.width, this.canvas.height)

        let img = this.canvas.toDataURL('image/png');

        this.setState({ isCapturing: true }, () => {

            if (ctx.props.onCapture) {
                ctx.props.onCapture(e, img)
            }

            if ("vibrate" in navigator) {
                navigator.vibrate(100)
            }
            shutterSound.play().then(() => {
                this.setState({ isCapturing: false })
            })

        })
    }

    _onError(err) {
        if (this.props.onError) {
            this.props.onError(err)
        }
        else {
            console.error(err)
        }
    }

    zoomIn() {
        let currentScale = this.state.scale
        let newScale = currentScale + ZOOM_INCREMENT;
        if (newScale > this.props.maxScale) {
            newScale = this.props.maxScale;
        }
        this.setState({ scale: this.validateScale(newScale) })

    }
    zoomOut() {

        let currentScale = this.state.scale
        let newScale = currentScale - ZOOM_INCREMENT;
        if (newScale < MIN_SCALE) {
            newScale = MIN_SCALE;
        }
        this.setState({ scale: this.validateScale(newScale) })
    }

    zoomChange(e, newValue) {

        let newScale = MIN_SCALE + (newValue) * (this.props.maxScale - MIN_SCALE)

        this.setState({ scale: this.validateScale(newScale) })
    }

    adjustAspectRatio(videoWidth, videoHeight, width) {
        let dimension = { height: width * videoHeight / videoWidth, width }
        return dimension
    }

    setCanvasDimension(videoWidth, videoHeight, width) {
        this.canvas.width = videoWidth
        this.canvas.height = videoHeight
    }

    getDeviceList() {

        let ctx = this

        let deviceList = null;
        let filter = (item) => { return (item.kind === "video" || item.kind === "videoinput"); };
        let sort = (a, b) => {

            let labelA = (a.label || "").toLowerCase()
            let labelB = (b.label || "").toLowerCase()

            let isARearCamera = (labelA.indexOf("rear") >= 0)
            let isBRearCamera = (labelB.indexOf("rear") >= 0)

            let returnVal = 0

            if (isARearCamera === isBRearCamera) {
                returnVal = (labelA < labelB) ? -1 : ((labelA > labelB) ? 1 : 0)
            }
            else if (isARearCamera && !isBRearCamera) {
                returnVal = -1
            }
            else {
                returnVal = 1
            }
            return returnVal
        }

        let handleDeviceReceived = (sourceList) => {
            deviceList = sourceList || []
            deviceList = deviceList.filter(filter)
            deviceList = deviceList.sort(sort)

            if (!deviceList.find(item => { return item.kind === "emulation" })) {
                deviceList.push(this.getEmulationDeviceInfo())
            }

            return Promise.resolve(deviceList)

        }
        try {
            if (navigator.mediaDevices.enumerateDevices) {
                return navigator.mediaDevices.enumerateDevices().then(handleDeviceReceived).catch(ctx._onError)
            }
            else if (MediaStreamTrack && MediaStreamTrack.getSources) {
                return MediaStreamTrack.getSources(handleDeviceReceived, ctx._onError);
            }
            else {
                return Promise.reject(false)
            }
        }
        catch (err) {
            this._onError(err)
            return Promise.reject(false)
        }

    }

    changeDevice(sourceId) {

        let ctx = this;
        //override device
        if (sourceId) {

            if (sourceId == 1) {
                //emulation
                this.setState({ emulation: true }, () => {
                    ctx.getUserMedia()
                })
            }
            else {
                this.setState({ emulation: false }, () => {
                    let constraints = {
                        audio: false,
                        video: {
                            optional: [{ sourceId }]
                        }
                    }
                    ctx.getUserMedia(constraints)
                })
            }
        }
    }

    getVideoCapabilities(videoTrack) {

        let capabilities = videoTrack.getCapabilities();

        if (capabilities.zoom) {
            console.log("hardware zoom supportd")
        }
        if (capabilities.focusDistance) {
            console.log("focus supportd")
        }

        if (typeof ImageCapture !== 'undefined') {
            try {
                //experimental
                console.log("ImageCapture supported")
                let imageCapture = new ImageCapture(videoTrack)

                let photoCapabilities = imageCapture.getPhotoCapabilities().then(c => {
                    console.dir(c)
                })
                if (navigator.mediaDevices.getSupportedConstraints) {
                    let c = navigator.mediaDevices.getSupportedConstraints();
                    console.dir(c)
                }

            }
            catch (err) {
                //ignore
            }

        }
    }

    loadEmulationVideo(video) {
        //stop existing videotracks
        if (video.srcObject) {
            video.srcObject.getVideoTracks().forEach(track => track.stop())
            video.srcObject = null;
        }

        video.src = this.state.emulationSrc;
        video.muted = true
        if (typeof video.loop == 'boolean') {
            // loop supported
            video.loop = true;
        }
    }
    handleVideoMetaDataLoaded(video, e) {
        let ctx = this
        video.play().then(() => {
            ctx.setCanvasDimension(video.videoWidth, video.videoHeight)
            let dimension = ctx.adjustAspectRatio(video.videoWidth, video.videoHeight, ctx.state.width)
            ctx.setState(dimension)
        }).catch(ctx._onError)
    }

    bindVideoEventHandlers(video) {
        if (!video) return;
        video.onabort = (e) => {
            console.log("video aborted", e)
        }
        video.onactivate = (e) => {
            console.log("video actived", e)
        }
        video.onclose = e => {
            console.log("video closed", e)
        }
        video.onerror = (e) => {
            this._onError(e)
        }
    }

    bindStreamEventHandlers(stream) {

        if (!stream) return;

        stream.oninactive = e => {
            console.log('Stream inactive', e);
        };
        stream.onactive = (e) => {
            console.log("Stream active", e)
        }
        stream.oneded = e => {
            console.log("Stream ended", e)
        }

    }

    handleStreamReceived(constraints, stream) {
        let videoTracks = null;
        let video = this.video;
        let ctx = this;

        if (stream && stream.getVideoTracks) {
            videoTracks = stream.getVideoTracks();

            if (videoTracks.length > 0 && videoTracks[0].getCapabilities) {
                console.log(videoTracks[0].label)
                this.getVideoCapabilities(videoTracks[0])
            }
        }

        if (this.state.emulation) {
            //emulation?
            this.loadEmulationVideo(video)

        }
        else if (stream instanceof MediaStream) {
            video.src = null;
            video.srcObject = stream
        }
        else {

            //this should not reach, but just in case..
            this.setState({ emulation: true })
            this.loadEmulationVideo(video)
        }

        this.bindVideoEventHandlers(video)
        this.bindStreamEventHandlers(stream)
        video.onloadedmetadata = this.handleVideoMetaDataLoaded.call(this, video)

    }

    loadDefaultDevice(deviceList) {

        let constraints = {
            audio: false,
            video: { width: 1920, height: 1080, facingMode: "environment" },

        }

        if (deviceList && deviceList.length > 0) {
            constraints.video =  { optional : [ { sourceId: deviceList[0].deviceId }] }
        }

        this.getUserMedia(constraints)
    }

    getUserMedia(constraints) {

        try {
            let getUserMedia;
            let ctx;

            if (!constraints) {
                constraints = {
                    audio: false,
                    video: { facingMode: "environment", width: 1920, height: 1080 }
                }
            }

            debugger

            if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
                getUserMedia = navigator.mediaDevices.getUserMedia;
                ctx = navigator.mediaDevices;
            }
            else if (navigator.getUserMedia) {
                getUserMedia = navigator.getUserMedia
                ctx = navigator;
            }
            else if (navigator.webkitGetUserMedia) {
                getUserMedia = navigator.webkitGetUserMedia
                ctx = navigator
            }
            else {
                getUserMedia = this.getUserMediaEmulation;
                ctx = this
            }
            //manually set the context to wherever the function belongs to, otherwise will get illegal invcation error
            return getUserMedia.call(ctx, constraints).then(this.handleStreamReceived.bind(this, constraints)).catch(this._onError);

        }
        catch (ex) {
            this._onError(ex)
        }
    }

    getEmulationDeviceInfo() {
        return {
            id: 1,
            deviceId: 1,
            label: "emulation",
            kind: "emulation",
            emulation: true,
            selected: false
        }
    }

    getUserMediaEmulation() {

        return new Promise((resolve, reject) => {
            this.setState({ emulation: true }, () => {

                resolve(false);//no MediaStream
            })
        })
    }

    validateScale(scale) {
        let newScale = MIN_SCALE;

        if (scale) {
            if (scale < MIN_SCALE) {
                newScale = MIN_SCALE;
            }
            else if (scale > this.props.maxScale) {
                newScale = this.props.maxScale
            }
            else {
                newScale = scale;
            }
        }

        return newScale;
    }
}

//https://toddmotto.com/react-create-class-versus-component/
Camera.defaultProps = {

    scale: 1,

    emulation: false,
    emulationSrc: null,
    showDevices: true,

    maxScale: MAX_SCALE,

    style: {
        width: 480,
        height: 360
    },

    onCapture: null,
    onError: null
};<commit_msg>fixed problem with selecting/changing device<commit_after>import { throttle, merge  } from "lodash"
import { ImageCapture } from "../ImageCapture"
import React, { Component } from 'react'
import Slider from 'material-ui/Slider';

import Message from './message'
import Devices from './devices'
import Shutter from './shutter'
import CaptureButton from './captureButton'

const shutterSound = new Audio("./camera-shutter-click-01.wav")
const MAX_SCALE = 10
const MIN_SCALE = 1
const ZOOM_INCREMENT = .25

const cameraControlStyle = {
    width: 150,
    backgroundColor: "black"
}
const defaultCameraConstraint = {

    audio : false,
    video : {
        width : { min:680,ideal:1920},
        height : { min:480,ideal : 1080 }
    }
}

export default class Camera extends Component {

    constructor(props) {

        super(props)

        this.canvas = document.createElement('canvas')

        this.canvas2dContext = this.canvas.getContext('2d')

        this.msgSpan = null;
        this.video = null;
        this.state = {
            scale: this.validateScale(this.props.scale),
            showDevices: this.props.showDevices,
            devices: [],
            selectedDeviceId: null,
            width: this.props.style.width - cameraControlStyle.width,
            height: this.props.style.height,
            emulation: this.props.emulation,
            emulationSrc: this.props.emulationSrc,
            isCapturing: false

        } // using react state to track ui state; should stay here even after introducing redux?

        this._onCapture = throttle(this._onCapture.bind(this), 1000)
        this._onError = this._onError.bind(this)

        this.changeDevice = this.changeDevice.bind(this)
        this.zoomIn = this.zoomIn.bind(this)
        this.zoomOut = this.zoomOut.bind(this)
        this.zoomChange = this.zoomChange.bind(this)

        this.getUserMedia = this.getUserMedia.bind(this)
    }

    render() {

        let cameraStyle = {
            width: this.state.width,
            height: this.state.height,
            overflow: "hidden",
            display: "flex",
            position: "relative",
            backgroundColor: "black"
        }

        let videoStyle = Object.assign({}, {
            position: "absolute",
            margin: 'auto',
            top: '50%',
            left: '50%'
        }, { WebkitTransform: "translate(-50%,-50%)scale(" + this.state.scale + ")", width: this.state.width, height: this.state.height })

        let sliderValue = (this.state.scale - MIN_SCALE) / (this.props.maxScale - MIN_SCALE)
        let sliderHeight = (this.state.height - 80)

        return (

                            <video style={videoStyle}
                                ref={vid => { this.video = vid }}

                            />

                            {
                                this.state.showDevices && <Devices devices={this.state.devices} style={{ margin: 20 }} onClick={this.changeDevice} />
                            }

                                {this.state.emulation && <Message msg="Emulation Mode" permanent={true} />}
                                <Message msg={Math.round(this.state.scale * 100) / 100 + "X"} />

                            <Shutter display={this.state.isCapturing} style={{ width: this.state.width, height: this.state.height }} />

                            <CaptureButton onClick={this._onCapture} />

                                <button onClick={this.zoomIn}>+</button>
                                <Slider style={{ height: sliderHeight, marginTop: 10, marginBottom: 10, display: "flex", justifyContent: "center" }} sliderStyle={{ marginTop: 0, marginBottom: 0 }} axis="y" value={sliderValue} defaultValue={sliderValue} onChange={this.zoomChange} />
                                <button onClick={this.zoomOut}>-</button>

        )
    }

    componentWillReceiveProps(props) {
        if (this.video && this.video.videoHeight > 0) {
            let dimension = this.adjustAspectRatio(this.video.videoWidth, this.video.videoHeight, props.style.width)
            this.setState(dimension)
        }

    }
    componentWillMount() {

    }

    componentDidMount() {

        let ctx = this;
        this.getDeviceList().then(deviceList => {
            ctx.setState({ devices: deviceList || [] })
            ctx.loadDefaultDevice(deviceList)

        })

    }

    _onCapture(e) {

        let ctx = this;

        //calculate image dimension based on scale

        let dx = (this.video.videoWidth / this.state.scale)
        let dy = (this.video.videoHeight / this.state.scale)

        let x1 = (this.video.videoWidth - dx) / 2;
        let y1 = (this.video.videoHeight - dy) / 2;

        this.canvas2dContext.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.canvas2dContext.drawImage(this.video, x1, y1, dx, dy, 0, 0, this.canvas.width, this.canvas.height)

        let img = this.canvas.toDataURL('image/png');

        this.setState({ isCapturing: true }, () => {

            if (ctx.props.onCapture) {
                ctx.props.onCapture(e, img)
            }

            if ("vibrate" in navigator) {
                navigator.vibrate(100)
            }
            shutterSound.play().then(() => {
                this.setState({ isCapturing: false })
            })

        })
    }

    _onError(err) {
        if (this.props.onError) {
            this.props.onError(err)
        }
        else {
            console.error(err)
        }
    }

    zoomIn() {
        let currentScale = this.state.scale
        let newScale = currentScale + ZOOM_INCREMENT;
        if (newScale > this.props.maxScale) {
            newScale = this.props.maxScale;
        }
        this.setState({ scale: this.validateScale(newScale) })

    }
    zoomOut() {

        let currentScale = this.state.scale
        let newScale = currentScale - ZOOM_INCREMENT;
        if (newScale < MIN_SCALE) {
            newScale = MIN_SCALE;
        }
        this.setState({ scale: this.validateScale(newScale) })
    }

    zoomChange(e, newValue) {

        let newScale = MIN_SCALE + (newValue) * (this.props.maxScale - MIN_SCALE)

        this.setState({ scale: this.validateScale(newScale) })
    }

    adjustAspectRatio(videoWidth, videoHeight, width) {
        let dimension = { height: width * videoHeight / videoWidth, width }
        return dimension
    }

    setCanvasDimension(videoWidth, videoHeight, width) {
        this.canvas.width = videoWidth
        this.canvas.height = videoHeight
    }

    getDeviceList() {

        let ctx = this

        let deviceList = null;
        let filter = (item) => { return (item.kind === "video" || item.kind === "videoinput"); };
        let sort = (a, b) => {

            let labelA = (a.label || "").toLowerCase()
            let labelB = (b.label || "").toLowerCase()

            let isARearCamera = (labelA.indexOf("rear") >= 0)
            let isBRearCamera = (labelB.indexOf("rear") >= 0)

            let returnVal = 0

            if (isARearCamera === isBRearCamera) {
                returnVal = (labelA < labelB) ? -1 : ((labelA > labelB) ? 1 : 0)
            }
            else if (isARearCamera && !isBRearCamera) {
                returnVal = -1
            }
            else {
                returnVal = 1
            }
            return returnVal
        }

        let handleDeviceReceived = (sourceList) => {
            deviceList = sourceList || []
            deviceList = deviceList.filter(filter)
            deviceList = deviceList.sort(sort)

            if (!deviceList.find(item => { return item.kind === "emulation" })) {
                deviceList.push(this.getEmulationDeviceInfo())
            }

            return Promise.resolve(deviceList)

        }
        try {
            if (navigator.mediaDevices.enumerateDevices) {
                return navigator.mediaDevices.enumerateDevices().then(handleDeviceReceived).catch(ctx._onError)
            }
            else if (MediaStreamTrack && MediaStreamTrack.getSources) {
                return MediaStreamTrack.getSources(handleDeviceReceived, ctx._onError);
            }
            else {
                return Promise.reject(false)
            }
        }
        catch (err) {
            this._onError(err)
            return Promise.reject(false)
        }

    }

    changeDevice(sourceId) {

        let ctx = this;
        //override device
        if (sourceId) {

            if (sourceId == 1) {
                //emulation
                this.setState({ emulation: true }, () => {
                    ctx.getUserMedia()
                })
            }
            else {
                this.setState({ emulation: false }, () => {

                    let constraints = merge({},defaultCameraConstraint, { video : { deviceId : { exact : sourceId}} });

                    ctx.getUserMedia(constraints)
                })
            }
        }
    }

    getVideoCapabilities(videoTrack) {

        let capabilities = videoTrack.getCapabilities();

        if (capabilities.zoom) {
            console.log("hardware zoom supportd")
        }
        if (capabilities.focusDistance) {
            console.log("focus supportd")
        }

        if (typeof ImageCapture !== 'undefined') {
            try {
                //experimental
                console.log("ImageCapture supported")
                let imageCapture = new ImageCapture(videoTrack)

                let photoCapabilities = imageCapture.getPhotoCapabilities().then(c => {
                    console.dir(c)
                })
                if (navigator.mediaDevices.getSupportedConstraints) {
                    let c = navigator.mediaDevices.getSupportedConstraints();
                    console.dir(c)
                }

            }
            catch (err) {
                //ignore
            }

        }
    }

    loadEmulationVideo(video) {

        video.src = this.state.emulationSrc;
        video.muted = true
        if (typeof video.loop == 'boolean') {
            // loop supported
            video.loop = true;
        }
    }
    handleVideoMetaDataLoaded(video, e) {
        let ctx = this
        video.play().then(() => {
            ctx.setCanvasDimension(video.videoWidth, video.videoHeight)
            let dimension = ctx.adjustAspectRatio(video.videoWidth, video.videoHeight, ctx.state.width)
            ctx.setState(dimension)
        }).catch(ctx._onError)
    }

    bindVideoEventHandlers(video) {
        if (!video) return;
        video.onabort = (e) => {
            console.log("video aborted", e)
        }
        video.onactivate = (e) => {
            console.log("video actived", e)
        }
        video.onclose = e => {
            console.log("video closed", e)
        }
        video.onerror = (e) => {
            this._onError(e)
        }
    }

    bindStreamEventHandlers(stream) {

        if (!stream) return;

        stream.oninactive = e => {
            console.log('Stream inactive', e);
        };
        stream.onactive = (e) => {
            console.log("Stream active", e)
        }
        stream.oneded = e => {
            console.log("Stream ended", e)
        }

    }

    handleStreamReceived(constraints, stream) {
        let videoTracks = null;
        let video = this.video;
        let ctx = this;
        //stop existing videotracks
        if (video.srcObject) {
            video.srcObject.getVideoTracks().forEach(track => track.stop())
            video.srcObject = null;
        }

        if (stream && stream.getVideoTracks) {
            videoTracks = stream.getVideoTracks();

            if (videoTracks.length > 0 && videoTracks[0].getCapabilities) {
                console.log(videoTracks[0].label)
                this.getVideoCapabilities(videoTracks[0])
            }
        }

        if (this.state.emulation) {
            //emulation?
            this.loadEmulationVideo(video)

        }
        else if (stream instanceof MediaStream) {
            video.src = null;
            video.srcObject = stream
        }
        else {

            //this should not reach, but just in case..
            this.setState({ emulation: true })
            this.loadEmulationVideo(video)
        }

        this.bindVideoEventHandlers(video)
        this.bindStreamEventHandlers(stream)
        video.onloadedmetadata =  (e)=> {
            return this.handleVideoMetaDataLoaded(video,e)
        }

    }

    loadDefaultDevice(deviceList) {

        let constraints = merge({},defaultCameraConstraint, { video : deviceList && deviceList.length > 0 ? { deviceId :  { exact : deviceList[0].deviceId } } :{} });

        // if (deviceList && deviceList.length > 0) {
        //     constraints.video =  Object.assign( {},constraints.video, { optional : [ { sourceId: deviceList[0].deviceId },{minAspectRatio:1.6}] }  )
        // }

        this.getUserMedia(constraints)
    }

    getUserMedia(constraints) {

        try {
            let getUserMedia;
            let ctx;

            if (!constraints) {
                constraints = {
                    audio: false,
                    video: { facingMode: "environment", width: 1920, height: 1080 }
                }
            }

            if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
                getUserMedia = navigator.mediaDevices.getUserMedia;
                ctx = navigator.mediaDevices;
            }
            else if (navigator.getUserMedia) {
                getUserMedia = navigator.getUserMedia
                ctx = navigator;
            }
            else if (navigator.webkitGetUserMedia) {
                getUserMedia = navigator.webkitGetUserMedia
                ctx = navigator
            }
            else {
                getUserMedia = this.getUserMediaEmulation;
                ctx = this
            }
            //manually set the context to wherever the function belongs to, otherwise will get illegal invcation error
            return getUserMedia.call(ctx, constraints).then(this.handleStreamReceived.bind(this, constraints)).catch(this._onError);

        }
        catch (ex) {
            this._onError(ex)
        }
    }

    getEmulationDeviceInfo() {
        return {
            id: 1,
            deviceId: 1,
            label: "emulation",
            kind: "emulation",
            emulation: true,
            selected: false
        }
    }

    getUserMediaEmulation() {

        return new Promise((resolve, reject) => {
            this.setState({ emulation: true }, () => {

                resolve(false);//no MediaStream
            })
        })
    }

    validateScale(scale) {
        let newScale = MIN_SCALE;

        if (scale) {
            if (scale < MIN_SCALE) {
                newScale = MIN_SCALE;
            }
            else if (scale > this.props.maxScale) {
                newScale = this.props.maxScale
            }
            else {
                newScale = scale;
            }
        }

        return newScale;
    }
}

//https://toddmotto.com/react-create-class-versus-component/
Camera.defaultProps = {

    scale: 1,

    emulation: false,
    emulationSrc: null,
    showDevices: true,

    maxScale: MAX_SCALE,

    style: {
        width: 480,
        height: 360
    },

    onCapture: null,
    onError: null
};<|endoftext|>


<commit_before>/*
 * Copyright 2016 e-UCM (http://www.e-ucm.es/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * This project has received funding from the European Union's Horizon
 * 2020 research and innovation programme under grant agreement No 644187.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0 (link is external)
 *
 * 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.
 */

'use strict';

var Path = require('path');
var config = require(Path.resolve(__dirname, '../config.js'));
var index = require(Path.resolve(__dirname, '../lib/kibana/defaultIndex.js'));
var visualizationArray = require(Path.resolve(__dirname, '../lib/kibana/defaultVisualizations.js'));
var elasticsearch = require('elasticsearch');

var esClient = new elasticsearch.Client({
    host: config.elasticsearch.uri,
    api: '5.0'
});

esClient.ping({
    // Ping usually has a 3000ms timeout
    requestTimeout: 3000
}, function (error) {
    if (error) {
        console.trace('elasticsearch cluster is down!');
    } else {
        console.log('Successfully connected to elasticsearch: ' + config.elasticsearch.uri);
        setupIndexTemplate();
        setupVisualizationTemplates();
    }
});

var setupIndexTemplate = function () {
    esClient.index({
        index: '.template',
        type: 'index',
        id: index.title,
        body: index
    }, function (error, response) {
        if (!error) {
            console.log('Added Index template.');
        } else {
            return handleError(error);
        }
    });
};

var setupVisualizationTemplates = function() {
    visualizationArray.forEach(function (visualization) {
        esClient.search({
            index: '.template',
            q: '_id:' + visualization.title
        }, function (error, response) {
            if (!error) {

                if (response.hits && response.hits.total > 0) {
                    console.log('Visualization template named:' + visualization.title + 'already exist, updating...');
                }

                esClient.index({
                    id: visualization.title,
                    index: '.template',
                    type: 'visualization',
                    body: visualization
                }, function (error, response) {
                    if (!error) {
                        console.log('Added Visualization template named: ' + visualization.title);
                    } else {
                        return handleError(error);
                    }
                });

            } else {
                handleError(error);
            }
        });
    });
};

var handleError = function(error) {
    console.error(error);
    console.error('Could not connect to ElasticsearchDB!');
    process.exit(0);
};<commit_msg>Added minor fix<commit_after>/*
 * Copyright 2016 e-UCM (http://www.e-ucm.es/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * This project has received funding from the European Union's Horizon
 * 2020 research and innovation programme under grant agreement No 644187.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0 (link is external)
 *
 * 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.
 */

'use strict';

var Path = require('path');
var config = require(Path.resolve(__dirname, '../config.js'));
var index = require(Path.resolve(__dirname, '../lib/kibana/defaultIndex.js'));
var visualizationArray = require(Path.resolve(__dirname, '../lib/kibana/defaultVisualizations.js'));
var elasticsearch = require('elasticsearch');

var esClient = new elasticsearch.Client({
    host: config.elasticsearch.uri,
    api: '5.0'
});

esClient.ping({
    // Ping usually has a 3000ms timeout
    requestTimeout: 3000
}, function (error) {
    if (error) {
        console.trace('elasticsearch cluster is down!');
    } else {
        console.log('Successfully connected to elasticsearch: ' + config.elasticsearch.uri);
        setupIndexTemplate();
        setupVisualizationTemplates();
    }
});

var setupIndexTemplate = function () {
    esClient.index({
        index: '.template',
        type: 'index',
        id: index.title,
        body: index
    }, function (error, response) {
        if (!error) {
            console.log('Added Index template.');
        } else {
            return handleError(error);
        }
    });
};

var setupVisualizationTemplates = function() {
    visualizationArray.forEach(function (visualization) {
        esClient.search({
            index: '.template',
            q: '_id:' + visualization.title
        }, function (error, response) {
            if (response && response.hits && response.hits.total > 0) {
                console.log('Visualization template named:' + visualization.title + 'already exist, updating...');
            }

            esClient.index({
                id: visualization.title,
                index: '.template',
                type: 'visualization',
                body: visualization
            }, function (error, response) {
                if (!error) {
                    console.log('Added Visualization template named: ' + visualization.title);
                } else {
                    return handleError(error);
                }
            });
        });
    });
};

var handleError = function(error) {
    console.error(error);
    console.error('Could not connect to ElasticsearchDB!');
    process.exit(0);
};<|endoftext|>


<commit_before>var disp = document.getElementById('text-disp-div');
var tarea = document.getElementById('textarea-div');
var icon_group = document.getElementById('textarea-icon-group');

tarea.addEventListener('input', function (evt) {
    disp.innerHTML = window.marked(tarea.innerText);
    window.renderMathInElement(disp);
});

// Button click handlers
icon_group.addEventListener('click', function(event) {
    // we care about two targets. Either on the button or on the span inside button
    // Otherwise we don't take any action
    var target_node = event.target;
    if (target_node.tagName !== 'BUTTON')
        target_node = target_node.parentElement;

    if (target_node.id) { // insert markdown only for valid buttons with an id
		// create a new text node to insert at the caret position
		var node = document.createTextNode('');
		// Get the selected text
		tarea.focus();
		var sel = window.getSelection();
		var range = sel.getRangeAt(0);
		var selected_text = range.toLocaleString();
		if (!selected_text)
			selected_text = 'Text';
		// To replace the selected text, delete it first
		range.deleteContents();

		switch(target_node.id) {
			case 'bold':
				node.textContent = '**'+ selected_text +'**';
				break;
			case 'italic':
				node.textContent = '*'+ selected_text +'*';
		}

		// Then add the new content
		range.insertNode(node);
		// Select the new content
		var new_range = document.createRange();
		//new_range.selectNodeContents(node); // selcts all including ** **
		new_range.setStart(node, 1);
		new_range.setEnd(node, selected_text.length+1);
		sel.removeAllRanges();
		sel.addRange(new_range);

	}
})

<commit_msg>Re-render after bold or italic buttons are pressed. Refractor event handler to a separate function and call it.<commit_after>var disp = document.getElementById('text-disp-div');
var tarea = document.getElementById('textarea-div');
var icon_group = document.getElementById('textarea-icon-group');

function re_render() {
	disp.innerHTML = window.marked(tarea.innerText);
    window.renderMathInElement(disp);
}

tarea.addEventListener('input', function (evt) {
    re_render();
});

// Button click handlers
icon_group.addEventListener('click', function(event) {
    // we care about two targets. Either on the button or on the span inside button
    // Otherwise we don't take any action
    var target_node = event.target;
    if (target_node.tagName !== 'BUTTON')
        target_node = target_node.parentElement;

    if (target_node.id) { // insert markdown only for valid buttons with an id
		// create a new text node to insert at the caret position
		var node = document.createTextNode('');
		// Get the selected text
		tarea.focus();
		var sel = window.getSelection();
		var range = sel.getRangeAt(0);
		var selected_text = range.toLocaleString();
		if (!selected_text)
			selected_text = 'Text';
		// To replace the selected text, delete it first
		range.deleteContents();

		switch(target_node.id) {
			case 'bold':
				node.textContent = '**'+ selected_text +'**';
				break;
			case 'italic':
				node.textContent = '*'+ selected_text +'*';
		}

		// Then add the new content
		range.insertNode(node);
		// Select the new content
		var new_range = document.createRange();
		//new_range.selectNodeContents(node); // selcts all including ** **
		new_range.setStart(node, 1);
		new_range.setEnd(node, selected_text.length+1);
		sel.removeAllRanges();
		sel.addRange(new_range);

		// Finally call the event handler for input change
		re_render();
	}
})

<|endoftext|>


<commit_before>/*

  Keyboard and mouse enabled horizontal screen
  scrolling plugin, with automatic realignment.

  Written in 2013 by Suraj N. Kurapati for
  Readably https://github.com/sunaku/readably
  and thus distributed under the ISC license.

  Requires: jQuery 1.2.6 or newer
  http://docs.jquery.com/Release:jQuery_1.2.6

  Optional: jquery-mousewheel 3.1.3 or newer
  https://github.com/brandonaaron/jquery-mousewheel

*/
$(function() {

  // Scrolls the screen horizontally to the given location, which can be
  // an absolute pixel offset (number) or one of the following (string):
  //
  // 'left':  if not aligned, scroll to start of current page;
  //          otherwise, scroll to start of previous page
  //
  // 'right': scroll to start of next page
  //
  // 'align': if beyond half of current page, scroll to start of next page;
  //          otherwise, scroll to start of current page
  //
  // In either case, the screen will be left-aligned to a page boundary.
  //
  function horizoll(where) {
    var start = typeof where === 'number' ? where : $(document).scrollLeft();
    var limit = $('html').width();
    var depth = start % limit;
    var space = limit - depth;
    switch (where) {
      case 'left' : where = start - (depth > 0 ? depth : limit); break;
      case 'right': where = start + (depth > 0 ? space : limit); break;
      case 'align': if (depth >= space) { where = start + space; break; }
      default     : where = start - depth; // ELSE for above IF falls through
    }
    $('body, html').animate({ scrollLeft: where });
  }

  // Aligns the screen to the nearest page boundary
  // while ensuring that any hash target is visible.
  function realign() {
    var target = $(':target');
    if (target.length) {
      horizoll(target.offset().left);
    }
    else {
      horizoll('align');
    }
  }

  // Tests whether the given event qualifies as a cause for scrolling.
  function qualify(event) {
    return !(
      // event originated from a form input field, so don't interfere:
      // the user is probably trying to enter text or scroll the field
      event.target.hasOwnProperty('form') ||

      // browser could not fit document vertically into window so don't
      // interfere with user's ability to scroll the document normally
      $(document).height() > $(window).height() ||

      // browser was able to fit document horizontally into window, so
      // scrolling is unnecessary: there's nothing here to be scrolled!
      $(document).width() < $(window).width()
    );
  }

  // traverse page boundaries using the keyboard
  $(document).bind('keydown', function(event) {
    if (qualify(event)) {
      switch (event.keyCode) {
        case 8: // backspace
        case 33: // page up
        case 37: // left arrow
        case 38: // up arrow
          horizoll('left');
          break;

        case 32: // space bar
        case 34: // page down
        case 39: // right arrow
        case 40: // down arrow
          horizoll('right');
          break;

        case 36: // home key
          horizoll(0);
          break;

        case 35: // end key
          horizoll($(document).width());
          break;
      }
    }
  });

  // traverse page boundaries using the mouse wheel
  $(document).bind('mousewheel', function(event, delta, deltaX, deltaY) {
    if (qualify(event) && delta !== 0 && deltaX === 0) {
      horizoll(deltaY > 0 ? 'left' : 'right');
    }
  });

  // automatically realign to nearest page boundary
  $(window).bind('resize', realign);
  setTimeout(realign, 500);

});
<commit_msg>jslint wants a single `var` keyword per function<commit_after>/*

  Keyboard and mouse enabled horizontal screen
  scrolling plugin, with automatic realignment.

  Written in 2013 by Suraj N. Kurapati for
  Readably https://github.com/sunaku/readably
  and thus distributed under the ISC license.

  Requires: jQuery 1.2.6 or newer
  http://docs.jquery.com/Release:jQuery_1.2.6

  Optional: jquery-mousewheel 3.1.3 or newer
  https://github.com/brandonaaron/jquery-mousewheel

*/
$(function() {

  // Scrolls the screen horizontally to the given location, which can be
  // an absolute pixel offset (number) or one of the following (string):
  //
  // 'left':  if not aligned, scroll to start of current page;
  //          otherwise, scroll to start of previous page
  //
  // 'right': scroll to start of next page
  //
  // 'align': if beyond half of current page, scroll to start of next page;
  //          otherwise, scroll to start of current page
  //
  // In either case, the screen will be left-aligned to a page boundary.
  //
  function horizoll(where) {
    var start = typeof where === 'number' ? where : $(document).scrollLeft(),
        limit = $('html').width(),
        depth = start % limit,
        space = limit - depth;

    switch (where) {
      case 'left' : where = start - (depth > 0 ? depth : limit); break;
      case 'right': where = start + (depth > 0 ? space : limit); break;
      case 'align': if (depth >= space) { where = start + space; break; }
                    // else fall through
      default     : where = start - depth;
    }

    $('body, html').animate({ scrollLeft: where });
  }

  // Aligns the screen to the nearest page boundary
  // while ensuring that any hash target is visible.
  function realign() {
    var target = $(':target');
    if (target.length) {
      horizoll(target.offset().left);
    }
    else {
      horizoll('align');
    }
  }

  // Tests whether the given event qualifies as a cause for scrolling.
  function qualify(event) {
    return !(
      // event originated from a form input field, so don't interfere:
      // the user is probably trying to enter text or scroll the field
      event.target.hasOwnProperty('form') ||

      // browser could not fit document vertically into window so don't
      // interfere with user's ability to scroll the document normally
      $(document).height() > $(window).height() ||

      // browser was able to fit document horizontally into window, so
      // scrolling is unnecessary: there's nothing here to be scrolled!
      $(document).width() < $(window).width()
    );
  }

  // traverse page boundaries using the keyboard
  $(document).bind('keydown', function(event) {
    if (qualify(event)) {
      switch (event.keyCode) {
        case 8: // backspace
        case 33: // page up
        case 37: // left arrow
        case 38: // up arrow
          horizoll('left');
          break;

        case 32: // space bar
        case 34: // page down
        case 39: // right arrow
        case 40: // down arrow
          horizoll('right');
          break;

        case 36: // home key
          horizoll(0);
          break;

        case 35: // end key
          horizoll($(document).width());
          break;
      }
    }
  });

  // traverse page boundaries using the mouse wheel
  $(document).bind('mousewheel', function(event, delta, deltaX, deltaY) {
    if (qualify(event) && delta !== 0 && deltaX === 0) {
      horizoll(deltaY > 0 ? 'left' : 'right');
    }
  });

  // automatically realign to nearest page boundary
  $(window).bind('resize', realign);
  setTimeout(realign, 500);

});
<|endoftext|>


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

var { log } = Components.utils.import('resource://auto-confirm-resources/modules/log.js', {});

var gRule;
var gMessages;
var gActions;

function init() {
  gRule = window.arguments[0] || {};
  if (gRule.name) {
    let title = document.documentElement.getAttribute('title-template');
    document.title = title.replace(/%s/i, gRule.name);
  }

  gMessages = document.getElementById('messages');
  gActions = document.getElementById('actions');

  Object.keys(gRule).forEach(function(aKey) {
    var value = gRule[aKey];
    var field = document.getElementById(aKey + '-field');
    if (field && value)
      field.value = value;
  });

  var actions = [];
  if (gRule.actions) {
    actions = JSON.parse(gRule.actions);
  } else if (gRule.action) {
    actions = [gRule.action];
  }

  actions.forEach(actionAdd);

  onGroupChanged();
  validateName();
}

function validateName() {
  var nameField = document.getElementById('name-field');
  var name = nameField.value;
  var accept = document.documentElement.getButton('accept');
  if (window.opener.isRuleDuplicated(name, gRule)) {
    accept.setAttribute('disabled', true);
    document.documentElement.setAttribute('validation-errors', 'duplicated-name');
    return false;
  } else if (name.trim() === '') {
    accept.setAttribute('disabled', true);
    document.documentElement.setAttribute('validation-errors', 'blank-name');
    return false;
  } else {
    accept.removeAttribute('disabled');
    document.documentElement.removeAttribute('validation-errors');
    return true;
  }
}

function onGroupChanged() {
  var group = document.getElementById('group-field').value;
  document.documentElement.setAttribute('group-type', group);
}

function captureActualOperation(aAction) {
  let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                          .getService(Components.interfaces.nsIPromptService);
  let type = document.getElementById('type-field');
  log(type.value);

  let title = gMessages.getString('config.edit.capture.dialog.title');
  let description = gMessages.getString('config.edit.capture.dialog.description');
  let checkboxLabel = gMessages.getString('config.edit.capture.dialog.checkbox');
  let checked = {value: false};

  switch (type.value) {
  case 'alert':
    {
      prompts.alertCheck(window,
                         title,
                         description,
                         checkboxLabel,
                         checked);
      log('checked: ' + checked);
      if (checked.value) {
        actionAdd('check');
      }
      actionAdd('accept');
    }
    break;
  case 'confirm':
    {
      let result = prompts.confirmCheck(window,
                                        title,
                                        description,
                                        checkboxLabel,
                                        checked);
      log('result: ' + result);
      log('checked: ' + checked);
      if (checked.value) {
        actionAdd('check');
      }
      if (result) {
        actionAdd('accept');
      } else {
        actionAdd('cancel');
      }
    }
    break;
  case 'confirmEx':
    {
      let buttonLabels = [];
      buttonLabels[0] = gMessages.getString('config.edit.capture.dialog.button.0');
      buttonLabels[1] = gMessages.getString('config.edit.capture.dialog.button.1');
      buttonLabels[2] = gMessages.getString('config.edit.capture.dialog.button.2');
      let flags = prompts.BUTTON_POS_0 * prompts.BUTTON_TITLE_IS_STRING +
                  prompts.BUTTON_POS_1 * prompts.BUTTON_TITLE_IS_STRING  +
                  prompts.BUTTON_POS_2 * prompts.BUTTON_TITLE_IS_STRING;
      let pressedButtonIndex = prompts.confirmEx(window,
                                                 title,
                                                 description,
                                                 flags,
                                                 buttonLabels[0],
                                                 buttonLabels[1],
                                                 buttonLabels[2],
                                                 null,
                                                 checked);
      log('pressedButtonIndex:' + pressedButtonIndex);
      log('checked: ' + checked);
      if (checked.value) {
        actionAdd('check');
      }
      actionAdd('push;' + buttonLabels[pressedButtonIndex]);
    }
    break;
  case 'prompt':
    {
      let inputMessage = {value: ''};
      let result = prompts.prompt(window,
                                  title,
                                  description,
                                  inputMessage,
                                  checkboxLabel,
                                  checked);
      log('result:' + result);
      log('inputMessage: ' + inputMessage);
      log('checked: ' + checked);
      if (inputMessage.value) {
        actionAdd('input;' + inputMessage.value);
      }
      if (checked.value) {
        actionAdd('check');
      }
      if (result) {
        actionAdd('accept');
      } else {
        actionAdd('cancel');
      }
    }
    break;
  case 'select':
    // TODO
    //select();
    break;
  }
}

function actionAdd(aAction) {
  var template = document.getElementById('action-item-template');
  var item = template.cloneNode(true);
  item.removeAttribute('id');
  gActions.insertBefore(item, gActions.lastChild);

  aAction = aAction || '';
  var matched = aAction.match(/^([^;]+)(?:;(.*)$)?/);
  if (!matched)
    return;

  var name = matched[1];
  var params = matched[2];
  if (name)
    item.querySelector('.action-name-field').value = name;
  if (params)
    item.querySelector('.action-params-field').value = params;
}

function actionUp(aItem) {
  if (aItem == gActions.firstChild)
    return;
  gActions.insertBefore(aItem, aItem.previousSibling);
}

function actionDown(aItem) {
  if (aItem.nextSibling == gActions.lastChild)
    return;
  gActions.insertBefore(aItem, aItem.nextSibling.nextSibling);
}

function actionDelete(aItem) {
  gActions.removeChild(aItem);
}

function serializeAction(aItem) {
  var nameField = aItem.querySelector('.action-name-field');
  var paramsField = aItem.querySelector('.action-params-field');
  if (paramsField.clientWidth > 0 &&
      paramsField.clientHeight > 0 &&
      paramsField.value) {
    return nameField.value + ';' + paramsField.value;
  } else {
    return nameField.value;
  }
}

function onAccept() {
  ['name',
   'group',
   'type',
   'url',
   'title',
   'text'].forEach(function(aProperty) {
    gRule[aProperty] = document.getElementById(aProperty + '-field').value;
  });
  switch (gRule.group) {
  case 'common':
    gRule.url = '';
    break;
  case 'general':
    gRule.type = '';
    break;
  }

  var actions = document.querySelectorAll('#actions richlistitem.action');
  if (actions.length === 0) {
    gRule.actions = gRule.action = '';
  } else if (actions.length == 1) {
    gRule.actions = '';
    gRule.action = serializeAction(actions[0]);
  } else {
    gRule.action = '';
    gRule.actions = JSON.stringify(Array.map(actions, serializeAction));
  }

  gRule.changed = true;

  return true;
}
<commit_msg>Improve debug print<commit_after>/*
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

var { log } = Components.utils.import('resource://auto-confirm-resources/modules/log.js', {});

var gRule;
var gMessages;
var gActions;

function init() {
  gRule = window.arguments[0] || {};
  if (gRule.name) {
    let title = document.documentElement.getAttribute('title-template');
    document.title = title.replace(/%s/i, gRule.name);
  }

  gMessages = document.getElementById('messages');
  gActions = document.getElementById('actions');

  Object.keys(gRule).forEach(function(aKey) {
    var value = gRule[aKey];
    var field = document.getElementById(aKey + '-field');
    if (field && value)
      field.value = value;
  });

  var actions = [];
  if (gRule.actions) {
    actions = JSON.parse(gRule.actions);
  } else if (gRule.action) {
    actions = [gRule.action];
  }

  actions.forEach(actionAdd);

  onGroupChanged();
  validateName();
}

function validateName() {
  var nameField = document.getElementById('name-field');
  var name = nameField.value;
  var accept = document.documentElement.getButton('accept');
  if (window.opener.isRuleDuplicated(name, gRule)) {
    accept.setAttribute('disabled', true);
    document.documentElement.setAttribute('validation-errors', 'duplicated-name');
    return false;
  } else if (name.trim() === '') {
    accept.setAttribute('disabled', true);
    document.documentElement.setAttribute('validation-errors', 'blank-name');
    return false;
  } else {
    accept.removeAttribute('disabled');
    document.documentElement.removeAttribute('validation-errors');
    return true;
  }
}

function onGroupChanged() {
  var group = document.getElementById('group-field').value;
  document.documentElement.setAttribute('group-type', group);
}

function captureActualOperation(aAction) {
  let prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                          .getService(Components.interfaces.nsIPromptService);
  let type = document.getElementById('type-field');
  log(type.value);

  let title = gMessages.getString('config.edit.capture.dialog.title');
  let description = gMessages.getString('config.edit.capture.dialog.description');
  let checkboxLabel = gMessages.getString('config.edit.capture.dialog.checkbox');
  let checked = {value: false};

  switch (type.value) {
  case 'alert':
    {
      prompts.alertCheck(window,
                         title,
                         description,
                         checkboxLabel,
                         checked);
      log('checked: ' + checked.value);
      if (checked.value) {
        actionAdd('check');
      }
      actionAdd('accept');
    }
    break;
  case 'confirm':
    {
      let result = prompts.confirmCheck(window,
                                        title,
                                        description,
                                        checkboxLabel,
                                        checked);
      log('result: ' + result);
      log('checked: ' + checked.value);
      if (checked.value) {
        actionAdd('check');
      }
      if (result) {
        actionAdd('accept');
      } else {
        actionAdd('cancel');
      }
    }
    break;
  case 'confirmEx':
    {
      let buttonLabels = [];
      buttonLabels[0] = gMessages.getString('config.edit.capture.dialog.button.0');
      buttonLabels[1] = gMessages.getString('config.edit.capture.dialog.button.1');
      buttonLabels[2] = gMessages.getString('config.edit.capture.dialog.button.2');
      let flags = prompts.BUTTON_POS_0 * prompts.BUTTON_TITLE_IS_STRING +
                  prompts.BUTTON_POS_1 * prompts.BUTTON_TITLE_IS_STRING  +
                  prompts.BUTTON_POS_2 * prompts.BUTTON_TITLE_IS_STRING;
      let pressedButtonIndex = prompts.confirmEx(window,
                                                 title,
                                                 description,
                                                 flags,
                                                 buttonLabels[0],
                                                 buttonLabels[1],
                                                 buttonLabels[2],
                                                 null,
                                                 checked);
      log('pressedButtonIndex:' + pressedButtonIndex);
      log('checked: ' + checked.value);
      if (checked.value) {
        actionAdd('check');
      }
      actionAdd('push;' + buttonLabels[pressedButtonIndex]);
    }
    break;
  case 'prompt':
    {
      let inputMessage = {value: ''};
      let result = prompts.prompt(window,
                                  title,
                                  description,
                                  inputMessage,
                                  checkboxLabel,
                                  checked);
      log('result:' + result);
      log('inputMessage: ' + inputMessage.value);
      log('checked: ' + checked.value);
      if (inputMessage.value) {
        actionAdd('input;' + inputMessage.value);
      }
      if (checked.value) {
        actionAdd('check');
      }
      if (result) {
        actionAdd('accept');
      } else {
        actionAdd('cancel');
      }
    }
    break;
  case 'select':
    // TODO
    //select();
    break;
  }
}

function actionAdd(aAction) {
  var template = document.getElementById('action-item-template');
  var item = template.cloneNode(true);
  item.removeAttribute('id');
  gActions.insertBefore(item, gActions.lastChild);

  aAction = aAction || '';
  var matched = aAction.match(/^([^;]+)(?:;(.*)$)?/);
  if (!matched)
    return;

  var name = matched[1];
  var params = matched[2];
  if (name)
    item.querySelector('.action-name-field').value = name;
  if (params)
    item.querySelector('.action-params-field').value = params;
}

function actionUp(aItem) {
  if (aItem == gActions.firstChild)
    return;
  gActions.insertBefore(aItem, aItem.previousSibling);
}

function actionDown(aItem) {
  if (aItem.nextSibling == gActions.lastChild)
    return;
  gActions.insertBefore(aItem, aItem.nextSibling.nextSibling);
}

function actionDelete(aItem) {
  gActions.removeChild(aItem);
}

function serializeAction(aItem) {
  var nameField = aItem.querySelector('.action-name-field');
  var paramsField = aItem.querySelector('.action-params-field');
  if (paramsField.clientWidth > 0 &&
      paramsField.clientHeight > 0 &&
      paramsField.value) {
    return nameField.value + ';' + paramsField.value;
  } else {
    return nameField.value;
  }
}

function onAccept() {
  ['name',
   'group',
   'type',
   'url',
   'title',
   'text'].forEach(function(aProperty) {
    gRule[aProperty] = document.getElementById(aProperty + '-field').value;
  });
  switch (gRule.group) {
  case 'common':
    gRule.url = '';
    break;
  case 'general':
    gRule.type = '';
    break;
  }

  var actions = document.querySelectorAll('#actions richlistitem.action');
  if (actions.length === 0) {
    gRule.actions = gRule.action = '';
  } else if (actions.length == 1) {
    gRule.actions = '';
    gRule.action = serializeAction(actions[0]);
  } else {
    gRule.action = '';
    gRule.actions = JSON.stringify(Array.map(actions, serializeAction));
  }

  gRule.changed = true;

  return true;
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
/*
 * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved
 *
 * @licence SPM for NodeJS is free-to-use, proprietary software.
 * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext)
 * This source code may not be copied, reverse engineered, or altered for any purpose.
 * This source code is to be used exclusively by users and customers of Sematext.
 * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies.
 */
var fs = require('fs')
var ZipZipTop = require('zip-zip-top')
var zip = new ZipZipTop()
var config = require('spm-agent').Config
var util = require('util')
var os = require('os')
var path = require('path')

var systemInfo = {
  operatingSystem: os.type() + ', ' + os.platform() + ', ' + os.release() + ', ' + os.arch(),
  processVersions: process.versions,
  processEnvironment: process.env
}

var cfgDumpFileName = path.join(os.tmpdir(), 'spm-cfg-dump.txt')
fs.writeFileSync(cfgDumpFileName, util.inspect(config).toString() + '\nSystem-Info:\n' + util.inspect(systemInfo))
zip.folder(config.logger.dir)
var archFileName = path.join(os.tmpdir(), 'spm-diagnose.zip')
zip.writeToFile(archFileName)
console.log('SPM diagnostics info is in  ' + archFileName)
console.log('Please e-mail the file to support@sematext.com')
fs.unlink(cfgDumpFileName, function () {})
<commit_msg>Removed some SPM references<commit_after>#!/usr/bin/env node
/*
 * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved
 *
 * @licence SPM for NodeJS is free-to-use, proprietary software.
 * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext)
 * This source code may not be copied, reverse engineered, or altered for any purpose.
 * This source code is to be used exclusively by users and customers of Sematext.
 * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies.
 */
var fs = require('fs')
var ZipZipTop = require('zip-zip-top')
var zip = new ZipZipTop()
var config = require('spm-agent').Config
var util = require('util')
var os = require('os')
var path = require('path')

var systemInfo = {
  operatingSystem: os.type() + ', ' + os.platform() + ', ' + os.release() + ', ' + os.arch(),
  processVersions: process.versions,
  processEnvironment: process.env
}

var cfgDumpFileName = path.join(os.tmpdir(), 'spm-cfg-dump.txt')
fs.writeFileSync(cfgDumpFileName, util.inspect(config).toString() + '\nSystem-Info:\n' + util.inspect(systemInfo))
zip.folder(config.logger.dir)
var archFileName = path.join(os.tmpdir(), 'spm-diagnose.zip')
zip.writeToFile(archFileName)
console.log('Sematext diagnostics info is in  ' + archFileName)
console.log('Please e-mail the file to support@sematext.com')
fs.unlink(cfgDumpFileName, function () {})
<|endoftext|>


<commit_before>// Depends on primitives, js-object-additions
Canvas.MenuItem = function(text, fn) {
  this.text = text;
  this.fn = fn;
};

Canvas.ContextMenu = function(ctx, items, options) {
  // Private variables
  var self = this;
  var rct = null;

  var sFont = options.font;
  var sColor = options.color; // text colour
  var bAutomatic = !!options.automatic; // Link the context menu into the canvas' events. Default: false

  var width = 120; // TODO: setting, or calculate from widest element
  var border = 2;
  var textHeight = 12; // TODO: calculate this.
  var itemHeight = textHeight + 4;
  var oldmousedown = null;

  // Public attributes
  this.items = items;

  var itemAt = function(pos) {
    for(var i = 0; i < self.items.length; i++) {
      var itm = self.items[i];
      if(pos.isIn(itm.rct))
        return itm;
    }

    return null;
  };

  // In order to erase the menu: Save the canvas image before showing the menu, and restore it afterwards
  var imd = null;
  var save = function() {
    imd = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
  };
  var restore = function() {
    if(imd == null)
      return;
    ctx.putImageData(imd, 0, 0);
  };

  this.show = function(evt) {
    save();
    if(bAutomatic)
      ctx.canvas.onclick = self.onclick;
    var pos = evt.targetPosition().translate(ctx.translation);
    var height = self.items.length * itemHeight + border * 2;
    rct = r(pos.y - border, pos.x + width, pos.y + height, pos.x - border);
    ctx.fillStyle = '#f6f6f6'; // TODO: setting
    ctx.fillRect(rct.left, rct.top, rct.right - rct.left, rct.bottom - rct.top);
    ctx.strokeStyle = 'black'; // TODO: setting
    ctx.strokeRect(rct.left, rct.top, rct.right - rct.left, rct.bottom - rct.top);

    self.items.each(function(i, itm) {
      ctx.drawText(pos.translate(p(-border, -border - i * itemHeight - textHeight)), itm.text, sFont, sColor);
      itm.rct = r(pos.y + i * itemHeight, pos.x + width + border, pos.y + (i + 1) * itemHeight, pos.x + border);
    });
    return false;
  };
  if(bAutomatic)
    ctx.canvas.oncontextmenu = this.show;
  else // Stop the default context menu from appearing
    ctx.canvas.oncontextmenu = function() { return false; };

  this.hide = function() {
    rct = null;
    restore();
    if(options.onhide)
      options.onhide();
  };

  this.onclick = function(evt) {
    if(rct == null)
      return false;

    var pos = evt.targetPosition().translate(ctx.translation);
    var bHit = pos.isIn(rct);
    self.hide();
    if(!bHit)
      return false;

    return self.activateItemAt(pos);
  };

  this.activateItemAt = function(pos) {
    var itm = itemAt(pos);
    if(itm == null)
      return false;
    itm.fn();
    return true;
  };
};
<commit_msg>Hide the menu on show() if it's already showing.<commit_after>// Depends on primitives, js-object-additions
Canvas.MenuItem = function(text, fn) {
  this.text = text;
  this.fn = fn;
};

Canvas.ContextMenu = function(ctx, items, options) {
  // Private variables
  var self = this;
  var rct = null;

  var sFont = options.font;
  var sColor = options.color; // text colour
  var bAutomatic = !!options.automatic; // Link the context menu into the canvas' events. Default: false

  var width = 120; // TODO: setting, or calculate from widest element
  var border = 2;
  var textHeight = 12; // TODO: calculate this.
  var itemHeight = textHeight + 4;
  var oldmousedown = null;

  // Public attributes
  this.items = items;

  var itemAt = function(pos) {
    for(var i = 0; i < self.items.length; i++) {
      var itm = self.items[i];
      if(pos.isIn(itm.rct))
        return itm;
    }

    return null;
  };

  // In order to erase the menu: Save the canvas image before showing the menu, and restore it afterwards
  var imd = null;
  var save = function() {
    restore();
    imd = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
  };
  var restore = function() {
    if(imd == null)
      return;
    ctx.putImageData(imd, 0, 0);
  };

  this.show = function(evt) {
    save();
    if(bAutomatic)
      ctx.canvas.onclick = self.onclick;
    var pos = evt.targetPosition().translate(ctx.translation);
    var height = self.items.length * itemHeight + border * 2;
    rct = r(pos.y - border, pos.x + width, pos.y + height, pos.x - border);
    ctx.fillStyle = '#f6f6f6'; // TODO: setting
    ctx.fillRect(rct.left, rct.top, rct.right - rct.left, rct.bottom - rct.top);
    ctx.strokeStyle = 'black'; // TODO: setting
    ctx.strokeRect(rct.left, rct.top, rct.right - rct.left, rct.bottom - rct.top);

    self.items.each(function(i, itm) {
      ctx.drawText(pos.translate(p(-border, -border - i * itemHeight - textHeight)), itm.text, sFont, sColor);
      itm.rct = r(pos.y + i * itemHeight, pos.x + width + border, pos.y + (i + 1) * itemHeight, pos.x + border);
    });
    return false;
  };
  if(bAutomatic)
    ctx.canvas.oncontextmenu = this.show;
  else // Stop the default context menu from appearing
    ctx.canvas.oncontextmenu = function() { return false; };

  this.hide = function() {
    rct = null;
    restore();
    if(options.onhide)
      options.onhide();
  };

  this.onclick = function(evt) {
    if(rct == null)
      return false;

    var pos = evt.targetPosition().translate(ctx.translation);
    var bHit = pos.isIn(rct);
    self.hide();
    if(!bHit)
      return false;

    return self.activateItemAt(pos);
  };

  this.activateItemAt = function(pos) {
    var itm = itemAt(pos);
    if(itm == null)
      return false;
    itm.fn();
    return true;
  };
};
<|endoftext|>


<commit_before>var initial_script = "examples/asteroids.lua";

$(document).ready(function(){
	var nacl_module = null;
	var src = null;

	function main() {
		xhr = new XMLHttpRequest();
		xhr.open("GET", initial_script);
		xhr.onload = function (event) {
			// TODO check for failure
			start_game(xhr.responseText);
		}
		xhr.send();
	}

	function switch_screen(id) {
		$(".screen").css({ "z-index": 50 });
		$(".screen").animate({ opacity:0.0 }, { queue: false, duration: "slow" });
		$("#"+id).css({ "z-index": 60 });
		$("#"+id).animate({ opacity:1.0 }, { queue: false, duration: "slow" });
	}

	function start_game(_src) {
		if (nacl_module) {
			$(nacl_module).remove();
			nacl_module = null;
		}

		nacl_html = '<embed name="nacl_module"        \
		                    id="nacl_module"          \
		                    src="static/load81.nmf"   \
		                    type="application/x-nacl" \
		                    tabindex="-1" />';

		var e = document.createElement("embed");
		e.id = "nacl_module";
		e.name = "nacl_module";
		e.src = "static/load81.nmf";
		e.type="application/x-nacl";
		$("#play-screen").append(e);
		nacl_module = e;
		src = _src;
	}

	/*
	 * Native Client events
	 */

	function moduleDidStartLoad() {
		$("#status").html("Loading...");
		$("#status").show();
	}

	function moduleLoadProgress(event) {
		if (event.total != 0) {
			var load_percent = Math.round(100.0 * event.loaded / event.total);
			$("#status").html("Loading: " + load_percent + "%");
		}
	}

	function moduleLoadError() {
	}

	function moduleLoadAbort() {
	}

	function moduleDidLoad() {
		nacl_module.postMessage(src);
		switch_screen("play-screen");
		nacl_module.focus();
	}

	function moduleDidEndLoad() {
		var lastError = event.target.lastError;
		if (lastError != undefined && lastError != "") {
			$("#status").html(lastError)
		} else {
			$("#status").fadeOut("slow")
			switch_screen("play-screen");
		}
	}

	function handleMessage(message_event) {
		console.log(message_event.data);
	}

	var listener = document.getElementById('play-screen')
	listener.addEventListener('loadstart', moduleDidStartLoad, true);
	listener.addEventListener('progress', moduleLoadProgress, true);
	listener.addEventListener('error', moduleLoadError, true);
	listener.addEventListener('abort', moduleLoadAbort, true);
	listener.addEventListener('load', moduleDidLoad, true);
	listener.addEventListener('loadend', moduleDidEndLoad, true);
	listener.addEventListener('message', handleMessage, true);

	/*
	 * Menu buttons
	 */

	$("#play").click(function(event) {
		switch_screen("play-screen");
		if (nacl_module) {
			nacl_module.focus();
		}
	});

	$("#help").click(function(event) {
		switch_screen("help-screen");
	});

	$("#load").click(function(event) {
		switch_screen("load-screen");
	});

	$("#save").click(function(event) {
		// TODO
		alert("save!");
	});

	/*
	 * Load screen
	 */

	$("#uploader").change(function(event) {
		var file = event.target.files[0];
		var reader = new FileReader();
		reader.onload = function(evt) {
			console.log(["uploaded", evt]);
			var code = reader.result;
			start_game(code);
		};
		reader.readAsBinaryString(file);
	});

	main();
});
<commit_msg>nacl: fix autofocus of embed element<commit_after>var initial_script = "examples/asteroids.lua";

$(document).ready(function(){
	var nacl_module = null;
	var src = null;

	function main() {
		xhr = new XMLHttpRequest();
		xhr.open("GET", initial_script);
		xhr.onload = function (event) {
			// TODO check for failure
			start_game(xhr.responseText);
		}
		xhr.send();
	}

	function switch_screen(id) {
		$(".screen").css({ "z-index": 50 });
		$(".screen").animate({ opacity:0.0 }, { queue: false, duration: "slow" });
		$("#"+id).css({ "z-index": 60 });
		$("#"+id).animate({ opacity:1.0 }, { queue: false, duration: "slow" });
	}

	function start_game(_src) {
		if (nacl_module) {
			$(nacl_module).remove();
			nacl_module = null;
		}

		nacl_html = '<embed name="nacl_module"        \
		                    id="nacl_module"          \
		                    src="static/load81.nmf"   \
		                    type="application/x-nacl" \
		                    tabindex="-1" />';

		var e = document.createElement("embed");
		e.id = "nacl_module";
		e.name = "nacl_module";
		e.src = "static/load81.nmf";
		e.type = "application/x-nacl";
		e.tabIndex = -1;
		$("#play-screen").append(e);
		nacl_module = e;
		src = _src;
	}

	/*
	 * Native Client events
	 */

	function moduleDidStartLoad() {
		$("#status").html("Loading...");
		$("#status").show();
	}

	function moduleLoadProgress(event) {
		if (event.total != 0) {
			var load_percent = Math.round(100.0 * event.loaded / event.total);
			$("#status").html("Loading: " + load_percent + "%");
		}
	}

	function moduleLoadError() {
	}

	function moduleLoadAbort() {
	}

	function moduleDidLoad() {
		nacl_module.postMessage(src);
		switch_screen("play-screen");
		nacl_module.focus();
	}

	function moduleDidEndLoad() {
		var lastError = event.target.lastError;
		if (lastError != undefined && lastError != "") {
			$("#status").html(lastError)
		} else {
			$("#status").fadeOut("slow")
			switch_screen("play-screen");
		}
	}

	function handleMessage(message_event) {
		console.log(message_event.data);
	}

	var listener = document.getElementById('play-screen')
	listener.addEventListener('loadstart', moduleDidStartLoad, true);
	listener.addEventListener('progress', moduleLoadProgress, true);
	listener.addEventListener('error', moduleLoadError, true);
	listener.addEventListener('abort', moduleLoadAbort, true);
	listener.addEventListener('load', moduleDidLoad, true);
	listener.addEventListener('loadend', moduleDidEndLoad, true);
	listener.addEventListener('message', handleMessage, true);

	/*
	 * Menu buttons
	 */

	$("#play").click(function(event) {
		switch_screen("play-screen");
		if (nacl_module) {
			nacl_module.focus();
		}
	});

	$("#help").click(function(event) {
		switch_screen("help-screen");
	});

	$("#load").click(function(event) {
		switch_screen("load-screen");
	});

	$("#save").click(function(event) {
		// TODO
		alert("save!");
	});

	/*
	 * Load screen
	 */

	$("#uploader").change(function(event) {
		var file = event.target.files[0];
		var reader = new FileReader();
		reader.onload = function(evt) {
			console.log(["uploaded", evt]);
			var code = reader.result;
			start_game(code);
		};
		reader.readAsBinaryString(file);
	});

	main();
});
<|endoftext|>


<commit_before>/*
 * This file is part of the Spludo Framework.
 * Copyright (c) 2009 DracoBlue, http://dracoblue.net/
 *
 * Licensed under the terms of MIT License. For the full copyright and license
 * information, please see the LICENSE file in the root folder.
 */

var sys = require('sys');

var logWithPrefix = function(prefix, args) {
    var message = "null";
    if (args.length > 1) {
        message = sys.inspect(args);
    }

    if (args.length === 1) {
        message = (typeof args[0] === "string") ? args[0] : sys.inspect(args[0]);
    }

    sys.debug(prefix + ': ' + message);

}
/*
 * Log Levels:
 *
 *     6   <     5     <  4   <  3   <  2    <   1   <  0
 *   TRACE < DEBUG/LOG < INFO < WARN < ERROR < FATAL < OFF
 */

var log_configuration = config.get(
    "logging", {
        "level": 3
    }
);

var doNotLog = function() {}

Logging = function() {};

Logging.LEVEL_TRACE = 6;
Logging.LEVEL_LOG = 5;
Logging.LEVEL_DEBUG = 5;
Logging.LEVEL_INFO = 4;
Logging.LEVEL_WARN = 3;
Logging.LEVEL_ERROR = 2;
Logging.LEVEL_FATAL = 1;
Logging.LEVEL_ALL = 0;

if (log_configuration.level >= Logging.LEVEL_TRACE) {
    Logging.prototype.trace = function() {
        logWithPrefix("TRACE", arguments);
    }
} else {
    Logging.prototype.trace = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_DEBUG) {
    Logging.prototype.log = function() {
        logWithPrefix("LOG  ", arguments);
    }
    Logging.prototype.debug = function() {
        logWithPrefix("DEBUG", arguments);
    }
} else {
    Logging.prototype.debug = doNotLog;
    Logging.prototype.log = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_INFO) {
    Logging.prototype.info = function() {
        logWithPrefix("INFO ", arguments);
    }
} else {
    Logging.prototype.info = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_WARN) {
    Logging.prototype.warn = function() {
        logWithPrefix("WARN ", arguments);
    }
} else {
    Logging.prototype.warn = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_ERROR) {
    Logging.prototype.error = function() {
        logWithPrefix("ERROR", arguments);
    }
} else {
    Logging.prototype.error = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_FATAL) {
    Logging.prototype.fatal = function() {
        logWithPrefix("FATAL", arguments);
    }
} else {
    Logging.prototype.fatal = doNotLog;
}

<commit_msg>Using constants also for default configuration.<commit_after>/*
 * This file is part of the Spludo Framework.
 * Copyright (c) 2009 DracoBlue, http://dracoblue.net/
 *
 * Licensed under the terms of MIT License. For the full copyright and license
 * information, please see the LICENSE file in the root folder.
 */

var sys = require('sys');

var logWithPrefix = function(prefix, args) {
    var message = "null";
    if (args.length > 1) {
        message = sys.inspect(args);
    }

    if (args.length === 1) {
        message = (typeof args[0] === "string") ? args[0] : sys.inspect(args[0]);
    }

    sys.debug(prefix + ': ' + message);

}

var doNotLog = function() {}

/*
 * Log Levels:
 *
 *    *  <   6   <     5     <  4   <  3   <  2    <   1   <  0
 *   ALL < TRACE < DEBUG/LOG < INFO < WARN < ERROR < FATAL < OFF
 */

Logging = function() {};

Logging.LEVEL_ALL = 127;
Logging.LEVEL_TRACE = 6;
Logging.LEVEL_LOG = 5;
Logging.LEVEL_DEBUG = 5;
Logging.LEVEL_INFO = 4;
Logging.LEVEL_WARN = 3;
Logging.LEVEL_ERROR = 2;
Logging.LEVEL_FATAL = 1;
Logging.LEVEL_OFF = 0;

var log_configuration = config.get(
    "logging", {
        "level": Logging.LEVEL_WARN
    }
);

if (log_configuration.level >= Logging.LEVEL_TRACE) {
    Logging.prototype.trace = function() {
        logWithPrefix("TRACE", arguments);
    }
} else {
    Logging.prototype.trace = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_DEBUG) {
    Logging.prototype.log = function() {
        logWithPrefix("LOG  ", arguments);
    }
    Logging.prototype.debug = function() {
        logWithPrefix("DEBUG", arguments);
    }
} else {
    Logging.prototype.debug = doNotLog;
    Logging.prototype.log = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_INFO) {
    Logging.prototype.info = function() {
        logWithPrefix("INFO ", arguments);
    }
} else {
    Logging.prototype.info = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_WARN) {
    Logging.prototype.warn = function() {
        logWithPrefix("WARN ", arguments);
    }
} else {
    Logging.prototype.warn = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_ERROR) {
    Logging.prototype.error = function() {
        logWithPrefix("ERROR", arguments);
    }
} else {
    Logging.prototype.error = doNotLog;
}

if (log_configuration.level >= Logging.LEVEL_FATAL) {
    Logging.prototype.fatal = function() {
        logWithPrefix("FATAL", arguments);
    }
} else {
    Logging.prototype.fatal = doNotLog;
}

<|endoftext|>


<commit_before>/**
 * @class Sampler
 * @description basic sampler abstraction based on buffer source node
 * @param {object} json parameters in JSON notation
 *                      { source: url, basePitch: pitch }
 */

// TODO: loop, loopStart, loopEnd
// TODO: voice management, max voice
// TODO: pitch modulation from inlet
// TODO: how to delete unused inlet

WX.Sampler = function(json) {
  // calling super constructor
  WX._Unit.call(this);
  // creating unit-specific properties
  Object.defineProperties(this, {
    _buffer: {
      enumerable: false,
      writable: true,
      value: undefined
    },
    _node: {
      enumerable: false,
      writable: true,
      value: undefined
    },
    _url: {
      enumerable: false,
      writable: true,
      value: ""
    },
    _basePitch: {
      enumerable: false,
      writable: true,
      value: 60
    },
    _label: {
      enumerable: false,
      writable: false,
      value: WX._Dictionary.Sampler
    }
  });
  // assign (default) parameters
  this.params = json;
};

WX.Sampler.prototype = Object.create(WX._Unit.prototype, {

  /**
   * get/set source location URL of sample
   * @param {string} url location of sample
   */
  source: {
    enumerable: true,
    get: function() {
      return this._url;
    },
    set: function(url) {
      if (url === undefined) {
        WX.error(this, "invalid audio file path.");
        return false;
      }
      var me = this;
      var xhr = new XMLHttpRequest();
      xhr.open("GET", url, true);
      xhr.responseType = "arraybuffer";
      xhr.onload = function() {
        try {
          me._buffer = WX._context.createBuffer(xhr.response, true);
        } catch(error) {
          WX.error(me, "file loading error: " + url + " (" + error.message + ")");
        }
      };
      xhr.send();
      this._url = url;
      return true;
    }
  },

  /**
   * get/set base pitch of sample (original pitch)
   * @type {Object}
   */
  basePitch: {
    enumerable: true,
    get: function() {
      return this._basePitch;
    },
    set: function(pitch) {
      this._basePitch = pitch;
    }
  },

  /**
   * fire sampler
   * @param {float} pitch playing pitch of sample
   */
  noteOn: {
    value: function(pitch) {
      // is this efficient?
      this._node = WX._context.createBufferSource();
      this._node.buffer = this._buffer;
      this._node.connect(this._outlet);
      // NOTE: calculate pitch and play the sound
      // (2 ^ (semitones change/12) = rate
      if (pitch !== undefined) {
        var rate = Math.pow(2, (pitch - this._basePitch) / 12);
        this._node.playbackRate.setValueAtTime(rate, 0);
      }
      // new method name, noteOn() is deprecated
      this._node.start(0);
    }
  },

  /**
   * stop sampler
   */
  noteOff: {
    value: function() {
      if (this._node) {
        // new method name, noteOff() is deprecated
        this._node.stop(0);
      }
    }
  }
});<commit_msg>patched sampler AJAX bug<commit_after>/**
 * @class Sampler
 * @description basic sampler abstraction based on buffer source node
 * @param {object} json parameters in JSON notation
 *                      { source: url, basePitch: pitch }
 */

// TODO: loop, loopStart, loopEnd
// TODO: voice management, max voice
// TODO: pitch modulation from inlet
// TODO: how to delete unused inlet

WX.Sampler = function(json) {
  // calling super constructor
  WX._Unit.call(this);
  // creating unit-specific properties
  Object.defineProperties(this, {
    _buffer: {
      enumerable: false,
      writable: true,
      value: undefined
    },
    _node: {
      enumerable: false,
      writable: true,
      value: undefined
    },
    _url: {
      enumerable: false,
      writable: true,
      value: ""
    },
    _basePitch: {
      enumerable: false,
      writable: true,
      value: 60
    },
    _label: {
      enumerable: false,
      writable: false,
      value: WX._Dictionary.Sampler
    },
    _ready: {
      enumerable: false,
      writable: true,
      value: false
    }
  });
  // assign (default) parameters
  this.params = json;
};

WX.Sampler.prototype = Object.create(WX._Unit.prototype, {

  /**
   * get/set source location URL of sample
   * @param {string} url location of sample
   */
  source: {
    enumerable: true,
    get: function() {
      return this._url;
    },
    set: function(url) {
      if (url === undefined) {
        WX.error(this, "invalid audio file path.");
        return false;
      }
      var me = this;
      var xhr = new XMLHttpRequest();
      xhr.open("GET", url, true);
      xhr.responseType = "arraybuffer";
      xhr.onload = function() {
        try {
          me._buffer = WX._context.createBuffer(xhr.response, true);
          me._ready = true;
        } catch(error) {
          WX.error(me, "file loading error: " + url + " (" + error.message + ")");
        }
      };
      xhr.send();
      this._url = url;
      return true;
    }
  },

  /**
   * get/set base pitch of sample (original pitch)
   * @type {Object}
   */
  basePitch: {
    enumerable: true,
    get: function() {
      return this._basePitch;
    },
    set: function(pitch) {
      this._basePitch = pitch;
    }
  },

  /**
   * fire sampler
   * @param {float} pitch playing pitch of sample
   */
  noteOn: {
    value: function(pitch) {
      if (!this._ready) {
        WX.error(this, "sampler is not ready.");
        return;
      }
      // is this efficient?
      this._node = WX._context.createBufferSource();
      this._node.buffer = this._buffer;
      this._node.connect(this._outlet);
      // NOTE: calculate pitch and play the sound
      // (2 ^ (semitones change/12) = rate
      if (pitch !== undefined) {
        var rate = Math.pow(2, (pitch - this._basePitch) / 12);
        this._node.playbackRate.setValueAtTime(rate, 0);
      }
      // new method name, noteOn() is deprecated
      this._node.start(0);
    }
  },

  /**
   * stop sampler
   */
  noteOff: {
    value: function() {
      if (this._node) {
        // new method name, noteOff() is deprecated
        this._node.stop(0);
      }
    }
  }
});<|endoftext|>


<commit_before>const os = require('os');
const { Config } = require('./config');
const { JsonStore } = require('./json_store');
const logger = require('../util/logger.js');

/**
 * GlobalContext is a single, globally available object that provides
 * information and services to all components of the application.
 */
class GlobalContext {
    /**
     * Constructs a new GlobalContext. Don't call this yourself, as it's
     * called when the module loads. You'll want to access pre-instantiated
     * Context object that this module exports.
     */
    constructor() {
        /**
          * isTestEnv indicates whether we're currently running as part of
          * a test suite. It will be true when process.env.NODE_ENV === 'test',
          * which Jest sets by default when you run `npm test`.
          *
          * @type {boolean}
          */
        this.isTestEnv = process.env.NODE_ENV === 'test';
        /**
          * config is the current configuration, either user or test, based
          * on whether isTestEnv is true.
          *
          * @type {Config}
          */
        this.config = this.isTestEnv ? Config.test : Config.user;
        /**
          * dataStores is a hash of the application data storage files.
          * The key is the object name (type of object stored in the file),
          * and the value is the queryable JsonStore object holding the data.
          *
          * @type {Object.<string, JsonStore>}
          */
        this.dataStores = {};

        /**
         * logger is an instance of the WinstonJS logger, the system-wide logging
         * facility. See https://github.com/winstonjs/winston.
         *
         * @type {Object}
         */
        this.logger = logger;
    }
    /**
      * Returns the JsonStore with the specified name (class name),
      * creating it first if necessary.
      *
      * @param {string} name - The name of the datastore. This can be a class name,
      * so each object type has it's own JSON data file.
     */
    db(name) {
        if (this.dataStores[name] == null) {
            this.dataStores[name] = new JsonStore(this.config.dataDir, name);
        }
        return this.dataStores[name];
    }

    /**
     * Returns true if we're running in Electron dev mode rather than in compiled mode.
     *
     * @returns {boolean}
     */
    isElectronDevMode() {
        return (process.execPath.includes('node_modules/electron') ||
                process.execPath.includes('node_modules\electron'));
    }

    /**
     * Returns a JavaScript object built from parsing this application's
     * package.json file.
     *
     * @returns {Object}
     */
    getPackageInfo() {
        var obj = null;
        try {
            obj = require('../package.json')
        } catch (ex) {
            this.logger.error(ex)
        }
        return obj;
    }

    /**
     * Returns the version of DART.
     *
     * @returns {string}
     */
    dartVersion() {
        var commitId = "$Id$";
        var pkg = this.getPackageInfo();
        if (pkg == null) {
            return "Cannot read version from package.json file.";
        }
        return `${pkg.name} ${pkg.version} (Electron ${pkg.build.electronVersion} with Node.js ${process.version} for ${os.platform()} ${os.arch()} ${os.release()}. Commit ${commitId.slice(8)})`
    }
}

const Context = new GlobalContext();
Object.freeze(Context);

module.exports.Context = Context;
<commit_msg>Removed commit id from version<commit_after>const os = require('os');
const { Config } = require('./config');
const { JsonStore } = require('./json_store');
const logger = require('../util/logger.js');

/**
 * GlobalContext is a single, globally available object that provides
 * information and services to all components of the application.
 */
class GlobalContext {
    /**
     * Constructs a new GlobalContext. Don't call this yourself, as it's
     * called when the module loads. You'll want to access pre-instantiated
     * Context object that this module exports.
     */
    constructor() {
        /**
          * isTestEnv indicates whether we're currently running as part of
          * a test suite. It will be true when process.env.NODE_ENV === 'test',
          * which Jest sets by default when you run `npm test`.
          *
          * @type {boolean}
          */
        this.isTestEnv = process.env.NODE_ENV === 'test';
        /**
          * config is the current configuration, either user or test, based
          * on whether isTestEnv is true.
          *
          * @type {Config}
          */
        this.config = this.isTestEnv ? Config.test : Config.user;
        /**
          * dataStores is a hash of the application data storage files.
          * The key is the object name (type of object stored in the file),
          * and the value is the queryable JsonStore object holding the data.
          *
          * @type {Object.<string, JsonStore>}
          */
        this.dataStores = {};

        /**
         * logger is an instance of the WinstonJS logger, the system-wide logging
         * facility. See https://github.com/winstonjs/winston.
         *
         * @type {Object}
         */
        this.logger = logger;
    }
    /**
      * Returns the JsonStore with the specified name (class name),
      * creating it first if necessary.
      *
      * @param {string} name - The name of the datastore. This can be a class name,
      * so each object type has it's own JSON data file.
     */
    db(name) {
        if (this.dataStores[name] == null) {
            this.dataStores[name] = new JsonStore(this.config.dataDir, name);
        }
        return this.dataStores[name];
    }

    /**
     * Returns true if we're running in Electron dev mode rather than in compiled mode.
     *
     * @returns {boolean}
     */
    isElectronDevMode() {
        return (process.execPath.includes('node_modules/electron') ||
                process.execPath.includes('node_modules\electron'));
    }

    /**
     * Returns a JavaScript object built from parsing this application's
     * package.json file.
     *
     * @returns {Object}
     */
    getPackageInfo() {
        var obj = null;
        try {
            obj = require('../package.json')
        } catch (ex) {
            this.logger.error(ex)
        }
        return obj;
    }

    /**
     * Returns the version of DART.
     *
     * @returns {string}
     */
    dartVersion() {
        var pkg = this.getPackageInfo();
        if (pkg == null) {
            return "Cannot read version from package.json file.";
        }
        return `${pkg.name} ${pkg.version} (Electron ${pkg.build.electronVersion} with Node.js ${process.version} for ${os.platform()}-${os.arch()}-${os.release()}.)`
    }
}

const Context = new GlobalContext();
Object.freeze(Context);

module.exports.Context = Context;
<|endoftext|>