<commit_before>'use strict';

WaveSurfer.WebAudio = {
    scriptBufferSize: 256,
    fftSize: 128,
    PLAYING_STATE: 0,
    PAUSED_STATE: 1,
    FINISHED_STATE: 2,

    getAudioContext: function () {
        if (!(window.AudioContext || window.webkitAudioContext)) {
            throw new Error("Your browser doesn't support Web Audio");
        }

        if (!WaveSurfer.WebAudio.audioContext) {
            WaveSurfer.WebAudio.audioContext = new (
                window.AudioContext || window.webkitAudioContext
            );
        }
        return WaveSurfer.WebAudio.audioContext;
    },

    init: function (params) {
        this.params = params;
        this.ac = params.audioContext || this.getAudioContext();

        this.lastPlay = this.ac.currentTime;
        this.startPosition = 0;

        this.states = [
            Object.create(WaveSurfer.WebAudio.state.playing),
            Object.create(WaveSurfer.WebAudio.state.paused),
            Object.create(WaveSurfer.WebAudio.state.finished)
        ];

        this.setState(this.PAUSED_STATE);

        this.createVolumeNode();
        this.createScriptNode();
        this.createAnalyserNode();
        this.setPlaybackRate(this.params.audioRate);
    },

    disconnectFilters: function () {
        if (this.filters) {
            this.filters.forEach(function (filter) {
                filter && filter.disconnect();
            });
            this.filters = null;
        }
    },

    setState: function (state) {
        if (this.state !== this.states[state]) {
            this.state = this.states[state];
            this.state.init.call(this);
        }
    },

    // Unpacked filters
    setFilter: function () {
        this.setFilters([].slice.call(arguments));
    },

    /**
     * @param {Array} filters Packed ilters array
     */
    setFilters: function (filters) {
        this.disconnectFilters();

        if (filters && filters.length) {
            this.filters = filters;

            // Connect each filter in turn
            filters.reduce(function (prev, curr) {
                prev.connect(curr);
                return curr;
            }, this.analyser).connect(this.gainNode);
        } else {
            this.analyser.connect(this.gainNode);
        }
    },

    createScriptNode: function () {
        var my = this;
        var bufferSize = this.scriptBufferSize;
        if (this.ac.createScriptProcessor) {
            this.scriptNode = this.ac.createScriptProcessor(bufferSize);
        } else {
            this.scriptNode = this.ac.createJavaScriptNode(bufferSize);
        }
        this.scriptNode.connect(this.ac.destination);

        this.scriptNode.onaudioprocess = function () {
            var time = my.getCurrentTime();

            if (my.state === my.states[my.PLAYING_STATE]) {
                my.fireEvent('audioprocess', time);
            }

            if (my.buffer && time > my.getDuration()) {
                my.setState(my.FINISHED_STATE);
            }
        };
    },

    createAnalyserNode: function () {
        this.analyser = this.ac.createAnalyser();
        this.analyser.fftSize = this.fftSize;
        this.analyserData = new Uint8Array(this.analyser.frequencyBinCount);
        this.analyser.connect(this.gainNode);
    },

    /**
     * Create the gain node needed to control the playback volume.
     */
    createVolumeNode: function () {
        // Create gain node using the AudioContext
        if (this.ac.createGain) {
            this.gainNode = this.ac.createGain();
        } else {
            this.gainNode = this.ac.createGainNode();
        }
        // Add the gain node to the graph
        this.gainNode.connect(this.ac.destination);
    },

    /**
     * Set the gain to a new value.
     *
     * @param {Number} newGain The new gain, a floating point value
     * between 0 and 1. 0 being no gain and 1 being maximum gain.
     */
    setVolume: function (newGain) {
        this.gainNode.gain.value = newGain;
    },

    /**
     * Get the current gain.
     *
     * @returns {Number} The current gain, a floating point value
     * between 0 and 1. 0 being no gain and 1 being maximum gain.
     */
    getVolume: function () {
        return this.gainNode.gain.value;
    },

    decodeArrayBuffer: function (arraybuffer, callback, errback) {
        var my = this;
        this.ac.decodeAudioData(arraybuffer, function (data) {
            my.buffer = data;
            callback(data);
        }, errback);
    },

    /**
     * @returns {Float32Array} Array of peaks.
     */
    getPeaks: function (length) {
        var buffer = this.buffer;
        var sampleSize = buffer.length / length;
        var sampleStep = ~~(sampleSize / 10) || 1;
        var channels = buffer.numberOfChannels;
        var peaks = new Float32Array(length);

        for (var c = 0; c < channels; c++) {
            var chan = buffer.getChannelData(c);
            for (var i = 0; i < length; i++) {
                var start = ~~(i * sampleSize);
                var end = ~~(start + sampleSize);
                var max = 0;
                for (var j = start; j < end; j += sampleStep) {
                    var value = chan[j];
                    if (value > max) {
                        max = value;
                    // faster than Math.abs
                    } else if (-value > max) {
                        max = -value;
                    }
                }
                if (c == 0 || max > peaks[i]) {
                    peaks[i] = max;
                }
            }
        }

        return peaks;
    },

    getPlayedPercents: function () {
        return this.state.getPlayedPercents.call(this);
    },

    disconnectSource: function () {
        if (this.source) {
            this.source.disconnect();
        }
    },

    /**
     * Returns the real-time waveform data.
     *
     * @return {Uint8Array} The frequency data.
     * Values range from 0 to 255.
     */
    waveform: function () {
        this.analyser.getByteTimeDomainData(this.analyserData);
        return this.analyserData;
    },

    destroy: function () {
        this.pause();
        this.unAll();
        this.buffer = null;
        this.disconnectFilters();
        this.disconnectSource();
        this.gainNode.disconnect();
        this.scriptNode.disconnect();
        this.analyser.disconnect();
    },

    load: function (buffer) {
        this.startPosition = 0;
        this.lastPlay = this.ac.currentTime;
        this.buffer = buffer;
        this.createSource();
    },

    createSource: function () {
        this.disconnectSource();
        this.source = this.ac.createBufferSource();

        //adjust for old browsers.
        this.source.start = this.source.start || this.source.noteGrainOn;
        this.source.stop = this.source.stop || this.source.noteOff;

        this.source.playbackRate.value = this.playbackRate;
        this.source.buffer = this.buffer;
        this.source.connect(this.analyser);
    },

    isPaused: function () {
        return this.state !== this.states[this.PLAYING_STATE];
    },

    getDuration: function () {
        return this.buffer.duration || 0;
    },

    seekTo: function (start, end) {
        if (start == null) {
            start = this.getCurrentTime();
            if (start >= this.getDuration()) {
                start = 0;
            }
        }
        if (end == null) {
            end = this.getDuration();
        }

        this.startPosition = start;
        this.lastPlay = this.ac.currentTime;

        if (this.state === this.states[this.FINISHED_STATE]) {
            this.setState(this.PAUSED_STATE);
        }

        return { start: start, end: end };
    },

    getPlayedTime: function () {
        return (this.ac.currentTime - this.lastPlay) * this.playbackRate;
    },

    /**
     * Plays the loaded audio region.
     *
     * @param {Number} start Start offset in seconds,
     * relative to the beginning of a clip.
     * @param {Number} end When to stop
     * relative to the beginning of a clip.
     */
    play: function (start, end) {
        // need to re-create source on each playback
        this.createSource();

        var adjustedTime = this.seekTo(start, end);

        start = adjustedTime.start;
        end = adjustedTime.end;

        this.source.start(0, start, end - start);

        this.setState(this.PLAYING_STATE);
    },

    /**
     * Pauses the loaded audio.
     */
    pause: function () {
        this.startPosition += this.getPlayedTime();
        this.source && this.source.stop(0);

        this.setState(this.PAUSED_STATE);
    },

    /**
    *   Returns the current time in seconds relative to the audioclip's duration.
    */
    getCurrentTime: function () {
        return this.state.getCurrentTime.call(this);
    },

    /**
     * Set the audio source playback rate.
     */
    setPlaybackRate: function (value) {
        value = value || 1;
        if (this.isPaused()) {
            this.playbackRate = value;
        } else {
            this.pause();
            this.playbackRate = value;
            this.play();
        }
    }
};

WaveSurfer.WebAudio.state = {};

WaveSurfer.WebAudio.state.playing = {
    init: function () {
    },
    getPlayedPercents: function () {
        var duration = this.getDuration();
        return (this.getCurrentTime() / duration) || 0;
    },
    getCurrentTime: function () {
        return this.startPosition + this.getPlayedTime();
    }
};

WaveSurfer.WebAudio.state.paused = {
    init: function () {
    },
    getPlayedPercents: function () {
        var duration = this.getDuration();
        return (this.getCurrentTime() / duration) || 0;
    },
    getCurrentTime: function () {
        return this.startPosition;
    }
};

WaveSurfer.WebAudio.state.finished = {
    init: function () {
        this.fireEvent('finish');
    },
    getPlayedPercents: function () {
        return 1;
    },
    getCurrentTime: function () {
        return this.getDuration();
    }
};

WaveSurfer.util.extend(WaveSurfer.WebAudio, WaveSurfer.Observer);
<commit_msg>make sure it's playing when trying to pause<commit_after>'use strict';

WaveSurfer.WebAudio = {
    scriptBufferSize: 256,
    fftSize: 128,
    PLAYING_STATE: 0,
    PAUSED_STATE: 1,
    FINISHED_STATE: 2,

    getAudioContext: function () {
        if (!(window.AudioContext || window.webkitAudioContext)) {
            throw new Error("Your browser doesn't support Web Audio");
        }

        if (!WaveSurfer.WebAudio.audioContext) {
            WaveSurfer.WebAudio.audioContext = new (
                window.AudioContext || window.webkitAudioContext
            );
        }
        return WaveSurfer.WebAudio.audioContext;
    },

    init: function (params) {
        this.params = params;
        this.ac = params.audioContext || this.getAudioContext();

        this.lastPlay = this.ac.currentTime;
        this.startPosition = 0;

        this.states = [
            Object.create(WaveSurfer.WebAudio.state.playing),
            Object.create(WaveSurfer.WebAudio.state.paused),
            Object.create(WaveSurfer.WebAudio.state.finished)
        ];

        this.setState(this.PAUSED_STATE);

        this.createVolumeNode();
        this.createScriptNode();
        this.createAnalyserNode();
        this.setPlaybackRate(this.params.audioRate);
    },

    disconnectFilters: function () {
        if (this.filters) {
            this.filters.forEach(function (filter) {
                filter && filter.disconnect();
            });
            this.filters = null;
        }
    },

    setState: function (state) {
        if (this.state !== this.states[state]) {
            this.state = this.states[state];
            this.state.init.call(this);
        }
    },

    // Unpacked filters
    setFilter: function () {
        this.setFilters([].slice.call(arguments));
    },

    /**
     * @param {Array} filters Packed ilters array
     */
    setFilters: function (filters) {
        this.disconnectFilters();

        if (filters && filters.length) {
            this.filters = filters;

            // Connect each filter in turn
            filters.reduce(function (prev, curr) {
                prev.connect(curr);
                return curr;
            }, this.analyser).connect(this.gainNode);
        } else {
            this.analyser.connect(this.gainNode);
        }
    },

    createScriptNode: function () {
        var my = this;
        var bufferSize = this.scriptBufferSize;
        if (this.ac.createScriptProcessor) {
            this.scriptNode = this.ac.createScriptProcessor(bufferSize);
        } else {
            this.scriptNode = this.ac.createJavaScriptNode(bufferSize);
        }
        this.scriptNode.connect(this.ac.destination);

        this.scriptNode.onaudioprocess = function () {
            var time = my.getCurrentTime();

            if (my.state === my.states[my.PLAYING_STATE]) {
                my.fireEvent('audioprocess', time);
            }

            if (my.buffer && time > my.getDuration()) {
                my.setState(my.FINISHED_STATE);
            }
        };
    },

    createAnalyserNode: function () {
        this.analyser = this.ac.createAnalyser();
        this.analyser.fftSize = this.fftSize;
        this.analyserData = new Uint8Array(this.analyser.frequencyBinCount);
        this.analyser.connect(this.gainNode);
    },

    /**
     * Create the gain node needed to control the playback volume.
     */
    createVolumeNode: function () {
        // Create gain node using the AudioContext
        if (this.ac.createGain) {
            this.gainNode = this.ac.createGain();
        } else {
            this.gainNode = this.ac.createGainNode();
        }
        // Add the gain node to the graph
        this.gainNode.connect(this.ac.destination);
    },

    /**
     * Set the gain to a new value.
     *
     * @param {Number} newGain The new gain, a floating point value
     * between 0 and 1. 0 being no gain and 1 being maximum gain.
     */
    setVolume: function (newGain) {
        this.gainNode.gain.value = newGain;
    },

    /**
     * Get the current gain.
     *
     * @returns {Number} The current gain, a floating point value
     * between 0 and 1. 0 being no gain and 1 being maximum gain.
     */
    getVolume: function () {
        return this.gainNode.gain.value;
    },

    decodeArrayBuffer: function (arraybuffer, callback, errback) {
        var my = this;
        this.ac.decodeAudioData(arraybuffer, function (data) {
            my.buffer = data;
            callback(data);
        }, errback);
    },

    /**
     * @returns {Float32Array} Array of peaks.
     */
    getPeaks: function (length) {
        var buffer = this.buffer;
        var sampleSize = buffer.length / length;
        var sampleStep = ~~(sampleSize / 10) || 1;
        var channels = buffer.numberOfChannels;
        var peaks = new Float32Array(length);

        for (var c = 0; c < channels; c++) {
            var chan = buffer.getChannelData(c);
            for (var i = 0; i < length; i++) {
                var start = ~~(i * sampleSize);
                var end = ~~(start + sampleSize);
                var max = 0;
                for (var j = start; j < end; j += sampleStep) {
                    var value = chan[j];
                    if (value > max) {
                        max = value;
                    // faster than Math.abs
                    } else if (-value > max) {
                        max = -value;
                    }
                }
                if (c == 0 || max > peaks[i]) {
                    peaks[i] = max;
                }
            }
        }

        return peaks;
    },

    getPlayedPercents: function () {
        return this.state.getPlayedPercents.call(this);
    },

    disconnectSource: function () {
        if (this.source) {
            this.source.disconnect();
        }
    },

    /**
     * Returns the real-time waveform data.
     *
     * @return {Uint8Array} The frequency data.
     * Values range from 0 to 255.
     */
    waveform: function () {
        this.analyser.getByteTimeDomainData(this.analyserData);
        return this.analyserData;
    },

    destroy: function () {
	if (!this.isPaused()) {
            this.pause();
        }
        this.unAll();
        this.buffer = null;
        this.disconnectFilters();
        this.disconnectSource();
        this.gainNode.disconnect();
        this.scriptNode.disconnect();
        this.analyser.disconnect();
    },

    load: function (buffer) {
        this.startPosition = 0;
        this.lastPlay = this.ac.currentTime;
        this.buffer = buffer;
        this.createSource();
    },

    createSource: function () {
        this.disconnectSource();
        this.source = this.ac.createBufferSource();

        //adjust for old browsers.
        this.source.start = this.source.start || this.source.noteGrainOn;
        this.source.stop = this.source.stop || this.source.noteOff;

        this.source.playbackRate.value = this.playbackRate;
        this.source.buffer = this.buffer;
        this.source.connect(this.analyser);
    },

    isPaused: function () {
        return this.state !== this.states[this.PLAYING_STATE];
    },

    getDuration: function () {
        return this.buffer.duration || 0;
    },

    seekTo: function (start, end) {
        if (start == null) {
            start = this.getCurrentTime();
            if (start >= this.getDuration()) {
                start = 0;
            }
        }
        if (end == null) {
            end = this.getDuration();
        }

        this.startPosition = start;
        this.lastPlay = this.ac.currentTime;

        if (this.state === this.states[this.FINISHED_STATE]) {
            this.setState(this.PAUSED_STATE);
        }

        return { start: start, end: end };
    },

    getPlayedTime: function () {
        return (this.ac.currentTime - this.lastPlay) * this.playbackRate;
    },

    /**
     * Plays the loaded audio region.
     *
     * @param {Number} start Start offset in seconds,
     * relative to the beginning of a clip.
     * @param {Number} end When to stop
     * relative to the beginning of a clip.
     */
    play: function (start, end) {
        // need to re-create source on each playback
        this.createSource();

        var adjustedTime = this.seekTo(start, end);

        start = adjustedTime.start;
        end = adjustedTime.end;

        this.source.start(0, start, end - start);

        this.setState(this.PLAYING_STATE);
    },

    /**
     * Pauses the loaded audio.
     */
    pause: function () {
        this.startPosition += this.getPlayedTime();
        this.source && this.source.stop(0);

        this.setState(this.PAUSED_STATE);
    },

    /**
    *   Returns the current time in seconds relative to the audioclip's duration.
    */
    getCurrentTime: function () {
        return this.state.getCurrentTime.call(this);
    },

    /**
     * Set the audio source playback rate.
     */
    setPlaybackRate: function (value) {
        value = value || 1;
        if (this.isPaused()) {
            this.playbackRate = value;
        } else {
            this.pause();
            this.playbackRate = value;
            this.play();
        }
    }
};

WaveSurfer.WebAudio.state = {};

WaveSurfer.WebAudio.state.playing = {
    init: function () {
    },
    getPlayedPercents: function () {
        var duration = this.getDuration();
        return (this.getCurrentTime() / duration) || 0;
    },
    getCurrentTime: function () {
        return this.startPosition + this.getPlayedTime();
    }
};

WaveSurfer.WebAudio.state.paused = {
    init: function () {
    },
    getPlayedPercents: function () {
        var duration = this.getDuration();
        return (this.getCurrentTime() / duration) || 0;
    },
    getCurrentTime: function () {
        return this.startPosition;
    }
};

WaveSurfer.WebAudio.state.finished = {
    init: function () {
        this.fireEvent('finish');
    },
    getPlayedPercents: function () {
        return 1;
    },
    getCurrentTime: function () {
        return this.getDuration();
    }
};

WaveSurfer.util.extend(WaveSurfer.WebAudio, WaveSurfer.Observer);
<|endoftext|>


<commit_before>'use strict';

WaveSurfer.WebAudio = {
    init: function (params) {
        this.ac = params.AudioContext ||
            new (window.AudioContext || window.webkitAudioContext);

        this.createScriptNode();
    },

    createScriptNode: function () {
        var my = this;
        this.scriptNode = this.ac.createJavaScriptNode(256);
        this.scriptNode.connect(this.ac.destination);
        this.scriptNode.onaudioprocess = function () {
            if (my.source && !my.isPaused()) {
                my.fireEvent('audioprocess', my.getPlayedPercents());
            }
        };
    },

    refreshBufferSource: function () {
        this.source && this.source.disconnect();
        this.source = this.ac.createBufferSource();
        this.source.buffer = this.buffer;
        this.source.connect(this.scriptNode);
        this.source.connect(this.ac.destination);
    },

    setBuffer: function (buffer) {
        this.lastPause = 0;
        this.lastStart = 0;
        this.startTime = 0;
        this.buffer = buffer;
        this.refreshBufferSource();
    },

    /**
     * Decodes binary data and creates buffer source.
     *
     * @param {ArrayBuffer} arraybuffer Audio data.
     */
    loadBuffer: function (arraybuffer, cb, errb) {
        var my = this;

        if (this.source) {
            this.pause();
        }

        this.ac.decodeAudioData(
            arraybuffer,
            function (buffer) {
                my.setBuffer(buffer);
                cb && cb(buffer);
            },
            function () {
                //console.error('Error decoding audio buffer');
                errb && errb();
            }
        );
    },

    isPaused: function () {
        return this.source.PLAYING_STATE != this.source.playbackState;
    },

    getDuration: function () {
        return this.buffer.duration;
    },

    /**
     * Plays the loaded audio region.
     *
     * @param {Number} start Start offset in seconds,
     * relative to the beginning of the track.
     *
     * @param {Number} end End offset in seconds,
     * relative to the beginning of the track.
     */
    play: function (start, end) {
        this.refreshBufferSource();

        if (null == start) { start = this.getCurrentTime(); }
        if (null == end  ) { end = this.source.buffer.duration; }

        this.lastStart = start;
        this.lastPause = end;
        this.startTime = this.ac.currentTime;
        this.source.noteGrainOn(0, start, end - start);
    },

    /**
     * Pauses the loaded audio.
     */
    pause: function () {
        this.lastPause = this.lastStart + (this.ac.currentTime - this.startTime);
        this.source.noteOff(0);
    },

    /**
     * @returns {Float32Array} Array of peaks.
     */
    getPeaks: function (length, sampleStep) {
        sampleStep = sampleStep || 128;
        var buffer = this.buffer;
        var k = buffer.length / length;
        var peaks = new Float32Array(length);

        for (var c = 0; c < buffer.numberOfChannels; c++) {
            var chan = buffer.getChannelData(c);

            for (var i = 0; i < length; i++) {
                var peak = -Infinity;
                var start = ~~(i * k);
                var end = (i + 1) * k;
                for (var j = start; j < end; j += sampleStep) {
                    var val = chan[j];
                    if (val > peak) {
                        peak = val;
                    } else if (-val > peak) {
                        peak = -val;
                    }
                }

                if (c > 0) {
                    peaks[i] += peak;
                } else {
                    peaks[i] = peak;
                }
            }
        }

        return peaks;
    },

    getMaxPeak: function () {
        /* Peaks are sums of absolute peak values from each channel. */
        return this.buffer.numberOfChannels * 1.0;
    },

    getPlayedPercents: function () {
        var duration = this.getDuration();
        return duration > 0 ? this.getCurrentTime() / duration : 0;
    },

    getCurrentTime: function () {
        if (this.isPaused()) {
            return this.lastPause;
        }
        return this.lastStart + (this.ac.currentTime - this.startTime);
    }
};

WaveSurfer.util.extend(WaveSurfer.WebAudio, Observer);
<commit_msg>mobile Safari no autoplay<commit_after>'use strict';

WaveSurfer.WebAudio = {
    init: function (params) {
        this.ac = params.AudioContext ||
            new (window.AudioContext || window.webkitAudioContext);

        this.createScriptNode();
    },

    createScriptNode: function () {
        var my = this;
        this.scriptNode = this.ac.createJavaScriptNode(256);
        this.scriptNode.connect(this.ac.destination);
        this.scriptNode.onaudioprocess = function () {
            if (my.source && !my.isPaused()) {
                my.fireEvent('audioprocess', my.getPlayedPercents());
            }
        };
    },

    refreshBufferSource: function () {
        this.source && this.source.disconnect();
        this.source = this.ac.createBufferSource();
        this.source.buffer = this.buffer;
        this.source.connect(this.scriptNode);
        this.source.connect(this.ac.destination);
    },

    setBuffer: function (buffer) {
        this.lastPause = 0;
        this.lastStart = 0;
        this.startTime = 0;
        this.buffer = buffer;
        this.refreshBufferSource();
    },

    /**
     * Decodes binary data and creates buffer source.
     *
     * @param {ArrayBuffer} arraybuffer Audio data.
     */
    loadBuffer: function (arraybuffer, cb, errb) {
        var my = this;

        if (this.source) {
            this.pause();
        }

        this.ac.decodeAudioData(
            arraybuffer,
            function (buffer) {
                my.setBuffer(buffer);
                cb && cb(buffer);
            },
            function () {
                //console.error('Error decoding audio buffer');
                errb && errb();
            }
        );
    },

    isPaused: function () {
        return this.source.PLAYING_STATE != this.source.playbackState;
    },

    getDuration: function () {
        return this.buffer.duration;
    },

    /**
     * Plays the loaded audio region.
     *
     * @param {Number} start Start offset in seconds,
     * relative to the beginning of the track.
     *
     * @param {Number} end End offset in seconds,
     * relative to the beginning of the track.
     */
    play: function (start, end) {
        this.refreshBufferSource();

        if (null == start) { start = this.getCurrentTime(); }
        if (null == end) {
            end = this.getDuration();
        } else {
            this.lastPause = end;
        }

        this.lastStart = start;
        this.startTime = this.ac.currentTime;

        this.source.noteGrainOn(0, start, end - start);
    },

    /**
     * Pauses the loaded audio.
     */
    pause: function () {
        this.lastPause = this.lastStart + (this.ac.currentTime - this.startTime);
        this.source.noteOff(0);
    },

    /**
     * @returns {Float32Array} Array of peaks.
     */
    getPeaks: function (length, sampleStep) {
        sampleStep = sampleStep || 128;
        var buffer = this.buffer;
        var k = buffer.length / length;
        var peaks = new Float32Array(length);

        for (var c = 0; c < buffer.numberOfChannels; c++) {
            var chan = buffer.getChannelData(c);

            for (var i = 0; i < length; i++) {
                var peak = -Infinity;
                var start = ~~(i * k);
                var end = (i + 1) * k;
                for (var j = start; j < end; j += sampleStep) {
                    var val = chan[j];
                    if (val > peak) {
                        peak = val;
                    } else if (-val > peak) {
                        peak = -val;
                    }
                }

                if (c > 0) {
                    peaks[i] += peak;
                } else {
                    peaks[i] = peak;
                }
            }
        }

        return peaks;
    },

    getMaxPeak: function () {
        /* Peaks are sums of absolute peak values from each channel. */
        return this.buffer.numberOfChannels * 1.0;
    },

    getPlayedPercents: function () {
        var duration = this.getDuration();
        return duration > 0 ? this.getCurrentTime() / duration : 0;
    },

    getCurrentTime: function () {
        if (this.isPaused()) {
            return this.lastPause;
        }
        return this.lastStart + (this.ac.currentTime - this.startTime);
    }
};

WaveSurfer.util.extend(WaveSurfer.WebAudio, Observer);
<|endoftext|>


<commit_before>/*
 * canvas 1.0
 * A simple, canvas CanvasRenderingContext2D.prototype 原型扩展库，便于链式操作；
 * from wbh5.com @Author leiroc
 * Copyright 2015, MIT License
 *
 */
function Wipe(t){this.opts={el:"#wipe",fg:"#ccc",size:10,debug:!1,autoWipe:!1,data:[],onswiping:function(t,i){}};for(var i in t)this.opts[i]=t[i];this.init()}window.requestNextAnimationFrame=function(){var t=void 0,i=void 0,e=void 0,n=0,s=navigator.userAgent,o=0,a=this;return window.webkitRequestAnimationFrame&&(i=function(t){void 0===t&&(t+=new Date),a.callback(t)},t=window.webkitRequestAnimationFrame,window.webkitRequestAnimationFrame=function(i,n){a.callback=e,t(i,n)}),window.mozRequestAnimationFrame&&(o=s.indexOf("rv:"),-1!=s.indexOf("Gecko")&&(n=s.substr(o+3,3),"2.0"===n&&(window.mozRequestAnimationFrame=void 0))),window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t,i){var e,n;window.setTimeout(function(){e=+new Date,t(e),n=+new Date,a.timeout=1e3/60-(n-e)},a.timeout)}}(),window.cancelAnimate=function(t){return window.cancelAnimationFrame(t)},function(t){t.drawRect=function(t,i,e,n,s,o){return"fill"==o?(this.fillStyle=s+"",this.fillRect(t,i,e,n)):"stroke"==o?(this.strokeStyle=s+"",this.strokeRect(t,i,e,n)):"round"==o||alert("type 参数错误"),this},t.clear=function(t,i,e,n){return this.clearRect(t,i,e,n),this},t.roundRect=function(t,i,e,n,s,o,a){return this.beginPath(),this.moveTo(t,i+o),this.lineTo(t,i+n-o),this.quadraticCurveTo(t,i+n,t+o,i+n),this.lineTo(t+e-o,i+n),this.quadraticCurveTo(t+e,i+n,t+e,i+n-o),this.lineTo(t+e,i+o),this.quadraticCurveTo(t+e,i,t+e-o,i),this.lineTo(t+o,i),this.quadraticCurveTo(t,i,t,i+o),"fill"==a?(this.fillStyle=s+"",this.fill()):"stroke"==a&&(this.strokeStyle=s+"",this.stroke(),this.closePath()),this},t._arc=function(t,i,e,n,s,o,a,h,r){return this.beginPath(),this.arc(t,i,e,n,s,o),a&&this.lineTo(a.x,a.y),"fill"==r?(this.fillStyle=h+"",this.fill()):"stroke"==r&&(this.strokeStyle=h+"",this.stroke(),this.closePath()),this},t.triangle=function(t,i,e,n,s){return this.beginPath(),this.moveTo(t,i),this.lineTo(e.x1,e.y1),this.lineTo(e.x2,e.y2),"fill"==s?(this.fillStyle=n+"",this.fill()):"stroke"==s&&(this.strokeStyle=n+"",this.lineTo(t,i),this.stroke(),this.closePath()),this},t.drawImg=function(t,i,e,n,s){var o=this,a=new Image;return a.onload=function(){o.drawImage(a,i,e,n,s)},a.src=t,this},t.lineW=function(t){return this.lineWidth=t,this},t._save=function(){return this.save(),this},t._moveTo=function(t,i){return this.moveTo(t,i),this},t._stroke=function(){return this.stroke(),this},t._lineTo=function(t,i){return this.lineTo(t,i),this},t.bPath=function(){return this.beginPath(),this},t.cPath=function(){return this.closePath(),this},t.sStyle=function(t){return this.strokeStyle=t,this},t._gco=function(t){return this.globalCompositeOperation=t,this},t._lineJoin=function(t){return this.lineJoin=t,this},t._lineCap=function(t){return this.lineCap=t,this}}(CanvasRenderingContext2D.prototype),Wipe.prototype={doc:document,$:function(t){return this.doc.querySelector(t)},init:function(){var t=this,i=window.devicePixelRatio||1;this.devicePixelRatio=i,this.wrap=this.$(this.opts.el),this.wrap.innerHTML=null,this.wrap.appendChild(this.doc.createElement("canvas")),this.wrapWidth=parseInt(this.wrap.offsetWidth),this.wrapHeight=parseInt(this.wrap.offsetHeight),this.wrap.addEventListener("touchmove",function(t){t.preventDefault()}),this.canvas=this.wrap.childNodes[0],this.canvas.style.cssText+="width: 100%; height: 100%",this.ctx=this.canvas.getContext("2d"),this.canvas.setAttribute("width",this.wrapWidth*i),this.canvas.setAttribute("height",this.wrapHeight*i),this.cWidth=this.canvas.width,this.cHeight=this.canvas.height,this.ctx.scale(i,i),this.pixels=Math.floor(this.cWidth*this.cHeight),this.drawFg(),this.setEvent(),this.opts.autoWipe&&setTimeout(function(){t.autoWipe()},100),this.path=[]},reset:function(t){this.ctx._gco("source-over"),this.drawFg(t),this.path=[]},winTcanvasXY:function(t,i,e){var n=t.getBoundingClientRect();return{x:i-n.left,y:e-n.top}},clear:function(){this.ctx.clear(0,0,this.cWidth,this.cHeight)},drawFg:function(t){(this.opts.fg||t)&&("#"===this.opts.fg.charAt(0)||t&&"#"===t.charAt(0)?this.ctx.drawRect(0,0,this.cWidth,this.cHeight,this.opts.fg||t,"fill"):/png|jpg|jpeg/.test(this.opts.fg)&&this.ctx.drawImg(this.opts.fg,0,0,this.wrapWidth,this.wrapHeight))},wipeStart:function(t,i,e){if(void 0!=i){e.startTime=+new Date;var n,s;if(e.opts.autoWipe)n=i.x,s=i.y;else{var o=e.winTcanvasXY(e.canvas,i.touches[0].pageX,i.touches[0].pageY);n=o.x,s=o.y,e.startTime+2e4<e.endTime?e.path=[]:(e.path.push("pause"),e.path.push(o))}t._gco("destination-out")._lineJoin("round")._lineCap("round").sStyle(this.opts.color).lineW(this.opts.size),t.bPath()._arc(n,s,this.opts.size/2,0,2*Math.PI,!0,null,this.opts.color,"fill").cPath(),t.bPath()._moveTo(n,s)}},wipeMove:function(t,i,e){var n,s;if(void 0!=i){if(e.opts.autoWipe)n=i.x,s=i.y;else{var o=e.winTcanvasXY(e.canvas,i.touches[0].pageX,i.touches[0].pageY);n=o.x,s=o.y,e.path.push(o)}t._lineTo(n,s)._stroke()}},wipeEnd:function(t,i,e){e.endTime=+new Date,t.cPath(),e.opts.onswiping.call(e,e.wipePercent(e),JSON.stringify(e.path),JSON.stringify(e.path.slice(e.path.lastIndexOf("pause")))),e.opts.debug&&console.log(JSON.stringify(e.path))},setEvent:function(){var t=this,i=this.ctx;this.canvas.addEventListener("touchstart",function(e){t.wipeStart(i,e,t)}),this.canvas.addEventListener("touchmove",function(e){t.wipeMove(i,e,t)}),this.canvas.addEventListener("touchend",function(e){t.wipeEnd(i,e,t)})},wipePercent:function(t){try{var i;i=t?t:this;for(var e=0,n=i.ctx.getImageData(0,0,i.cWidth,i.cHeight),s=0,o=n.data.length;o>s;s+=4)0===n.data[s]&&0===n.data[s+1]&&0===n.data[s+2]&&0===n.data[s+3]&&e++;return e/i.pixels*100}catch(a){console.log(a)}},similar:function(t,i){for(var e=t.length,n=(i.length,0),s=0;e>s;s++)(t[s].x==i[s].x||t[s].x<=i[s].x+1||t[s].x<=i[s].x-1)&&(t[s].y==i[s].y||t[s].y<=i[s].y+1||t[s].y<=i[s].y-1)&&n++;return Math.floor(n/e*100)},autoWipe:function(t){function i(){h++,e=requestNextAnimationFrame(i),"pause"===o[h]?(n.wipeEnd(s,o[h],n),n.wipeStart(s,o[h],n)):a>h?n.wipeMove(s,o[h],n):h>=a-1&&(cancelAnimate(e),n.wipeEnd(s,o[a-1],n))}var e,n=this,s=this.ctx,o=t||n.opts.data,a=o.length,h=0;o.forEach(function(t){n.path.push(t)}),n.wipeStart(s,o[h],n),requestNextAnimationFrame(i)}};
<commit_msg>修复真机调试时触摸点击无法绘制的问题<commit_after>/*
 * canvas 1.0
 * A simple, canvas CanvasRenderingContext2D.prototype 原型扩展库，便于链式操作；
 * from wbh5.com @Author leiroc
 * Copyright 2015, MIT License
 *
 */
function Wipe(t){this.opts={el:"#wipe",fg:"#ccc",size:10,debug:!1,autoWipe:!1,data:[],onswiping:function(t,i){}};for(var i in t)this.opts[i]=t[i];this.init()}window.requestNextAnimationFrame=function(){var t=void 0,i=void 0,e=void 0,n=0,s=navigator.userAgent,o=0,a=this;return window.webkitRequestAnimationFrame&&(i=function(t){void 0===t&&(t+=new Date),a.callback(t)},t=window.webkitRequestAnimationFrame,window.webkitRequestAnimationFrame=function(i,n){a.callback=e,t(i,n)}),window.mozRequestAnimationFrame&&(o=s.indexOf("rv:"),-1!=s.indexOf("Gecko")&&(n=s.substr(o+3,3),"2.0"===n&&(window.mozRequestAnimationFrame=void 0))),window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t,i){var e,n;window.setTimeout(function(){e=+new Date,t(e),n=+new Date,a.timeout=1e3/60-(n-e)},a.timeout)}}(),window.cancelAnimate=function(t){return window.cancelAnimationFrame(t)},function(t){t.drawRect=function(t,i,e,n,s,o){return"fill"==o?(this.fillStyle=s+"",this.fillRect(t,i,e,n)):"stroke"==o?(this.strokeStyle=s+"",this.strokeRect(t,i,e,n)):"round"==o||alert("type 参数错误"),this},t.clear=function(t,i,e,n){return this.clearRect(t,i,e,n),this},t.roundRect=function(t,i,e,n,s,o,a){return this.beginPath(),this.moveTo(t,i+o),this.lineTo(t,i+n-o),this.quadraticCurveTo(t,i+n,t+o,i+n),this.lineTo(t+e-o,i+n),this.quadraticCurveTo(t+e,i+n,t+e,i+n-o),this.lineTo(t+e,i+o),this.quadraticCurveTo(t+e,i,t+e-o,i),this.lineTo(t+o,i),this.quadraticCurveTo(t,i,t,i+o),"fill"==a?(this.fillStyle=s+"",this.fill()):"stroke"==a&&(this.strokeStyle=s+"",this.stroke(),this.closePath()),this},t._arc=function(t,i,e,n,s,o,a,h,r){return this.beginPath(),this.arc(t,i,e,n,s,o),a&&this.lineTo(a.x,a.y),"fill"==r?(this.fillStyle=h+"",this.fill()):"stroke"==r&&(this.strokeStyle=h+"",this.stroke(),this.closePath()),this},t.triangle=function(t,i,e,n,s){return this.beginPath(),this.moveTo(t,i),this.lineTo(e.x1,e.y1),this.lineTo(e.x2,e.y2),"fill"==s?(this.fillStyle=n+"",this.fill()):"stroke"==s&&(this.strokeStyle=n+"",this.lineTo(t,i),this.stroke(),this.closePath()),this},t.drawImg=function(t,i,e,n,s){var o=this,a=new Image;return a.onload=function(){o.drawImage(a,i,e,n,s)},a.src=t,this},t.lineW=function(t){return this.lineWidth=t,this},t._save=function(){return this.save(),this},t._moveTo=function(t,i){return this.moveTo(t,i),this},t._stroke=function(){return this.stroke(),this},t._lineTo=function(t,i){return this.lineTo(t,i),this},t.bPath=function(){return this.beginPath(),this},t.cPath=function(){return this.closePath(),this},t.sStyle=function(t){return this.strokeStyle=t,this},t._gco=function(t){return this.globalCompositeOperation=t,this},t._lineJoin=function(t){return this.lineJoin=t,this},t._lineCap=function(t){return this.lineCap=t,this}}(CanvasRenderingContext2D.prototype),Wipe.prototype={doc:document,$:function(t){return this.doc.querySelector(t)},init:function(){var t=this,i=window.devicePixelRatio||1;this.devicePixelRatio=i,this.wrap=this.$(this.opts.el),this.wrap.innerHTML=null,this.wrap.appendChild(this.doc.createElement("canvas")),this.wrapWidth=parseInt(this.wrap.offsetWidth),this.wrapHeight=parseInt(this.wrap.offsetHeight),this.wrap.addEventListener("touchmove",function(t){t.preventDefault()}),this.canvas=this.wrap.childNodes[0],this.canvas.style.cssText+="width: 100%; height: 100%",this.ctx=this.canvas.getContext("2d"),this.canvas.setAttribute("width",this.wrapWidth*i),this.canvas.setAttribute("height",this.wrapHeight*i),this.cWidth=this.canvas.width,this.cHeight=this.canvas.height,this.ctx.scale(i,i),this.pixels=Math.floor(this.cWidth*this.cHeight),this.drawFg(),this.setEvent(),this.opts.autoWipe&&setTimeout(function(){t.autoWipe()},100),this.path=[]},reset:function(t){this.ctx._gco("source-over"),this.drawFg(t),this.path=[]},winTcanvasXY:function(t,i,e){var n=t.getBoundingClientRect();return{x:i-n.left,y:e-n.top}},clear:function(){this.ctx.clear(0,0,this.cWidth,this.cHeight)},drawFg:function(t){(this.opts.fg||t)&&("#"===this.opts.fg.charAt(0)||t&&"#"===t.charAt(0)?this.ctx.drawRect(0,0,this.cWidth,this.cHeight,this.opts.fg||t,"fill"):/png|jpg|jpeg/.test(this.opts.fg)&&this.ctx.drawImg(this.opts.fg,0,0,this.wrapWidth,this.wrapHeight))},wipeStart:function(t,i,e){if(void 0!=i){e.startTime=+new Date;var n,s;if(e.opts.autoWipe)n=i.x,s=i.y;else{var o=e.winTcanvasXY(e.canvas,i.touches[0].pageX,i.touches[0].pageY);n=o.x,s=o.y,e.startTime+2e4<e.endTime?e.path=[]:(e.path.push("pause"),e.path.push(o))}t._gco("destination-out")._lineJoin("round")._lineCap("round").sStyle(this.opts.color).lineW(this.opts.size),t.bPath()._arc(n,s,this.opts.size/2,0,2*Math.PI,!0,null,this.opts.color,"fill").cPath(),t.bPath()._moveTo(n,s)}},wipeMove:function(t,i,e){var n,s;if(void 0!=i){if(e.opts.autoWipe)n=i.x,s=i.y;else{var o=e.winTcanvasXY(e.canvas,i.touches[0].pageX,i.touches[0].pageY);n=o.x,s=o.y,e.path.push(o)}t._lineTo(n,s)._stroke()}},wipeEnd:function(t,i,e){e.endTime=+new Date,t.cPath(),e.opts.onswiping.call(e,e.wipePercent(e),JSON.stringify(e.path),JSON.stringify(e.path.slice(e.path.lastIndexOf("pause")))),e.opts.debug&&console.log(JSON.stringify(e.path))},setEvent:function(){var t=this,i=this.ctx;this.canvas.addEventListener("touchstart",function(e){t.wipeStart(i,e,t)}),this.canvas.addEventListener("touchmove",function(e){t.wipeMove(i,e,t)}),this.canvas.addEventListener("touchend",function(e){t.wipeEnd(i,e,t)})},wipePercent:function(t){try{var i;i=t?t:this;for(var e=0,n=i.ctx.getImageData(0,0,i.cWidth,i.cHeight),s=0,o=n.data.length;o>s;s+=4)0===n.data[s]&&0===n.data[s+1]&&0===n.data[s+2]&&0===n.data[s+3]&&e++;return e/i.pixels*100}catch(a){console.log(a)}},similar:function(t,i){for(var e=t.length,n=(i.length,0),s=0;e>s;s++)(t[s].x==i[s].x||t[s].x<=i[s].x+1||t[s].x<=i[s].x-1)&&(t[s].y==i[s].y||t[s].y<=i[s].y+1||t[s].y<=i[s].y-1)&&n++;return Math.floor(n/e*100)},autoWipe:function(t){function i(){h++,e=requestNextAnimationFrame(i),"pause"===o[h]?(n.wipeEnd(s,o[h],n),++h<a?n.wipeStart(s,o[h],n):cancelAnimate(e)):a>h?n.wipeMove(s,o[h],n):h>=a-1&&(cancelAnimate(e),n.wipeEnd(s,o[a-1],n))}var e,n=this,s=this.ctx,o=t||n.opts.data,a=o.length,h=0;for(o.forEach(function(t){n.path.push(t)});a>h&&"pause"===o[h];)h++;a>h&&(n.wipeStart(s,o[h],n),requestNextAnimationFrame(i))}};
<|endoftext|>


<commit_before>const State = reqire('./state');

class World {
  /**
   * Constructs a new world
   */
  constructor() {
    this.states = {};
  }

  /**
   * Adds a state to the world
   */
  add_state(state) {
    if (state instanceof State) {
      return this.states[state.name] = state;
    }

    throw new Error('state is not a State');
  }

  /**
   * Removes the state from the world
   */
  remove_state(state) {
    if (state instanceof State) {
      return delete this.states[state.name];
    }

    if (state instanceof String) {
      return delete this.states[state];
    }

    throw new Error('state is not a State');
  }

  /**
   * Checks wether state is true or false
   */
  is(state_name) {
    if (typeof state_name !== 'string') {
      throw new Error('state_name is not a String');
    }

    if (this.states[state_name] !== undefined) {
      return this.states[state_name].value;
    }

    throw new Error(`state '${state_name}' does not exist in world`);
  }

};

module.exports = World;
<commit_msg>world<commit_after>class World {
  /**
   * Constructs a new world
   */
  constructor() {
    this.state = {};
  }

  /**
   * Adds a state to the world
   */
  add_state(name, state) {
    this.state[name] = state;
  }

  /**
   * Removes the state from the world
   */
  remove_state(name, state) {
    delete this.state[name];
  }

};

module.exports = World;
<|endoftext|>


<commit_before>function _dubug(msg){
    DEBUG && console.log(msg);
}

function callBotAPI(newmsg,callback) {
   //YQL for cross region json ajax
    var yql_url = 'https://query.yahooapis.com/v1/public/yql';
    var url = 'http://www.tuling123.com/openapi/api?key=abab9d3783d6e367e71e56c721e3165a&info='+encodeURIComponent(newmsg);
    $.ajax({
        'url': yql_url,
        'data': {
              'q': 'SELECT * FROM json WHERE url="'+url+'"',
                   'format': 'json',
                   'jsonCompat': 'new',
        },
        'dataType': 'jsonp',
        'success': function(response) {
            ans = response.query.results.json.text;
            callback(ans);
        },
        'error': function() {
            _dubug("ajax error occured");
        }
    });
}

function sendmsg(ans) {
    _dubug("bot resp with: " + ans);
    $('#textInput')[0].value=ans;
    $('.chatSend')[0].click();
    _dubug("msg sent to: " + name);
    $('#conv_filehelper').click();
}

function installbot(chats){
    //add bot notes
    for (i=0;i<chats.length;i++) {
        var bot = document.createElement('div');
        bot.className='bot';
        chats[i].appendChild(bot);
    }

    //listen on bot click event
    $(chats).children('.bot').click(function(e){
        e.stopPropagation();
        $(this).toggleClass('active');
    });

    //add drag drop event to bot div
    jQuery.event.props.push('dataTransfer');
    $(chats).on({
        dragenter: function(e) {
            $(this).addClass('over');
        },
        dragover: function(e) {
            e.preventDefault();
        },
        dragleave: function(e) {
            $(this).removeClass('over');
        },
        drop: function() {
            $(this).find('.bot').toggleClass('active');
        },
    });

    _dubug("installed "+chats.length.toString()+" bots");
}

function buildbothome() {
    //add bot home
    $('#profile').append([
    '
',
        '',
        '',
            '
快把我拖到聊天列表上
',
            '
点击我可以 暂停/恢复
',
        '',
        '',
    '
'].join(''));

    //show tooltip for 10s
    $('img.botico').load(function(){
        $('#bot-wrapper span').show();
        setTimeout(function(){
            $('#bot-wrapper span').hide();
        },10*1000);
    });

    //clear tooltip on mousedown
    $('.bot-home').mousedown(function(){
        $('#bot-wrapper span').hide();
    });

    //listen on bot-home click event
    $('.bot-home').click(function(){
        $('.bot-home').toggleClass('paused');
    });

    //listen drag event
    jQuery.event.props.push('dataTransfer');
    $('.bot-home').on({
        dragstart: function() {
            $(this).css('opacity', '0.5');
            $('.chatListColumn *').css('pointer-events','none');
        },
        dragend: function() {
            $(this).css('opacity', '1');
            $('.chatListColumn *').css('pointer-events','');
            $('.chatListColumn').removeClass('over');
        },
    });
    _dubug("bot home constructed");
}

function botinit(){
    $(document).ready(function(){
        //init bot-home
        buildbothome();
        //init bot divs
        var bots = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")'].join(''))
        installbot(bots);
        _dubug(bots.length.toString()+" bots initiated");
    });
}

function botstart(interval){
    interval = typeof interval !== 'undefined' ? interval : 30;
    setInterval(chatbot,interval*1000);
    _dubug("started with interval: "+interval.toString()+"s");
}

function botupdate(){
    uninstalled = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")',
            ':not(:has(".bot"))'].join(''));
    uninstalled.length && _dubug(uninstalled.length.toString()+" nodes to update");
    uninstalled.length && installbot(uninstalled);
}

function chatbot() {
    botupdate();

    //if paused
    if ( $('.bot-home').hasClass('paused') ) return;
    //if no bot-took-overed
    if ( $('.bot.active').length == 0 )  return;

    //reply in current chat window
    if ( $('.activeColumn:has(".bot.active")').length ) {
        var observer = new MutationObserver(function(mutations) {
         mutations.forEach(function(mutation) {
            e = mutation.addedNodes;
            console.log(e);
            //dirty hack: disconnect every time bot runs
            if (e !== undefined &&
                e.length == 3 &&
                e[1].className == 'chatItem you'){
                oberver.disconnect();
            }
         });
        });
        observer.observe($('#chat_chatmsglist')[0], { childList: true});
    }

    //reply for red dotted item
    //$('#conv_filehelper').click();
    $('.unreadDot:visible,.unreadDotS:visible').each(function()
    {
        is_active = $(this).parent().find(".bot").hasClass("active");
        if (!is_active) return;
        name = $(this).parent().find(".left.name").text();
        _dubug("msg from: " + name);
        $(this).click();
        //Wait till chat box loaded
        setTimeout(function(){
            newmsg = $("#chat_chatmsglist").children(".chatItem.you").last().find("pre").text();
            if (newmsg) {
                _dubug("msg content: " + newmsg);
                callBotAPI(newmsg,sendmsg);
            } else {
                _dubug("no msg found")
            }
        },500);
    });
}

DEBUG = true;
botinit();
botstart(runtimeGlobal.interval);
botupdate();
<commit_msg>测试mutation observer<commit_after>function _dubug(msg){
    DEBUG && console.log(msg);
}

function callBotAPI(newmsg,callback) {
   //YQL for cross region json ajax
    var yql_url = 'https://query.yahooapis.com/v1/public/yql';
    var url = 'http://www.tuling123.com/openapi/api?key=abab9d3783d6e367e71e56c721e3165a&info='+encodeURIComponent(newmsg);
    $.ajax({
        'url': yql_url,
        'data': {
              'q': 'SELECT * FROM json WHERE url="'+url+'"',
                   'format': 'json',
                   'jsonCompat': 'new',
        },
        'dataType': 'jsonp',
        'success': function(response) {
            ans = response.query.results.json.text;
            callback(ans);
        },
        'error': function() {
            _dubug("ajax error occured");
        }
    });
}

function sendmsg(ans) {
    _dubug("bot resp with: " + ans);
    $('#textInput')[0].value=ans;
    $('.chatSend')[0].click();
    _dubug("msg sent to: " + name);
    $('#conv_filehelper').click();
}

function installbot(chats){
    //add bot notes
    for (i=0;i<chats.length;i++) {
        var bot = document.createElement('div');
        bot.className='bot';
        chats[i].appendChild(bot);
    }

    //listen on bot click event
    $(chats).children('.bot').click(function(e){
        e.stopPropagation();
        $(this).toggleClass('active');
    });

    //add drag drop event to bot div
    jQuery.event.props.push('dataTransfer');
    $(chats).on({
        dragenter: function(e) {
            $(this).addClass('over');
        },
        dragover: function(e) {
            e.preventDefault();
        },
        dragleave: function(e) {
            $(this).removeClass('over');
        },
        drop: function() {
            $(this).find('.bot').toggleClass('active');
        },
    });

    _dubug("installed "+chats.length.toString()+" bots");
}

function buildbothome() {
    //add bot home
    $('#profile').append([
    '
',
        '',
        '',
            '
快把我拖到聊天列表上
',
            '
点击我可以 暂停/恢复
',
        '',
        '',
    '
'].join(''));

    //show tooltip for 10s
    $('img.botico').load(function(){
        $('#bot-wrapper span').show();
        setTimeout(function(){
            $('#bot-wrapper span').hide();
        },10*1000);
    });

    //clear tooltip on mousedown
    $('.bot-home').mousedown(function(){
        $('#bot-wrapper span').hide();
    });

    //listen on bot-home click event
    $('.bot-home').click(function(){
        $('.bot-home').toggleClass('paused');
    });

    //listen drag event
    jQuery.event.props.push('dataTransfer');
    $('.bot-home').on({
        dragstart: function() {
            $(this).css('opacity', '0.5');
            $('.chatListColumn *').css('pointer-events','none');
        },
        dragend: function() {
            $(this).css('opacity', '1');
            $('.chatListColumn *').css('pointer-events','');
            $('.chatListColumn').removeClass('over');
        },
    });
    _dubug("bot home constructed");
}

function botinit(){
    $(document).ready(function(){
        //init bot-home
        buildbothome();
        //init bot divs
        var bots = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")'].join(''))
        installbot(bots);
        _dubug(bots.length.toString()+" bots initiated");
    });
}

function botstart(interval){
    interval = typeof interval !== 'undefined' ? interval : 30;
    setInterval(chatbot,interval*1000);
    _dubug("started with interval: "+interval.toString()+"s");
}

function botupdate(){
    uninstalled = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")',
            ':not(:has(".bot"))'].join(''));
    uninstalled.length && _dubug(uninstalled.length.toString()+" nodes to update");
    uninstalled.length && installbot(uninstalled);
}

function chatbot() {
    botupdate();

    //if paused
    if ( $('.bot-home').hasClass('paused') ) return;
    //if no bot-took-overed
    if ( $('.bot.active').length == 0 )  return;

    //reply in current chat window
    if ( $('.activeColumn:has(".bot.active")').length ) {
         if (observer !== 'undefined') observer.disconnet();
         observer = new MutationObserver(function(mutations) {
         mutations.forEach(function(mutation) {
            e = mutation.addedNodes;
            console.log(e);
         });
        });
        observer.observe($('#chat_chatmsglist')[0], { childList: true});
    }

    //reply for red dotted item
    //$('#conv_filehelper').click();
    $('.unreadDot:visible,.unreadDotS:visible').each(function()
    {
        is_active = $(this).parent().find(".bot").hasClass("active");
        if (!is_active) return;
        name = $(this).parent().find(".left.name").text();
        _dubug("msg from: " + name);
        $(this).click();
        //Wait till chat box loaded
        setTimeout(function(){
            newmsg = $("#chat_chatmsglist").children(".chatItem.you").last().find("pre").text();
            if (newmsg) {
                _dubug("msg content: " + newmsg);
                callBotAPI(newmsg,sendmsg);
            } else {
                _dubug("no msg found")
            }
        },500);
    });
}

DEBUG = true;
botinit();
botstart(runtimeGlobal.interval);
botupdate();
<|endoftext|>


<commit_before>function _dubug(msg){
    DEBUG && console.log(msg);
}

function callBotAPI(newmsg,callback) {
   //YQL for cross region json ajax
    var yql_url = 'https://query.yahooapis.com/v1/public/yql';
    var url = 'http://www.tuling123.com/openapi/api?key=abab9d3783d6e367e71e56c721e3165a&info='+encodeURIComponent(newmsg);
    $.ajax({
        'url': yql_url,
        'data': {
              'q': 'SELECT * FROM json WHERE url="'+url+'"',
                   'format': 'json',
                   'jsonCompat': 'new',
        },
        'dataType': 'jsonp',
        'success': function(response) {
            ans = response.query.results.json.text;
            callback(ans);
        },
        'error': function() {
            _dubug("ajax error occured");
        }
    });
}

function sendmsg(ans) {
    _dubug("bot resp with: " + ans);
    $('#textInput')[0].value=ans;
    $('.chatSend')[0].click();
    _dubug("msg sent to: " + name);
    $('#conv_filehelper').click();
}

function installbot(chats){
    //add bot notes
    for (i=0;i<chats.length;i++) {
        var bot = document.createElement('div');
        bot.className='bot';
        chats[i].appendChild(bot);
    }

    //listen on bot click event
    $(chats).children('.bot').click(function(e){
        e.stopPropagation();
        $(this).toggleClass('active');
    });

    //add drag drop event to bot div
    jQuery.event.props.push('dataTransfer');
    $(chats).on({
        dragenter: function(e) {
            $(this).addClass('over');
        },
        dragover: function(e) {
            e.preventDefault();
        },
        dragleave: function(e) {
            $(this).removeClass('over');
        },
        drop: function() {
            $(this).find('.bot').toggleClass('active');
        },
    });

    _dubug("installed "+chats.length.toString()+" bots");
}

function buildbothome() {
    //add bot home
    $('#profile').append([
    '
',
        '',
        '',
            '
快把我拖到聊天列表上
',
            '
点击我可以 暂停/恢复
',
        '',
        '',
    '
'].join(''));

    //show tooltip for 10s
    setTimeout(function(){
        $('img.botico').on('load',function(){
            $('#bot-wrapper span').show();
            setTimeout(function(){
                $('#bot-wrapper span').hide();
            },10*1000);
        });
    },500);

    //clear tooltip on mousedown
    $('.bot-home').mousedown(function(){
        $('#bot-wrapper span').hide();
    });

    //listen on bot-home click event
    $('.bot-home').click(function(){
        $('.bot-home').toggleClass('paused');
    });

    //listen drag event
    jQuery.event.props.push('dataTransfer');
    $('.bot-home').on({
        dragstart: function() {
            $(this).css('opacity', '0.5');
            $('.chatListColumn *').css('pointer-events','none');
        },
        dragend: function() {
            $(this).css('opacity', '1');
            $('.chatListColumn *').css('pointer-events','');
            $('.chatListColumn').removeClass('over');
        },
    });
    _dubug("bot home constructed");
}

function botinit(){
    $(document).ready(function(){
        //init bot-home
        buildbothome();
        //init bot divs
        var bots = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")'].join(''))
        installbot(bots);
        _dubug(bots.length.toString()+" bots initiated");
    });
}

function botstart(interval){
    setInterval(chatbot,interval*1000);
    _dubug("started with interval: "+interval.toString()+"s");
}

function botupdate(){
    uninstalled = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")',
            ':not(:has(".bot"))'].join(''));
    uninstalled.length && installbot(uninstalled);
    _dubug(uninstalled.length.toString()+" nodes to update");
}

function chatbot() {
    botupdate();
    //if paused
    if ( $('.bot-home').hasClass('paused') ) return;
    //if no bot-took-overed
    if ( $('.bot.active').length == 0 )  return;

    $('#conv_filehelper').click();
    $('.unreadDot:visible,.unreadDotS:visible').each(function()
    {
        is_active = $(this).parent().find(".bot").hasClass("active");
        if (!is_active) return;
        name = $(this).parent().find(".left.name").text();
        _dubug("msg from: " + name);
        $(this).click();
        //Wait till chat box loaded
        setTimeout(function(){
            newmsg = $("#chat_chatmsglist").children(".chatItem.you").last().find("pre").text();
            if (newmsg) {
                _dubug("msg content: " + newmsg);
                callBotAPI(newmsg,sendmsg);
            } else {
                _dubug("no msg found")
            }
        },500);
    });
}

DEBUG = true;
botinit();
botstart(30);
botupdate();
<commit_msg>之前tooltip timing问题修复错误<commit_after>function _dubug(msg){
    DEBUG && console.log(msg);
}

function callBotAPI(newmsg,callback) {
   //YQL for cross region json ajax
    var yql_url = 'https://query.yahooapis.com/v1/public/yql';
    var url = 'http://www.tuling123.com/openapi/api?key=abab9d3783d6e367e71e56c721e3165a&info='+encodeURIComponent(newmsg);
    $.ajax({
        'url': yql_url,
        'data': {
              'q': 'SELECT * FROM json WHERE url="'+url+'"',
                   'format': 'json',
                   'jsonCompat': 'new',
        },
        'dataType': 'jsonp',
        'success': function(response) {
            ans = response.query.results.json.text;
            callback(ans);
        },
        'error': function() {
            _dubug("ajax error occured");
        }
    });
}

function sendmsg(ans) {
    _dubug("bot resp with: " + ans);
    $('#textInput')[0].value=ans;
    $('.chatSend')[0].click();
    _dubug("msg sent to: " + name);
    $('#conv_filehelper').click();
}

function installbot(chats){
    //add bot notes
    for (i=0;i<chats.length;i++) {
        var bot = document.createElement('div');
        bot.className='bot';
        chats[i].appendChild(bot);
    }

    //listen on bot click event
    $(chats).children('.bot').click(function(e){
        e.stopPropagation();
        $(this).toggleClass('active');
    });

    //add drag drop event to bot div
    jQuery.event.props.push('dataTransfer');
    $(chats).on({
        dragenter: function(e) {
            $(this).addClass('over');
        },
        dragover: function(e) {
            e.preventDefault();
        },
        dragleave: function(e) {
            $(this).removeClass('over');
        },
        drop: function() {
            $(this).find('.bot').toggleClass('active');
        },
    });

    _dubug("installed "+chats.length.toString()+" bots");
}

function buildbothome() {
    //add bot home
    $('#profile').append([
    '
',
        '',
        '',
            '
快把我拖到聊天列表上
',
            '
点击我可以 暂停/恢复
',
        '',
        '',
    '
'].join(''));

    //show tooltip for 10s
    $('img.botico').load(function(){
        $('#bot-wrapper span').show();
        setTimeout(function(){
            $('#bot-wrapper span').hide();
        },10*1000);
    });

    //clear tooltip on mousedown
    $('.bot-home').mousedown(function(){
        $('#bot-wrapper span').hide();
    });

    //listen on bot-home click event
    $('.bot-home').click(function(){
        $('.bot-home').toggleClass('paused');
    });

    //listen drag event
    jQuery.event.props.push('dataTransfer');
    $('.bot-home').on({
        dragstart: function() {
            $(this).css('opacity', '0.5');
            $('.chatListColumn *').css('pointer-events','none');
        },
        dragend: function() {
            $(this).css('opacity', '1');
            $('.chatListColumn *').css('pointer-events','');
            $('.chatListColumn').removeClass('over');
        },
    });
    _dubug("bot home constructed");
}

function botinit(){
    $(document).ready(function(){
        //init bot-home
        buildbothome();
        //init bot divs
        var bots = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")'].join(''))
        installbot(bots);
        _dubug(bots.length.toString()+" bots initiated");
    });
}

function botstart(interval){
    setInterval(chatbot,interval*1000);
    _dubug("started with interval: "+interval.toString()+"s");
}

function botupdate(){
    uninstalled = $(['.chatListColumn',
            ':not([un="newsapp"])',
            ':not([un="filehelper"])',
            ':not([un="fmessage"])',
            ':not(".loadMoreConv")',
            ':not(:has(".bot"))'].join(''));
    uninstalled.length && installbot(uninstalled);
    _dubug(uninstalled.length.toString()+" nodes to update");
}

function chatbot() {
    botupdate();
    //if paused
    if ( $('.bot-home').hasClass('paused') ) return;
    //if no bot-took-overed
    if ( $('.bot.active').length == 0 )  return;

    $('#conv_filehelper').click();
    $('.unreadDot:visible,.unreadDotS:visible').each(function()
    {
        is_active = $(this).parent().find(".bot").hasClass("active");
        if (!is_active) return;
        name = $(this).parent().find(".left.name").text();
        _dubug("msg from: " + name);
        $(this).click();
        //Wait till chat box loaded
        setTimeout(function(){
            newmsg = $("#chat_chatmsglist").children(".chatItem.you").last().find("pre").text();
            if (newmsg) {
                _dubug("msg content: " + newmsg);
                callBotAPI(newmsg,sendmsg);
            } else {
                _dubug("no msg found")
            }
        },500);
    });
}

DEBUG = true;
botinit();
botstart(30);
botupdate();
<|endoftext|>


<commit_before>function Player() {
  this.x = Math.random() * width | 0;
  this.y = Math.random() * height| 0;

  // Image h/w
  this.h = this.w = 36;

  this.dx = 0;
  this.dy = 0;

  this.turnSpeed = 0.001;
  this.thrust = 0.1;
  this.angle = 0;
  this.exploded = false;

  this.name = name;

  this.img = new Image();
  this.img.src = 'http://retroships.com/generate.png?&size=3&cB=300&seed=' + name;
}

inherits(Player, CanvasItem);

Player.prototype.update = function () {
  if (keys[32]) {
    if (thisPlayer.exploded) {
      thisPlayer.reset();
    } else {
      thisPlayer.fire();
    }
  }
  if (keys[90]) {
    thisPlayer.explode();
  }
  // Turns
  if (keys[39]) {
    this.angle += this.turnSpeed * -1;
  }

  if (keys[37]) {
    this.angle += this.turnSpeed * 1;
  }

  // Math stuff to determine direction
  var radians = this.angle / Math.PI * 180;

  // Adjust speeds for player input
  if (keys[38]) {
    this.dx -= Math.sin(radians) * this.thrust;
    this.dy -= Math.cos(radians) * this.thrust;
  }
  if (keys[40]) {
    this.dx += Math.sin(radians) * this.thrust;
    this.dy += Math.cos(radians) * this.thrust;
  }
  // Actually make changes
  this.x += this.dx;
  this.y += this.dy;

  // Check for wraparound
  if (this.x < 0) {
    this.x = width;
  } else if (this.x > width) {
    this.x = 0;
  }
  if (this.y < 0) {
    this.y = height;
  } else if (this.y > height) {
    this.y = 0;
  }

  // There's totally friction in space.
  this.dx *= 0.98;
  this.dy *= 0.98;
};
Player.prototype.destroyed = function () {
  return this.exploded;
};
Player.prototype.explode = function () {
  if (!this.exploded) {
    this.exploded = true;
    boom(this.x, this.y, this.dx, this.dy);
  }
};
Player.prototype.fire = function () {
  var radians = (this.angle + 0.055) * (180/Math.PI);

  var xx = this.x + (this.w/2 * Math.cos(-(this.angle + 0.0275) * (180/Math.PI)));
  var yy = this.y + (this.w/2 * Math.sin(-(this.angle + 0.0275) * (180/Math.PI)));

  var r = this.w/2;
  playerBullets.create({
    x: xx,
    y: yy,
    dx: Math.sin(radians) * 10,
    dy: Math.cos(radians) * 10,
    c: 'rgba(0,24,234,1)',
    r: 7,
    decay: 0.06
  });
}

function FBPlayer (params) {
  this.x = params.x;
  this.y = params.y;
  this.angle = params.angle;

  this.name = params.name;

  this.h = this.w = 36;

  this.connected = true;
  this.exploded = !!params.exploded;

  this.img = new Image();
  this.img.src = 'http://retroships.com/generate.png?&size=3&seed=' + this.name;

  this.lastUpdated = new Date();
};

inherits(FBPlayer, CanvasItem);

FBPlayer.prototype.update = function () {
  if (playerBullets.colliding(this.x, this.y)) {
    socket.emit('exploded', {
      name: this.name,
      killer: name
    });
  }
  if (this.firing && !this.exploded) {
    this.fire();
  }
};
FBPlayer.prototype.destroyed = function () {
  return !this.connected
};

FBPlayer.prototype.render = Player.prototype.render = function () {
  context.fillStyle = 'white';
  context.font = '12px Arial';
  var w = context.measureText(this.name).width;
  context.fillText(this.name, this.x - (w/2), this.y + this.h);
  if (this.exploded) { return; }
  context.save();
  context.translate(this.x, this.y);
  context.rotate(-(this.angle + 0.055) * (180/Math.PI));
  context.drawImage(this.img, -this.w/2, -this.h/2);
  context.restore();
};
FBPlayer.prototype.reset = Player.prototype.reset = function (params) {
  if (!this.exploded) { return; }

  // Crummy workaround
  if (!params) {
    // We're a player
    socket.emit('reset', {name: name});
  }
  this.constructor(params);
};
FBPlayer.prototype.fire = function () {
  var radians = (this.angle + 0.055) * (180/Math.PI);

  var xx = this.x + (this.w/2 * Math.cos(-(this.angle + 0.0275) * (180/Math.PI)));
  var yy = this.y + (this.w/2 * Math.sin(-(this.angle + 0.0275) * (180/Math.PI)));

  var r = this.w/2;
  particles.create({
    x: xx,
    y: yy,
    dx: Math.sin(radians) * 10,
    dy: Math.cos(radians) * 10,
    c: 'rgba(287,3,24,1)',
    r: 7,
    decay: 0.06
  });
};<commit_msg>players can no longer move after exploding<commit_after>function Player() {
  this.x = Math.random() * width | 0;
  this.y = Math.random() * height| 0;

  // Image h/w
  this.h = this.w = 36;

  this.dx = 0;
  this.dy = 0;

  this.turnSpeed = 0.001;
  this.thrust = 0.1;
  this.angle = 0;
  this.exploded = false;

  this.name = name;

  this.img = new Image();
  this.img.src = 'http://retroships.com/generate.png?&size=3&cB=300&seed=' + name;
}

inherits(Player, CanvasItem);

Player.prototype.update = function () {
  if (keys[32]) {
    if (thisPlayer.exploded) {
      thisPlayer.reset();
    } else {
      thisPlayer.fire();
    }
  }
  if (keys[90]) {
    thisPlayer.explode();
  }

  if (this.exploded) { return; }

  // Turns
  if (keys[39]) {
    this.angle += this.turnSpeed * -1;
  }

  if (keys[37]) {
    this.angle += this.turnSpeed * 1;
  }

  // Math stuff to determine direction
  var radians = this.angle / Math.PI * 180;

  // Adjust speeds for player input
  if (keys[38]) {
    this.dx -= Math.sin(radians) * this.thrust;
    this.dy -= Math.cos(radians) * this.thrust;
  }
  if (keys[40]) {
    this.dx += Math.sin(radians) * this.thrust;
    this.dy += Math.cos(radians) * this.thrust;
  }
  // Actually make changes
  this.x += this.dx;
  this.y += this.dy;

  // Check for wraparound
  if (this.x < 0) {
    this.x = width;
  } else if (this.x > width) {
    this.x = 0;
  }
  if (this.y < 0) {
    this.y = height;
  } else if (this.y > height) {
    this.y = 0;
  }

  // There's totally friction in space.
  this.dx *= 0.98;
  this.dy *= 0.98;
};
Player.prototype.destroyed = function () {
  return this.exploded;
};
Player.prototype.explode = function () {
  if (!this.exploded) {
    this.exploded = true;
    boom(this.x, this.y, this.dx, this.dy);
  }
};
Player.prototype.fire = function () {
  var radians = (this.angle + 0.055) * (180/Math.PI);

  var xx = this.x + (this.w/2 * Math.cos(-(this.angle + 0.0275) * (180/Math.PI)));
  var yy = this.y + (this.w/2 * Math.sin(-(this.angle + 0.0275) * (180/Math.PI)));

  var r = this.w/2;
  playerBullets.create({
    x: xx,
    y: yy,
    dx: Math.sin(radians) * 10,
    dy: Math.cos(radians) * 10,
    c: 'rgba(0,24,234,1)',
    r: 7,
    decay: 0.06
  });
}

function FBPlayer (params) {
  this.x = params.x;
  this.y = params.y;
  this.angle = params.angle;

  this.name = params.name;

  this.h = this.w = 36;

  this.connected = true;
  this.exploded = !!params.exploded;

  this.img = new Image();
  this.img.src = 'http://retroships.com/generate.png?&size=3&seed=' + this.name;

  this.lastUpdated = new Date();
};

inherits(FBPlayer, CanvasItem);

FBPlayer.prototype.update = function () {
  if (playerBullets.colliding(this.x, this.y)) {
    socket.emit('exploded', {
      name: this.name,
      killer: name
    });
  }
  if (this.firing && !this.exploded) {
    this.fire();
  }
};
FBPlayer.prototype.destroyed = function () {
  return !this.connected
};

FBPlayer.prototype.render = Player.prototype.render = function () {
  context.fillStyle = 'white';
  context.font = '12px Arial';
  var w = context.measureText(this.name).width;
  context.fillText(this.name, this.x - (w/2), this.y + this.h);
  if (this.exploded) { return; }
  context.save();
  context.translate(this.x, this.y);
  context.rotate(-(this.angle + 0.055) * (180/Math.PI));
  context.drawImage(this.img, -this.w/2, -this.h/2);
  context.restore();
};
FBPlayer.prototype.reset = Player.prototype.reset = function (params) {
  if (!this.exploded) { return; }

  // Crummy workaround
  if (!params) {
    // We're a player
    socket.emit('reset', {name: name});
  }
  this.constructor(params);
};
FBPlayer.prototype.fire = function () {
  var radians = (this.angle + 0.055) * (180/Math.PI);

  var xx = this.x + (this.w/2 * Math.cos(-(this.angle + 0.0275) * (180/Math.PI)));
  var yy = this.y + (this.w/2 * Math.sin(-(this.angle + 0.0275) * (180/Math.PI)));

  var r = this.w/2;
  particles.create({
    x: xx,
    y: yy,
    dx: Math.sin(radians) * 10,
    dy: Math.cos(radians) * 10,
    c: 'rgba(287,3,24,1)',
    r: 7,
    decay: 0.06
  });
};<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var routes = require('./app/routes/index.js');
var models = require('./app/models/urls.js')
var mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/urls');

function getNewUrl(orig){
    var db = mongoose.connection;
    db.once('open', function(){

        var url = models.url;
        var newUrl = new url({original : orig});

        url.count({original : orig}, function(err, count){
            if(err){throw err}
            if(count === 0){
                newUrl.save();
                console.log('created a new url for ' + orig);
            }else{
                console.log('failed to create a new url for ' + orig);
            }
        })
        db.close();
    })
}

function getUrls(){
    var db = mongoose.connection;
    db.once('open', function(){
        var url = models.url;
        url.find(function(err,urls){
            if(err){throw err}
            console.log(urls);
            return urls;
        });
        db.close();
    })
}

module.exports.getNewUrl = getNewUrl;
module.exports.getUrls = getUrls;<commit_msg>Added comments to show error<commit_after>var express = require('express');
var app = express();
var routes = require('./app/routes/index.js');
var models = require('./app/models/urls.js')
var mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/urls');

function getNewUrl(orig){
    var db = mongoose.connection;
    db.once('open', function(){
        console.log("test"); //This and below don't happen
        var url = models.url;
        var newUrl = new url({original : orig});

        url.count({original : orig}, function(err, count){
            if(err){throw err}
            if(count === 0){
                newUrl.save();
                console.log('created a new url for ' + orig);
            }else{
                console.log('failed to create a new url for ' + orig);
            }
        })
        db.close();
    })
}

function getUrls(){
    var db = mongoose.connection;
    db.once('open', function(){
        console.log("test"); //This and below don't happen
        var url = models.url;
        url.find(function(err,urls){
            if(err){throw err}
            console.log(urls);
            return urls;
        });
        db.close();
    })
}

module.exports.getNewUrl = getNewUrl;
module.exports.getUrls = getUrls;<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name Shape
 *
 * @class
 *
 * @extends Item
 */
var Shape = Item.extend(/** @lends Shape# */{
	_class: 'Shape',
	_transformContent: false,

	isEmpty: function() {
		// A shape can never be "empty" in the sense that it does not hold a
		// definition. This is required for Group#bounds to work correctly when
		// containing a Shape.
		return false;
	},

	initialize: function Shape(type, point, size, props) {
		this._initialize(props, point);
		this._type = type;
		this._size = size;
	},

	/**
	 * The size of the shape.
	 *
	 * @type Size
	 * @bean
	 */
	getSize: function() {
		var size = this._size;
		return new LinkedSize(size.width, size.height, this, 'setSize');
	},

	setSize: function(/* size */) {
		var size = Size.read(arguments);
		if (!this._size.equals(size)) {
			this._size.set(size.width, size.height);
			this._changed(/*#=*/ Change.GEOMETRY);
		}
	},

	/**
	 * The radius of the shape if it is a circle.
	 *
	 * @type Size
	 * @bean
	 */
	getRadius: function() {
		var size = this._size;
		// Average half of width & height for radius...
		return (size.width + size.height) / 4;
	},

	setRadius: function(radius) {
		var size = radius * 2;
		this.setSize(size, size);
	},

	_draw: function(ctx, param) {
		var style = this._style,
			size = this._size,
			width = size.width,
			height = size.height,
			fillColor = style.getFillColor(),
			strokeColor = style.getStrokeColor();
		if (fillColor || strokeColor || param.clip) {
			ctx.beginPath();
			switch (this._type) {
			case 'rect':
				ctx.rect(-width / 2, -height / 2, width, height);
				break;
			case 'circle':
				// Average half of width & height for radius...
				ctx.arc(0, 0, (width + height) / 4, 0, Math.PI * 2, true);
				break;
			case 'ellipse':
				// Use four bezier curves and KAPPA value to aproximate ellipse
				var mx = width / 2,
					my = height / 2,
					kappa = Numerical.KAPPA,
					cx = mx * kappa,
					cy = my * kappa;
				ctx.moveTo(-mx, 0);
				ctx.bezierCurveTo(-mx, -cy, -cx, -my, 0, -my);
				ctx.bezierCurveTo(cx, -my, mx, -cy, mx, 0);
				ctx.bezierCurveTo(mx, cy, cx, my, 0, my);
				ctx.bezierCurveTo(-cx, my, -mx, cy, -mx, 0);
				break;
			}
		}
		if (!param.clip && (fillColor || strokeColor)) {
			this._setStyles(ctx);
			if (fillColor)
				ctx.fill();
			if (strokeColor)
				ctx.stroke();
		}
	},

	_canComposite: function() {
		// A path with only a fill  or a stroke can be directly blended, but if
		// it has both, it needs to be drawn into a separate canvas first.
		return !(this.hasFill() && this.hasStroke());
	},

	_getBounds: function(getter, matrix) {
		var rect = new Rectangle(this._size).setCenter(0, 0);
		if (getter !== 'getBounds' && this.hasStroke())
			rect = rect.expand(this.getStrokeWidth());
		return matrix ? matrix._transformBounds(rect) : rect;
	},

	_contains: function _contains(point) {
		switch (this._type) {
		case 'rect':
			return _contains.base.call(this, point);
		case 'circle':
		case 'ellipse':
			return point.divide(this._size).getLength() <= 0.5;
		}
	},

	_hitTest: function _hitTest(point) {
		if (this.hasStroke()) {
			var type = this._type,
				strokeWidth = this.getStrokeWidth();
			switch (type) {
			case 'rect':
				var rect = new Rectangle(this._size).setCenter(0, 0),
					outer = rect.expand(strokeWidth),
					inner = rect.expand(-strokeWidth);
				if (outer._containsPoint(point) && !inner._containsPoint(point))
					return new HitResult('stroke', this);
				break;
			case 'circle':
			case 'ellipse':
				var size = this._size,
					width = size.width,
					height = size.height,
					radius;
				if (type === 'ellipse') {
					// Calculate ellipse radius at angle
					var angle = point.getAngleInRadians(),
						x = width * Math.sin(angle),
						y = height * Math.cos(angle);
					radius = width * height / (2 * Math.sqrt(x * x + y * y));
				} else {
					// Average half of width & height for radius...
					radius = (width + height) / 4;
				}
				if (2 * Math.abs(point.getLength() - radius) <= strokeWidth)
					return new HitResult('stroke', this);
				break;
			}
		}
		return _hitTest.base.apply(this, arguments);
	},

	statics: new function() {
		function createShape(type, point, size, args) {
			return new Shape(type, point, size, Base.getNamed(args));
		}

		return /** @lends Shape */{
			/**
			 * Creates a circular Shape item.
			 *
			 * @param {Point} center the center point of the circle
			 * @param {Number} radius the radius of the circle
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var shape = new Shape.Circle(new Point(80, 50), 30);
			 * shape.strokeColor = 'black';
			 *
			 * @example {@paperscript} // Using object notation
			 * var shape = new Shape.Circle({
			 * 	center: [80, 50],
			 * 	radius: 30,
			 * 	strokeColor: 'black'
			 * });
			 */
			Circle: function(/* center, radius */) {
				var center = Point.readNamed(arguments, 'center'),
					radius = Base.readNamed(arguments, 'radius');
				return createShape('circle', center, new Size(radius * 2),
						arguments);
			},

			/**
			 * Creates a rectangular Shape item from the passed point and size.
			 *
			 * @name Shape.Rectangle
			 * @param {Point} point
			 * @param {Size} size
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var point = new Point(20, 20);
			 * var size = new Size(60, 60);
			 * var shape = new Shape.Rectangle(point, size);
			 * shape.strokeColor = 'black';
			 *
			 * @example {@paperscript} // Using object notation
			 * var shape = new Shape.Rectangle({
			 * 	point: [20, 20],
			 * 	size: [60, 60],
			 * 	strokeColor: 'black'
			 * });
			 */
			/**
			 * Creates a rectanglular Shape item from the passed points. These
			 * do not necessarily need to be the top left and bottom right
			 * corners, the constructor figures out how to fit a rectangle
			 * between them.
			 *
			 * @name Shape.Rectangle
			 * @param {Point} from The first point defining the rectangle
			 * @param {Point} to The second point defining the rectangle
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var from = new Point(20, 20);
			 * var to = new Point(80, 80);
			 * var shape = new Shape.Rectangle(from, to);
			 * shape.strokeColor = 'black';
			 *
			 * @example {@paperscript} // Using object notation
			 * var shape = new Shape.Rectangle({
			 * 	from: [20, 20],
			 * 	to: [80, 80],
			 * 	strokeColor: 'black'
			 * });
			 */
			/**
			 * Creates a rectangular Shape item from the passed abstract
			 * {@link Rectangle}.
			 *
			 * @name Shape.Rectangle
			 * @param {Rectangle} rectangle
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var rectangle = new Rectangle({
			 * 	point: new Point(20, 20),
			 * 	size: new Size(60, 60)
			 * });
			 * var shape = new Shape.Rectangle(rectangle);
			 * shape.strokeColor = 'black';
			 *
			 * @example {@paperscript}
			 * var rectangle = new Rectangle({
			 * 	point: [20, 20],
			 * 	size: [60, 60]
			 * });
			 *
			 * var shape = new Shape.Rectangle({
			 * 	rectangle: rectangle,
			 * 	strokeColor: 'black'
			 * });
			 */
			Rectangle: function(/* rectangle */) {
				var rect = Rectangle.readNamed(arguments, 'rectangle');
				return createShape('rect', rect.getCenter(true),
						rect.getSize(true), arguments);
			},

			/**
			 * Creates an elliptic Shape item.
			 *
			 * @param {Rectangle} rectangle
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var rectangle = new Rectangle({
			 * 	point: [20, 20],
			 * 	size: [180, 60]
			 * });
			 * var shape = new Shape.Ellipse(rectangle);
			 * shape.fillColor = 'black';
			 *
			 * @example {@paperscript} // Using object notation
			 * var shape = new Shape.Ellipse({
			 * 	point: [20, 20],
			 * 	size: [180, 60],
			 * 	fillColor: 'black'
			 * });
			 */
			Ellipse: function(/* rectangle */) {
				var rect = Rectangle.readNamed(arguments, 'rectangle');
				return createShape('ellipse', rect.getCenter(true),
						rect.getSize(true), arguments);
			}
		};
	}
});
<commit_msg>Move Shape#isEmpty() to right place.<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name Shape
 *
 * @class
 *
 * @extends Item
 */
var Shape = Item.extend(/** @lends Shape# */{
	_class: 'Shape',
	_transformContent: false,

	initialize: function Shape(type, point, size, props) {
		this._initialize(props, point);
		this._type = type;
		this._size = size;
	},

	/**
	 * The size of the shape.
	 *
	 * @type Size
	 * @bean
	 */
	getSize: function() {
		var size = this._size;
		return new LinkedSize(size.width, size.height, this, 'setSize');
	},

	setSize: function(/* size */) {
		var size = Size.read(arguments);
		if (!this._size.equals(size)) {
			this._size.set(size.width, size.height);
			this._changed(/*#=*/ Change.GEOMETRY);
		}
	},

	/**
	 * The radius of the shape if it is a circle.
	 *
	 * @type Size
	 * @bean
	 */
	getRadius: function() {
		var size = this._size;
		// Average half of width & height for radius...
		return (size.width + size.height) / 4;
	},

	setRadius: function(radius) {
		var size = radius * 2;
		this.setSize(size, size);
	},

	isEmpty: function() {
		// A shape can never be "empty" in the sense that it does not hold a
		// definition. This is required for Group#bounds to work correctly when
		// containing a Shape.
		return false;
	},

	_draw: function(ctx, param) {
		var style = this._style,
			size = this._size,
			width = size.width,
			height = size.height,
			fillColor = style.getFillColor(),
			strokeColor = style.getStrokeColor();
		if (fillColor || strokeColor || param.clip) {
			ctx.beginPath();
			switch (this._type) {
			case 'rect':
				ctx.rect(-width / 2, -height / 2, width, height);
				break;
			case 'circle':
				// Average half of width & height for radius...
				ctx.arc(0, 0, (width + height) / 4, 0, Math.PI * 2, true);
				break;
			case 'ellipse':
				// Use four bezier curves and KAPPA value to aproximate ellipse
				var mx = width / 2,
					my = height / 2,
					kappa = Numerical.KAPPA,
					cx = mx * kappa,
					cy = my * kappa;
				ctx.moveTo(-mx, 0);
				ctx.bezierCurveTo(-mx, -cy, -cx, -my, 0, -my);
				ctx.bezierCurveTo(cx, -my, mx, -cy, mx, 0);
				ctx.bezierCurveTo(mx, cy, cx, my, 0, my);
				ctx.bezierCurveTo(-cx, my, -mx, cy, -mx, 0);
				break;
			}
		}
		if (!param.clip && (fillColor || strokeColor)) {
			this._setStyles(ctx);
			if (fillColor)
				ctx.fill();
			if (strokeColor)
				ctx.stroke();
		}
	},

	_canComposite: function() {
		// A path with only a fill  or a stroke can be directly blended, but if
		// it has both, it needs to be drawn into a separate canvas first.
		return !(this.hasFill() && this.hasStroke());
	},

	_getBounds: function(getter, matrix) {
		var rect = new Rectangle(this._size).setCenter(0, 0);
		if (getter !== 'getBounds' && this.hasStroke())
			rect = rect.expand(this.getStrokeWidth());
		return matrix ? matrix._transformBounds(rect) : rect;
	},

	_contains: function _contains(point) {
		switch (this._type) {
		case 'rect':
			return _contains.base.call(this, point);
		case 'circle':
		case 'ellipse':
			return point.divide(this._size).getLength() <= 0.5;
		}
	},

	_hitTest: function _hitTest(point) {
		if (this.hasStroke()) {
			var type = this._type,
				strokeWidth = this.getStrokeWidth();
			switch (type) {
			case 'rect':
				var rect = new Rectangle(this._size).setCenter(0, 0),
					outer = rect.expand(strokeWidth),
					inner = rect.expand(-strokeWidth);
				if (outer._containsPoint(point) && !inner._containsPoint(point))
					return new HitResult('stroke', this);
				break;
			case 'circle':
			case 'ellipse':
				var size = this._size,
					width = size.width,
					height = size.height,
					radius;
				if (type === 'ellipse') {
					// Calculate ellipse radius at angle
					var angle = point.getAngleInRadians(),
						x = width * Math.sin(angle),
						y = height * Math.cos(angle);
					radius = width * height / (2 * Math.sqrt(x * x + y * y));
				} else {
					// Average half of width & height for radius...
					radius = (width + height) / 4;
				}
				if (2 * Math.abs(point.getLength() - radius) <= strokeWidth)
					return new HitResult('stroke', this);
				break;
			}
		}
		return _hitTest.base.apply(this, arguments);
	},

	statics: new function() {
		function createShape(type, point, size, args) {
			return new Shape(type, point, size, Base.getNamed(args));
		}

		return /** @lends Shape */{
			/**
			 * Creates a circular Shape item.
			 *
			 * @param {Point} center the center point of the circle
			 * @param {Number} radius the radius of the circle
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var shape = new Shape.Circle(new Point(80, 50), 30);
			 * shape.strokeColor = 'black';
			 *
			 * @example {@paperscript} // Using object notation
			 * var shape = new Shape.Circle({
			 * 	center: [80, 50],
			 * 	radius: 30,
			 * 	strokeColor: 'black'
			 * });
			 */
			Circle: function(/* center, radius */) {
				var center = Point.readNamed(arguments, 'center'),
					radius = Base.readNamed(arguments, 'radius');
				return createShape('circle', center, new Size(radius * 2),
						arguments);
			},

			/**
			 * Creates a rectangular Shape item from the passed point and size.
			 *
			 * @name Shape.Rectangle
			 * @param {Point} point
			 * @param {Size} size
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var point = new Point(20, 20);
			 * var size = new Size(60, 60);
			 * var shape = new Shape.Rectangle(point, size);
			 * shape.strokeColor = 'black';
			 *
			 * @example {@paperscript} // Using object notation
			 * var shape = new Shape.Rectangle({
			 * 	point: [20, 20],
			 * 	size: [60, 60],
			 * 	strokeColor: 'black'
			 * });
			 */
			/**
			 * Creates a rectanglular Shape item from the passed points. These
			 * do not necessarily need to be the top left and bottom right
			 * corners, the constructor figures out how to fit a rectangle
			 * between them.
			 *
			 * @name Shape.Rectangle
			 * @param {Point} from The first point defining the rectangle
			 * @param {Point} to The second point defining the rectangle
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var from = new Point(20, 20);
			 * var to = new Point(80, 80);
			 * var shape = new Shape.Rectangle(from, to);
			 * shape.strokeColor = 'black';
			 *
			 * @example {@paperscript} // Using object notation
			 * var shape = new Shape.Rectangle({
			 * 	from: [20, 20],
			 * 	to: [80, 80],
			 * 	strokeColor: 'black'
			 * });
			 */
			/**
			 * Creates a rectangular Shape item from the passed abstract
			 * {@link Rectangle}.
			 *
			 * @name Shape.Rectangle
			 * @param {Rectangle} rectangle
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var rectangle = new Rectangle({
			 * 	point: new Point(20, 20),
			 * 	size: new Size(60, 60)
			 * });
			 * var shape = new Shape.Rectangle(rectangle);
			 * shape.strokeColor = 'black';
			 *
			 * @example {@paperscript}
			 * var rectangle = new Rectangle({
			 * 	point: [20, 20],
			 * 	size: [60, 60]
			 * });
			 *
			 * var shape = new Shape.Rectangle({
			 * 	rectangle: rectangle,
			 * 	strokeColor: 'black'
			 * });
			 */
			Rectangle: function(/* rectangle */) {
				var rect = Rectangle.readNamed(arguments, 'rectangle');
				return createShape('rect', rect.getCenter(true),
						rect.getSize(true), arguments);
			},

			/**
			 * Creates an elliptic Shape item.
			 *
			 * @param {Rectangle} rectangle
			 * @return {Shape} the newly created shape
			 *
			 * @example {@paperscript}
			 * var rectangle = new Rectangle({
			 * 	point: [20, 20],
			 * 	size: [180, 60]
			 * });
			 * var shape = new Shape.Ellipse(rectangle);
			 * shape.fillColor = 'black';
			 *
			 * @example {@paperscript} // Using object notation
			 * var shape = new Shape.Ellipse({
			 * 	point: [20, 20],
			 * 	size: [180, 60],
			 * 	fillColor: 'black'
			 * });
			 */
			Ellipse: function(/* rectangle */) {
				var rect = Rectangle.readNamed(arguments, 'rectangle');
				return createShape('ellipse', rect.getCenter(true),
						rect.getSize(true), arguments);
			}
		};
	}
});
<|endoftext|>