<commit_before>var Class = require('../../utils/Class');
var BaseSound = require('../BaseSound');
var SoundEvent = require('../SoundEvent');
var SoundValueEvent = require('../SoundValueEvent');
var HTML5AudioSound = new Class({
    Extends: BaseSound,
    initialize: function HTML5AudioSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        /**
         * An array containing all HTML5 Audio tags that could be used for individual
         * sound's playback. Number of instances depends on the config value passed
         * to the Loader#audio method call, default is 1.
         *
         * @private
         * @property {HTMLAudioElement[]} tags
         */
        this.tags = manager.game.cache.audio.get(key);
        if (!this.tags) {
            console.error('No audio loaded in cache with key: \'' + key + '\'!');
            return;
        }
        /**
         * Reference to an HTML5 Audio tag used for playing sound.
         *
         * @private
         * @property {HTMLAudioElement} audio
         * @default null
         */
        this.audio = null;
        /**
         * Timestamp as generated by the Request Animation Frame or SetTimeout
         * representing the time at which the delayed sound playback should start.
         * Set to 0 if sound playback is not delayed.
         *
         * @private
         * @property {number} startTime
         * @default 0
         */
        this.startTime = 0;
        /**
         * Audio tag's playback position recorded on previous
         * update method call. Set to 0 if sound is not playing.
         *
         * @private
         * @property {number} previousTime
         * @default 0
         */
        this.previousTime = 0;
        this.duration = this.tags[0].duration;
        this.totalDuration = this.tags[0].duration;
        BaseSound.call(this, manager, key, config);
    },
    play: function (markerName, config) {
        if (!BaseSound.prototype.play.call(this, markerName, config)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        if (!this.pickAndPlayAudioTag()) {
            return false;
        }
        this.events.dispatch(new SoundEvent(this, 'SOUND_PLAY'));
        return true;
    },
    pause: function () {
        if (this.startTime > 0) {
            return false;
        }
        if (!BaseSound.prototype.pause.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = true \/\/\/
        this.currentConfig.seek = this.audio.currentTime
            - (this.currentMarker ? this.currentMarker.start : 0);
        this.stopAndReleaseAudioTag();
        this.events.dispatch(new SoundEvent(this, 'SOUND_PAUSE'));
        return true;
    },
    resume: function () {
        if (this.startTime > 0) {
            return false;
        }
        if (!BaseSound.prototype.resume.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        if (!this.pickAndPlayAudioTag()) {
            return false;
        }
        this.events.dispatch(new SoundEvent(this, 'SOUND_RESUME'));
        return true;
    },
    stop: function () {
        if (!BaseSound.prototype.stop.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = false \/\/\/
        this.stopAndReleaseAudioTag();
        this.events.dispatch(new SoundEvent(this, 'SOUND_STOP'));
        return true;
    },
    pickAndPlayAudioTag: function () {
        if (!this.pickAudioTag()) {
            this.reset();
            return false;
        }
        var seek = this.currentConfig.seek;
        var delay = this.currentConfig.delay;
        var offset = (this.currentMarker ? this.currentMarker.start : 0) + seek;
        this.previousTime = offset;
        this.audio.currentTime = offset;
        this.applyConfig();
        if (delay === 0) {
            this.startTime = 0;
            if (this.audio.paused) {
                this.audio.play();
            }
        }
        else {
            this.startTime = window.performance.now() + delay;
            if (!this.audio.paused) {
                this.audio.pause();
            }
        }
        this.resetConfig();
        return true;
    },
    pickAudioTag: function () {
        if (!this.audio) {
            for (var i = 0; i < this.tags.length; i++) {
                var audio = this.tags[i];
                if (audio.dataset.used === 'false') {
                    audio.dataset.used = 'true';
                    this.audio = audio;
                    return true;
                }
            }
            if (!this.manager.override) {
                return false;
            }
            var otherSounds_1 = [];
            this.manager.forEachActiveSound(function (sound) {
                if (sound.key === this.key && sound.audio) {
                    otherSounds_1.push(sound);
                }
            }, this);
            otherSounds_1.sort(function (a1, a2) {
                if (a1.loop === a2.loop) {
                    // sort by progress
                    return (a2.seek / a2.duration) - (a1.seek / a1.duration);
                }
                return a1.loop ? 1 : -1;
            });
            var selectedSound = otherSounds_1[0];
            this.audio = selectedSound.audio;
            selectedSound.reset();
            selectedSound.audio = null;
            selectedSound.startTime = 0;
            selectedSound.previousTime = 0;
        }
        return true;
    },
    stopAndReleaseAudioTag: function () {
        this.audio.pause();
        this.audio.dataset.used = 'false';
        this.audio = null;
        this.startTime = 0;
        this.previousTime = 0;
    },
    reset: function () {
        BaseSound.prototype.stop.call(this);
    },
    update: function (time, delta) {
        // TODO include play method call delay
        if (this.isPlaying) {
            // handling delayed playback
            if (this.startTime > 0) {
                if (this.startTime < time) {
                    this.audio.currentTime += (time - this.startTime) / 1000;
                    this.startTime = 0;
                    this.previousTime = this.audio.currentTime;
                    this.audio.play();
                }
                return;
            }
            // handle looping and ending
            var startTime = this.currentMarker ? this.currentMarker.start : 0;
            var endTime = startTime + this.duration;
            var currentTime = this.audio.currentTime;
            if (currentTime >= endTime) {
                if (this.currentConfig.loop) {
                    this.audio.currentTime = startTime + (currentTime - endTime);
                    currentTime = this.audio.currentTime;
                }
                else {
                    this.reset();
                    this.stopAndReleaseAudioTag();
                    this.events.dispatch(new SoundEvent(this, 'SOUND_ENDED'));
                    return;
                }
            }
            else if (currentTime < startTime) {
                this.audio.currentTime += startTime;
                currentTime = this.audio.currentTime;
            }
            if (currentTime < this.previousTime) {
                this.events.dispatch(new SoundEvent(this, 'SOUND_LOOP'));
            }
            this.previousTime = currentTime;
        }
    },
    destroy: function () {
        BaseSound.prototype.destroy.call(this);
        this.tags = null;
        if (this.audio) {
            this.stopAndReleaseAudioTag();
        }
    },
    setMute: function () {
        if (this.audio) {
            this.audio.muted = this.currentConfig.mute || this.manager.mute;
        }
    },
    setVolume: function () {
        if (this.audio) {
            this.audio.volume = this.currentConfig.volume * this.manager.volume;
        }
    },
    setRate: function () {
        BaseSound.prototype.setRate.call(this);
        if (this.audio) {
            this.audio.playbackRate = this.totalRate;
        }
    }
});
/**
 * Mute setting.
 *
 * @name Phaser.Sound.HTML5AudioSound#mute
 * @property {boolean} mute
 */
Object.defineProperty(HTML5AudioSound.prototype, 'mute', {
    get: function () {
        return this.currentConfig.mute;
    },
    set: function (value) {
        this.currentConfig.mute = value;
        this.setMute();
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_MUTE', value));
    }
});
/**
 * Volume setting.
 *
 * @name Phaser.Sound.HTML5AudioSound#volume
 * @property {number} volume
 */
Object.defineProperty(HTML5AudioSound.prototype, 'volume', {
    get: function () {
        return this.currentConfig.volume;
    },
    set: function (value) {
        this.currentConfig.volume = value;
        this.setVolume();
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_VOLUME', value));
    }
});
/**
 * Current position of playing sound.
 *
 * @name Phaser.Sound.HTML5AudioSound#seek
 * @property {number} seek
 */
Object.defineProperty(HTML5AudioSound.prototype, 'seek', {
    get: function () {
        if (this.isPlaying) {
            return this.audio.currentTime -
                (this.currentMarker ? this.currentMarker.start : 0);
        }
        else if (this.isPaused) {
            return this.currentConfig.seek;
        }
        else {
            return 0;
        }
    },
    set: function (value) {
        if (this.startTime > 0) {
            return;
        }
        if (this.isPlaying || this.isPaused) {
            value = Math.min(Math.max(0, value), this.duration);
            if (this.isPlaying) {
                this.previousTime = value;
                this.audio.currentTime = value;
            }
            else if (this.isPaused) {
                this.currentConfig.seek = value;
            }
            this.events.dispatch(new SoundValueEvent(this, 'SOUND_SEEK', value));
        }
    }
});
/**
 * Property indicating whether or not
 * the sound or current sound marker will loop.
 *
 * @name Phaser.Sound.HTML5AudioSound#loop
 * @property {boolean} loop
 */
Object.defineProperty(HTML5AudioSound.prototype, 'loop', {
    get: function () {
        return this.currentConfig.loop;
    },
    set: function (value) {
        this.currentConfig.loop = value;
        if (this.audio) {
            this.audio.loop = value;
        }
    }
});
module.exports = HTML5AudioSound;
<commit_msg>Fixed ms to s conversion for delay value when setting start time for delayed playback<commit_after>var Class = require('../../utils/Class');
var BaseSound = require('../BaseSound');
var SoundEvent = require('../SoundEvent');
var SoundValueEvent = require('../SoundValueEvent');
var HTML5AudioSound = new Class({
    Extends: BaseSound,
    initialize: function HTML5AudioSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        /**
         * An array containing all HTML5 Audio tags that could be used for individual
         * sound's playback. Number of instances depends on the config value passed
         * to the Loader#audio method call, default is 1.
         *
         * @private
         * @property {HTMLAudioElement[]} tags
         */
        this.tags = manager.game.cache.audio.get(key);
        if (!this.tags) {
            console.error('No audio loaded in cache with key: \'' + key + '\'!');
            return;
        }
        /**
         * Reference to an HTML5 Audio tag used for playing sound.
         *
         * @private
         * @property {HTMLAudioElement} audio
         * @default null
         */
        this.audio = null;
        /**
         * Timestamp as generated by the Request Animation Frame or SetTimeout
         * representing the time at which the delayed sound playback should start.
         * Set to 0 if sound playback is not delayed.
         *
         * @private
         * @property {number} startTime
         * @default 0
         */
        this.startTime = 0;
        /**
         * Audio tag's playback position recorded on previous
         * update method call. Set to 0 if sound is not playing.
         *
         * @private
         * @property {number} previousTime
         * @default 0
         */
        this.previousTime = 0;
        this.duration = this.tags[0].duration;
        this.totalDuration = this.tags[0].duration;
        BaseSound.call(this, manager, key, config);
    },
    play: function (markerName, config) {
        if (!BaseSound.prototype.play.call(this, markerName, config)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        if (!this.pickAndPlayAudioTag()) {
            return false;
        }
        this.events.dispatch(new SoundEvent(this, 'SOUND_PLAY'));
        return true;
    },
    pause: function () {
        if (this.startTime > 0) {
            return false;
        }
        if (!BaseSound.prototype.pause.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = true \/\/\/
        this.currentConfig.seek = this.audio.currentTime
            - (this.currentMarker ? this.currentMarker.start : 0);
        this.stopAndReleaseAudioTag();
        this.events.dispatch(new SoundEvent(this, 'SOUND_PAUSE'));
        return true;
    },
    resume: function () {
        if (this.startTime > 0) {
            return false;
        }
        if (!BaseSound.prototype.resume.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        if (!this.pickAndPlayAudioTag()) {
            return false;
        }
        this.events.dispatch(new SoundEvent(this, 'SOUND_RESUME'));
        return true;
    },
    stop: function () {
        if (!BaseSound.prototype.stop.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = false \/\/\/
        this.stopAndReleaseAudioTag();
        this.events.dispatch(new SoundEvent(this, 'SOUND_STOP'));
        return true;
    },
    pickAndPlayAudioTag: function () {
        if (!this.pickAudioTag()) {
            this.reset();
            return false;
        }
        var seek = this.currentConfig.seek;
        var delay = this.currentConfig.delay;
        var offset = (this.currentMarker ? this.currentMarker.start : 0) + seek;
        this.previousTime = offset;
        this.audio.currentTime = offset;
        this.applyConfig();
        if (delay === 0) {
            this.startTime = 0;
            if (this.audio.paused) {
                this.audio.play();
            }
        }
        else {
            this.startTime = window.performance.now() + delay * 1000;
            if (!this.audio.paused) {
                this.audio.pause();
            }
        }
        this.resetConfig();
        return true;
    },
    pickAudioTag: function () {
        if (!this.audio) {
            for (var i = 0; i < this.tags.length; i++) {
                var audio = this.tags[i];
                if (audio.dataset.used === 'false') {
                    audio.dataset.used = 'true';
                    this.audio = audio;
                    return true;
                }
            }
            if (!this.manager.override) {
                return false;
            }
            var otherSounds_1 = [];
            this.manager.forEachActiveSound(function (sound) {
                if (sound.key === this.key && sound.audio) {
                    otherSounds_1.push(sound);
                }
            }, this);
            otherSounds_1.sort(function (a1, a2) {
                if (a1.loop === a2.loop) {
                    // sort by progress
                    return (a2.seek / a2.duration) - (a1.seek / a1.duration);
                }
                return a1.loop ? 1 : -1;
            });
            var selectedSound = otherSounds_1[0];
            this.audio = selectedSound.audio;
            selectedSound.reset();
            selectedSound.audio = null;
            selectedSound.startTime = 0;
            selectedSound.previousTime = 0;
        }
        return true;
    },
    stopAndReleaseAudioTag: function () {
        this.audio.pause();
        this.audio.dataset.used = 'false';
        this.audio = null;
        this.startTime = 0;
        this.previousTime = 0;
    },
    reset: function () {
        BaseSound.prototype.stop.call(this);
    },
    update: function (time, delta) {
        // TODO include play method call delay
        if (this.isPlaying) {
            // handling delayed playback
            if (this.startTime > 0) {
                if (this.startTime < time) {
                    this.audio.currentTime += (time - this.startTime) / 1000;
                    this.startTime = 0;
                    this.previousTime = this.audio.currentTime;
                    this.audio.play();
                }
                return;
            }
            // handle looping and ending
            var startTime = this.currentMarker ? this.currentMarker.start : 0;
            var endTime = startTime + this.duration;
            var currentTime = this.audio.currentTime;
            if (currentTime >= endTime) {
                if (this.currentConfig.loop) {
                    this.audio.currentTime = startTime + (currentTime - endTime);
                    currentTime = this.audio.currentTime;
                }
                else {
                    this.reset();
                    this.stopAndReleaseAudioTag();
                    this.events.dispatch(new SoundEvent(this, 'SOUND_ENDED'));
                    return;
                }
            }
            else if (currentTime < startTime) {
                this.audio.currentTime += startTime;
                currentTime = this.audio.currentTime;
            }
            if (currentTime < this.previousTime) {
                this.events.dispatch(new SoundEvent(this, 'SOUND_LOOP'));
            }
            this.previousTime = currentTime;
        }
    },
    destroy: function () {
        BaseSound.prototype.destroy.call(this);
        this.tags = null;
        if (this.audio) {
            this.stopAndReleaseAudioTag();
        }
    },
    setMute: function () {
        if (this.audio) {
            this.audio.muted = this.currentConfig.mute || this.manager.mute;
        }
    },
    setVolume: function () {
        if (this.audio) {
            this.audio.volume = this.currentConfig.volume * this.manager.volume;
        }
    },
    setRate: function () {
        BaseSound.prototype.setRate.call(this);
        if (this.audio) {
            this.audio.playbackRate = this.totalRate;
        }
    }
});
/**
 * Mute setting.
 *
 * @name Phaser.Sound.HTML5AudioSound#mute
 * @property {boolean} mute
 */
Object.defineProperty(HTML5AudioSound.prototype, 'mute', {
    get: function () {
        return this.currentConfig.mute;
    },
    set: function (value) {
        this.currentConfig.mute = value;
        this.setMute();
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_MUTE', value));
    }
});
/**
 * Volume setting.
 *
 * @name Phaser.Sound.HTML5AudioSound#volume
 * @property {number} volume
 */
Object.defineProperty(HTML5AudioSound.prototype, 'volume', {
    get: function () {
        return this.currentConfig.volume;
    },
    set: function (value) {
        this.currentConfig.volume = value;
        this.setVolume();
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_VOLUME', value));
    }
});
/**
 * Current position of playing sound.
 *
 * @name Phaser.Sound.HTML5AudioSound#seek
 * @property {number} seek
 */
Object.defineProperty(HTML5AudioSound.prototype, 'seek', {
    get: function () {
        if (this.isPlaying) {
            return this.audio.currentTime -
                (this.currentMarker ? this.currentMarker.start : 0);
        }
        else if (this.isPaused) {
            return this.currentConfig.seek;
        }
        else {
            return 0;
        }
    },
    set: function (value) {
        if (this.startTime > 0) {
            return;
        }
        if (this.isPlaying || this.isPaused) {
            value = Math.min(Math.max(0, value), this.duration);
            if (this.isPlaying) {
                this.previousTime = value;
                this.audio.currentTime = value;
            }
            else if (this.isPaused) {
                this.currentConfig.seek = value;
            }
            this.events.dispatch(new SoundValueEvent(this, 'SOUND_SEEK', value));
        }
    }
});
/**
 * Property indicating whether or not
 * the sound or current sound marker will loop.
 *
 * @name Phaser.Sound.HTML5AudioSound#loop
 * @property {boolean} loop
 */
Object.defineProperty(HTML5AudioSound.prototype, 'loop', {
    get: function () {
        return this.currentConfig.loop;
    },
    set: function (value) {
        this.currentConfig.loop = value;
        if (this.audio) {
            this.audio.loop = value;
        }
    }
});
module.exports = HTML5AudioSound;
<|endoftext|>


<commit_before><commit_msg>implement<commit_after><|endoftext|>


<commit_before>var mongodb = require('mongodb'),
    server = new mongodb.Server('127.0.0.1', 27017, {}),
    client = new mongodb.Db('mydatabase', server, {w: 1});

///////////
// ERROR //
///////////

client.open(function (err) {
    if (err) throw err;
    client.collection('test_insert', function (err, collection) {
        if (err) throw err;
        console.log("We are now able to perform queries.");
    });
});<commit_msg>updates 5-storing-data -- 3-using-mongo<commit_after>/**
 * MongoDB is a open-source document database that provides
 * high-performance, high availability and automatic scaling.
 *
 * Each record that composes the database is called Document, which is a
 * data structure composed of fields and values pairs, with the values
 * of the fields being able to anso include other documents, arrays and
 * arrays of documents. Documents are then grouped into Collections,
 * which is the equivalent of an RDBMS table. A collection exists within
 * a single DB and do not enfore a schema, i.e, the documents within a
 * collection can have differente fields; tipically the documents of a
 * collection just share a similar or related purpose and one or more
 * indexes.
 */

var MongoClient = require('mongodb').MongoClient;
var format = require('util').format;

MongoClient.connect('mongodb://127.0.0.1:27017/test', function (err, db) {
    if (err) throw err;
    console.log("We'v got da powa of mongo!!!");

    // collection object is a pointer to a specific collection in the
    // database. If we want to insert new records or query existing ones
    // then we need to have a valid collection object.

    var collection = db.collection('test_insert');

    // MongoDb has async insert/update/remove operations. When we issue
    // an insert operation we are just providing a fire and forget
    // operation where the database does not reply with the status of
    // the insert operation.

    collection.insert({a:2}, function (err, docs) {

        // after the insert op goes, then we perform some other ops.

        // retrieving the number of items in the collection.
        collection.count(function (err, count) {
            console.log(format("count = %s", count));
        });

    // getting the items of the collection and transforming into an
    // array. It's async as well.

        collection.find().toArray(function (err, results) {
            console.dir(results);
            db.close();
        });

    });

});<|endoftext|>


<commit_before>'use strict'

const co = require('co')
const cli = require('heroku-cli-util')
const pg = require('heroku-pg')
const _ = require('lodash')

function * run (context, heroku) {
  const app = context.app
  const {database} = context.args

  let db = yield pg.fetcher(heroku).addon(app, database)
  let host = pg.host(db)
  let rsp = yield heroku.get(`/client/v11/databases/${db.name}/user_connections`, {host})
  let connections = _.map(rsp.connections, function (v, k) {
    return {credential: k, count: v}
  })
  cli.table(connections, {columns: [ {key: 'credential', label: 'Credential'}, {key: 'count', label: 'Connections'} ]})
}

const cmd = {
  topic: 'pg',
  description: 'returns the number of connections per credential',
  needsApp: true,
  needsAuth: true,
  args: [{name: 'database', optional: true}],
  run: cli.command({preauth: true}, co.wrap(run))
}

module.exports = [
  Object.assign({command: 'user-connections'}, cmd),
  Object.assign({command: 'user_connections', hidden: true}, cmd)
]
<commit_msg>show default instead of the usename if it is a default credential<commit_after>'use strict'

const co = require('co')
const cli = require('heroku-cli-util')
const pg = require('heroku-pg')
const _ = require('lodash')

function * run (context, heroku) {
  const app = context.app
  const {database} = context.args

  let db = yield pg.fetcher(heroku).addon(app, database)
  let host = pg.host(db)

  let credentials = yield heroku.get(`/postgres/v0/databases/${db.name}/credentials`, { host: host })
  let default_credentials = _.filter(credentials, c => c.name === 'default')
  let default_users = _.flatMap(default_credentials, c => _.map(c.credentials, u => u.user))

  let isDefaultUser = (user) => _.includes(default_users, user)
  let styledName = (user) => {
    if (isDefaultUser(user)) {
      return 'default'
    } else {
      return user
    }
  }

  let rsp = yield heroku.get(`/client/v11/databases/${db.name}/user_connections`, {host})
  let connections = _.map(rsp.connections, function (v, k) {
    return {credential: styledName(k), count: v}
  })

  cli.table(connections, {columns: [ {key: 'credential', label: 'Credential'}, {key: 'count', label: 'Connections'} ]})
}

const cmd = {
  topic: 'pg',
  description: 'returns the number of connections per credential',
  needsApp: true,
  needsAuth: true,
  args: [{name: 'database', optional: true}],
  run: cli.command({preauth: true}, co.wrap(run))
}

module.exports = [
  Object.assign({command: 'user-connections'}, cmd),
  Object.assign({command: 'user_connections', hidden: true}, cmd)
]
<|endoftext|>


<commit_before>import urlRegex from 'url-regex' // Check https://mathiasbynens.be/demo/url-regex for results RE: this pattern
import sw from 'remove-stopwords'
import rmDiacritics from './remove-diacritics'

const allWhitespacesPattern = /\s+/g
// const singleDigitNumbersPattern = /\b\d\b/g
const nonWordsPattern = /[\u2000-\u206F\u2E00-\u2E7F\\!"#$%&()*+,.\/:;<=>?@\[\]^_`{|}~«»。（）ㅇ]/g
const apostrophePattern = /['’]/g
const allWordsWithDigits = /[a-z]+\d\w*|\w*\d[a-z]+/g // /\w*\d\w*/g
const dashPattern = /[-]/g
const giberishWords = /\S*([b-df-hj-np-tv-z]){5,}\S*/g
const longWords = /\b\w{20,}\b/g
const randomDigits = /\b(\d{1,3}|\d{5,})\b/g
const urlPattern = urlRegex()

const removeUrls = (text = '') => text.replace(urlPattern, ' ')

const removePunctuation = (text = '') => text.replace(nonWordsPattern, ' ')

const cleanupWhitespaces = (text = '') =>
    text.replace(allWhitespacesPattern, ' ').trim()

// Split strings on non-words, filtering out duplicates, before rejoining them with single space
const removeDuplicateWords = (text = '') =>
    text
        .split(' ')
        .filter((word, i, allWords) => i === allWords.indexOf(word))
        .join(' ')

const removeUselessWords = (text = '', lang) => {
    const oldString = text.split(' ')
    const newString = sw.removeStopwords(oldString, lang)
    return newString.join(' ')
}

const combinePunctuation = (text = '') => text.replace(apostrophePattern, '')

const splitPunctuation = (text = '') => text.replace(dashPattern, ' ')

const removeDiacritics = (text = '') => {
    return rmDiacritics(text)
}

// This also removes any numbers greater than 5 chars
const removeAllWordsWithDigits = (text = '') =>
    text.replace(allWordsWithDigits, ' ')

const removeRandomDigits = (text = '') => text.replace(randomDigits, ' ')

const removeLongWords = (text = '') => text.replace(longWords, ' ')

const removeGiberishWords = (text = '') => text.replace(giberishWords, ' ')

/**
 * Takes in some text content and strips it of unneeded data. Currently does
 * puncation (although includes accented characters), numbers, and whitespace.
 * TODO: pass in options to disable certain functionality.
 *
 * @param {any} content A content string to transform.
 * @returns {any} Object containing the transformed `content` + less important
 *  `lengthBefore`, `lengthAfter` stats.
 */
export default function transform({ text = '', lang = 'en' }) {
    // Short circuit if no text
    if (!text || !text.replace(/\s/g, '')) {
        return text
    }
    // console.log( text + "transform-text" + lang)
    let searchableText = text
    const lengthBefore = searchableText.length

    // Remove URLs first before we start messing with things
    searchableText = removeUrls(searchableText)

    // Removes ' from words effectively combining them
    // Example O'Grady => OGrady
    searchableText = combinePunctuation(searchableText)

    // Splits words with - into two separate words
    // Example "chevron-right", "chevron right"
    searchableText = splitPunctuation(searchableText)

    // Changes accented characters to regular letters
    searchableText = removeDiacritics(searchableText)

    searchableText = removePunctuation(searchableText)

    // Removes 'stopwords' such as they'll, don't, however ect..
    searchableText = removeUselessWords(searchableText, lang)

    // We don't care about non-single-space whitespace (' ' is cool)
    searchableText = cleanupWhitespaces(searchableText)

    // Remove all words containing numbers ex. blah123
    searchableText = removeAllWordsWithDigits(searchableText)

    // Removes all single digits and digits over 5+ characters
    searchableText = removeRandomDigits(searchableText)

    // Removes all words 20+ characters long
    searchableText = removeLongWords(searchableText)

    // Removes all words containing 4+ consonants such as "hellllo"
    searchableText = removeGiberishWords(searchableText)

    searchableText = removeDuplicateWords(searchableText)

    const lengthAfter = searchableText.length

    return { text: searchableText, lengthBefore, lengthAfter }
}
<commit_msg>Removing © and °<commit_after>import urlRegex from 'url-regex' // Check https://mathiasbynens.be/demo/url-regex for results RE: this pattern
import sw from 'remove-stopwords'
import rmDiacritics from './remove-diacritics'

const allWhitespacesPattern = /\s+/g
// const singleDigitNumbersPattern = /\b\d\b/g
const nonWordsPattern = /[\u2000-\u206F\u2E00-\u2E7F\\!"#$%&()*+,.\/:;<=>?@\[\]^_`{|}~«»。（）ㅇ©ºø°]/g
const apostrophePattern = /['’]/g
const allWordsWithDigits = /[a-z]+\d\w*|\w*\d[a-z]+/g // /\w*\d\w*/g
const dashPattern = /[-]/g
const giberishWords = /\S*([b-df-hj-np-tv-z]){5,}\S*/g
const longWords = /\b\w{20,}\b/g
const randomDigits = /\b(\d{1,3}|\d{5,})\b/g
const urlPattern = urlRegex()

const removeUrls = (text = '') => text.replace(urlPattern, ' ')

const removePunctuation = (text = '') => text.replace(nonWordsPattern, ' ')

const cleanupWhitespaces = (text = '') =>
    text.replace(allWhitespacesPattern, ' ').trim()

// Split strings on non-words, filtering out duplicates, before rejoining them with single space
const removeDuplicateWords = (text = '') =>
    text
        .split(' ')
        .filter((word, i, allWords) => i === allWords.indexOf(word))
        .join(' ')

const removeUselessWords = (text = '', lang) => {
    const oldString = text.split(' ')
    const newString = sw.removeStopwords(oldString, lang)
    return newString.join(' ')
}

const combinePunctuation = (text = '') => text.replace(apostrophePattern, '')

const splitPunctuation = (text = '') => text.replace(dashPattern, ' ')

const removeDiacritics = (text = '') => {
    return rmDiacritics(text)
}

// This also removes any numbers greater than 5 chars
const removeAllWordsWithDigits = (text = '') =>
    text.replace(allWordsWithDigits, ' ')

const removeRandomDigits = (text = '') => text.replace(randomDigits, ' ')

const removeLongWords = (text = '') => text.replace(longWords, ' ')

const removeGiberishWords = (text = '') => text.replace(giberishWords, ' ')

/**
 * Takes in some text content and strips it of unneeded data. Currently does
 * puncation (although includes accented characters), numbers, and whitespace.
 * TODO: pass in options to disable certain functionality.
 *
 * @param {any} content A content string to transform.
 * @returns {any} Object containing the transformed `content` + less important
 *  `lengthBefore`, `lengthAfter` stats.
 */
export default function transform({ text = '', lang = 'en' }) {
    // Short circuit if no text
    if (!text || !text.replace(/\s/g, '')) {
        return text
    }
    // console.log( text + "transform-text" + lang)
    let searchableText = text
    const lengthBefore = searchableText.length

    // Remove URLs first before we start messing with things
    searchableText = removeUrls(searchableText)

    // Removes ' from words effectively combining them
    // Example O'Grady => OGrady
    searchableText = combinePunctuation(searchableText)

    // Splits words with - into two separate words
    // Example "chevron-right", "chevron right"
    searchableText = splitPunctuation(searchableText)

    // Changes accented characters to regular letters
    searchableText = removeDiacritics(searchableText)

    searchableText = removePunctuation(searchableText)

    // Removes 'stopwords' such as they'll, don't, however ect..
    searchableText = removeUselessWords(searchableText, lang)

    // We don't care about non-single-space whitespace (' ' is cool)
    searchableText = cleanupWhitespaces(searchableText)

    // Remove all words containing numbers ex. blah123
    searchableText = removeAllWordsWithDigits(searchableText)

    // Removes all single digits and digits over 5+ characters
    searchableText = removeRandomDigits(searchableText)

    // Removes all words 20+ characters long
    searchableText = removeLongWords(searchableText)

    // Removes all words containing 4+ consonants such as "hellllo"
    searchableText = removeGiberishWords(searchableText)

    searchableText = removeDuplicateWords(searchableText)

    const lengthAfter = searchableText.length

    return { text: searchableText, lengthBefore, lengthAfter }
}
<|endoftext|>


<commit_before>var leftCanvas = false;

  // Get window dimension
  var ww = window.innerWidth,
      wh = window.innerHeight;
  // Save half window dimension
  var ww2 = ww * 0.5,
      wh2 = wh * 0.5;

  // Constructor function
  function Tunnel() {
    // Init the scene and the
    this.init();
    // Create the shape of the tunnel
    this.createMesh();

    // Mouse events & window resize
    this.handleEvents();

    // Start loop animation
    window.requestAnimationFrame(this.render.bind(this));
  }

  Tunnel.prototype.init = function() {
    // Define the speed of the tunnel
    this.speed = 0.04;

    // Store the position of the mouse
    // Default is center of the screen
    this.mouse = {
      position: new THREE.Vector2(0, 0),
      target: new THREE.Vector2(0, 0)
    };

    // Create a WebGL renderer
    if (leftCanvas === false) {
      this.renderer = new THREE.WebGLRenderer({
        antialias:true,
        canvas: document.querySelector("#scene")
      });
      leftCanvas = true;
      this.renderer.setSize(ww2, wh);
    }
    else {
      this.renderer = new THREE.WebGLRenderer({
        antialias:true,
        canvas: document.querySelector("#scene2")
      });
      this.renderer.setSize((ww2-5), wh);
    }

    // Set size of the renderer and its background color
    this.renderer.setClearColor(0xe8e1bc);

    // Create a camera and move it along Z axis
    this.camera = new THREE.PerspectiveCamera(15, ww2 / wh, 0.01, 1000);
    this.camera.position.z = 0.35;

    // Create an empty scene and define a fog for it
    this.scene = new THREE.Scene();
    this.scene.fog = new THREE.Fog(0xe8e1bc, 0.8, 2.5);
  };

  Tunnel.prototype.createMesh = function() {
    // Empty array to store the points along the path
    var points = [];

    // Define points along Z axis to create a curve
    for (var i = 0; i < 5; i += 1) {
      points.push(new THREE.Vector3(0, 0, 2.5 * (i / 4)));
    }
    // Set custom Y position for the last point
    points[4].y = -0.06;

    // Create a curve based on the points
    this.curve = new THREE.CatmullRomCurve3(points);
    // Define the curve type

    // Empty geometry
    var geometry = new THREE.Geometry();
    // Create vertices based on the curve
    geometry.vertices = this.curve.getPoints(70);
    // Create a line from the points with a basic line material
    this.splineMesh = new THREE.Line(geometry, new THREE.LineBasicMaterial());

    // Create a material for the tunnel with a custom texture
    // Set side to BackSide since the camera is inside the tunnel
    this.tubeMaterial = new THREE.MeshBasicMaterial({
      side: THREE.BackSide,
      map: tunnelTexture
    });
    // Repeat the pattern
    this.tubeMaterial.map.wrapS = THREE.RepeatWrapping;
    this.tubeMaterial.map.wrapT = THREE.RepeatWrapping;
    this.tubeMaterial.map.repeat.set(15, 3);

    // Create a tube geometry based on the curve
    this.tubeGeometry = new THREE.TubeGeometry(this.curve, 70, 0.02, 30, false);
    // Create a mesh based on the tube geometry and its material
    this.tubeMesh = new THREE.Mesh(this.tubeGeometry, this.tubeMaterial);
    // Push the tube into the scene
    this.scene.add(this.tubeMesh);

    // Clone the original tube geometry
    // Because we will modify the visible one but we need to keep track of the original position of the vertices
    this.tubeGeometry_o = this.tubeGeometry.clone();

  };

  Tunnel.prototype.handleEvents = function() {
    // When user resize window
    window.addEventListener('resize', this.onResize.bind(this), false);
    // When user move the mouse
    document.body.addEventListener('mousemove', this.onMouseMove.bind(this), false);

    // Listen to device orientation events
    this.deviceOrientation = new FULLTILT.DeviceOrientation();
    var self = this;
    this.deviceOrientation.start(function(){
      self.onDeviceOrientationChange();
    });

  };

  Tunnel.prototype.onResize = function() {
    // On resize, get new width & height of window
    ww = window.innerWidth;
    wh = window.innerHeight;
    ww2 = ww * 0.5;
    wh2 = wh * 0.5;

    // Update camera aspect
    this.camera.aspect = ww2 / wh;
    // Reset aspect of the camera
    this.camera.updateProjectionMatrix();
    // Update size of the canvas
    if (leftCanvas === false) {
      this.renderer.setSize(ww2, wh);
    }
    else {
      this.renderer.setSize((ww2-5), wh);
    }
  };

  Tunnel.prototype.onMouseMove = function(e) {
    // Save mouse X & Y position
    this.mouse.target.x = (e.clientX - ww2) / ww2;
    this.mouse.target.y = (wh2 - e.clientY) / wh2;
  };

  Tunnel.prototype.onDeviceOrientationChange = function() {
    // When the user move his device, change mouse target
    var euler = this.deviceOrientation.getScreenAdjustedEuler();
    if(euler.alpha > 0 && euler.beta < 90){
        this.mouse.target.y = (Math.max(-1, Math.min(1, ((euler.beta - 20) / 30))));
        this.mouse.target.x = -(Math.max(-1, Math.min(1, ((euler.gamma) / 30))));
    }
  };

  Tunnel.prototype.updateCameraPosition = function() {
    // Update the mouse position with some lerp
    this.mouse.position.x += (this.mouse.target.x - this.mouse.position.x) / 30;
    this.mouse.position.y += (this.mouse.target.y - this.mouse.position.y) / 30;

    // Rotate Z & Y axis
    this.camera.rotation.z = this.mouse.position.x * 0.2;
    this.camera.rotation.y = Math.PI - (this.mouse.position.x * 0.06);
    // Move a bit the camera horizontally & vertically
    this.camera.position.x = this.mouse.position.x * 0.015;
    this.camera.position.y = -this.mouse.position.y * 0.015;

  };

  Tunnel.prototype.updateMaterialOffset = function() {
    // Update the offset of the material
    this.tubeMaterial.map.offset.x += this.speed;
  };

  Tunnel.prototype.updateCurve = function() {
    var index = 0,
        vertice_o = null,
        vertice = null;
    // For each vertice of the tube, move it a bit based on the spline
    for (var i = 0, j = this.tubeGeometry.vertices.length; i < j; i += 1) {
      // Get the original tube vertice
      vertice_o = this.tubeGeometry_o.vertices[i];
      // Get the visible tube vertice
      vertice = this.tubeGeometry.vertices[i];
      // Calculate index of the vertice based on the Z axis
      // The tube is made of 30 circles of vertices
      index = Math.floor(i / 30);
      // Update tube vertice
      vertice.x += ((vertice_o.x + this.splineMesh.geometry.vertices[index].x) - vertice.x) / 10;
      vertice.y += ((vertice_o.y + this.splineMesh.geometry.vertices[index].y) - vertice.y) / 5;
    }
    // Warn ThreeJs that the points have changed
    this.tubeGeometry.verticesNeedUpdate = true;

    // Update the points along the curve base on mouse position
    this.curve.points[2].x = -this.mouse.position.x * 0.2;
    this.curve.points[4].x = -this.mouse.position.x * 0.2;
    this.curve.points[2].y = this.mouse.position.y * 0.2;

    // Warn ThreeJs that the spline has changed
    this.splineMesh.geometry.verticesNeedUpdate = true;
    this.splineMesh.geometry.vertices = this.curve.getPoints(70);
  };

  Tunnel.prototype.render = function() {

    // Update material offset
    this.updateMaterialOffset();

    // Update camera position & rotation
    this.updateCameraPosition();

    // Update the tunnel
    this.updateCurve();

    // render the scene
    this.renderer.render(this.scene, this.camera);

    // Animation loop
    window.requestAnimationFrame(this.render.bind(this));
  };

  // Create a new loader
  var loader = new THREE.TextureLoader();
  // Prevent crossorigin issue
  loader.crossOrigin = "Anonymous";
  // Load the texture
  loader.load("img/demo6/stonePattern.jpg",
              function(texture){
    // When texture is loaded, init the scene
    document.body.classList.remove("loading");
    window.tunnelTexture = texture;
    window.tunnel = new Tunnel();
    window.tunnel2 = new Tunnel();
  });
<commit_msg>Slower speed<commit_after>var leftCanvas = false;

  // Get window dimension
  var ww = window.innerWidth,
      wh = window.innerHeight;
  // Save half window dimension
  var ww2 = ww * 0.5,
      wh2 = wh * 0.5;

  // Constructor function
  function Tunnel() {
    // Init the scene and the
    this.init();
    // Create the shape of the tunnel
    this.createMesh();

    // Mouse events & window resize
    this.handleEvents();

    // Start loop animation
    window.requestAnimationFrame(this.render.bind(this));
  }

  Tunnel.prototype.init = function() {
    // Define the speed of the tunnel
    this.speed = 0.02;

    // Store the position of the mouse
    // Default is center of the screen
    this.mouse = {
      position: new THREE.Vector2(0, 0),
      target: new THREE.Vector2(0, 0)
    };

    // Create a WebGL renderer
    if (leftCanvas === false) {
      this.renderer = new THREE.WebGLRenderer({
        antialias:true,
        canvas: document.querySelector("#scene")
      });
      leftCanvas = true;
      this.renderer.setSize(ww2, wh);
    }
    else {
      this.renderer = new THREE.WebGLRenderer({
        antialias:true,
        canvas: document.querySelector("#scene2")
      });
      this.renderer.setSize((ww2-5), wh);
    }

    // Set size of the renderer and its background color
    this.renderer.setClearColor(0xe8e1bc);

    // Create a camera and move it along Z axis
    this.camera = new THREE.PerspectiveCamera(15, ww2 / wh, 0.01, 1000);
    this.camera.position.z = 0.35;

    // Create an empty scene and define a fog for it
    this.scene = new THREE.Scene();
    this.scene.fog = new THREE.Fog(0xe8e1bc, 0.8, 2.5);
  };

  Tunnel.prototype.createMesh = function() {
    // Empty array to store the points along the path
    var points = [];

    // Define points along Z axis to create a curve
    for (var i = 0; i < 5; i += 1) {
      points.push(new THREE.Vector3(0, 0, 2.5 * (i / 4)));
    }
    // Set custom Y position for the last point
    points[4].y = -0.06;

    // Create a curve based on the points
    this.curve = new THREE.CatmullRomCurve3(points);
    // Define the curve type

    // Empty geometry
    var geometry = new THREE.Geometry();
    // Create vertices based on the curve
    geometry.vertices = this.curve.getPoints(70);
    // Create a line from the points with a basic line material
    this.splineMesh = new THREE.Line(geometry, new THREE.LineBasicMaterial());

    // Create a material for the tunnel with a custom texture
    // Set side to BackSide since the camera is inside the tunnel
    this.tubeMaterial = new THREE.MeshBasicMaterial({
      side: THREE.BackSide,
      map: tunnelTexture
    });
    // Repeat the pattern
    this.tubeMaterial.map.wrapS = THREE.RepeatWrapping;
    this.tubeMaterial.map.wrapT = THREE.RepeatWrapping;
    this.tubeMaterial.map.repeat.set(15, 3);

    // Create a tube geometry based on the curve
    this.tubeGeometry = new THREE.TubeGeometry(this.curve, 70, 0.02, 30, false);
    // Create a mesh based on the tube geometry and its material
    this.tubeMesh = new THREE.Mesh(this.tubeGeometry, this.tubeMaterial);
    // Push the tube into the scene
    this.scene.add(this.tubeMesh);

    // Clone the original tube geometry
    // Because we will modify the visible one but we need to keep track of the original position of the vertices
    this.tubeGeometry_o = this.tubeGeometry.clone();

  };

  Tunnel.prototype.handleEvents = function() {
    // When user resize window
    window.addEventListener('resize', this.onResize.bind(this), false);
    // When user move the mouse
    document.body.addEventListener('mousemove', this.onMouseMove.bind(this), false);

    // Listen to device orientation events
    this.deviceOrientation = new FULLTILT.DeviceOrientation();
    var self = this;
    this.deviceOrientation.start(function(){
      self.onDeviceOrientationChange();
    });

  };

  Tunnel.prototype.onResize = function() {
    // On resize, get new width & height of window
    ww = window.innerWidth;
    wh = window.innerHeight;
    ww2 = ww * 0.5;
    wh2 = wh * 0.5;

    // Update camera aspect
    this.camera.aspect = ww2 / wh;
    // Reset aspect of the camera
    this.camera.updateProjectionMatrix();
    // Update size of the canvas
    if (leftCanvas === false) {
      this.renderer.setSize(ww2, wh);
    }
    else {
      this.renderer.setSize((ww2-5), wh);
    }
  };

  Tunnel.prototype.onMouseMove = function(e) {
    // Save mouse X & Y position
    this.mouse.target.x = (e.clientX - ww2) / ww2;
    this.mouse.target.y = (wh2 - e.clientY) / wh2;
  };

  Tunnel.prototype.onDeviceOrientationChange = function() {
    // When the user move his device, change mouse target
    var euler = this.deviceOrientation.getScreenAdjustedEuler();
    if(euler.alpha > 0 && euler.beta < 90){
        this.mouse.target.y = (Math.max(-1, Math.min(1, ((euler.beta - 20) / 30))));
        this.mouse.target.x = -(Math.max(-1, Math.min(1, ((euler.gamma) / 30))));
    }
  };

  Tunnel.prototype.updateCameraPosition = function() {
    // Update the mouse position with some lerp
    this.mouse.position.x += (this.mouse.target.x - this.mouse.position.x) / 30;
    this.mouse.position.y += (this.mouse.target.y - this.mouse.position.y) / 30;

    // Rotate Z & Y axis
    this.camera.rotation.z = this.mouse.position.x * 0.2;
    this.camera.rotation.y = Math.PI - (this.mouse.position.x * 0.06);
    // Move a bit the camera horizontally & vertically
    this.camera.position.x = this.mouse.position.x * 0.015;
    this.camera.position.y = -this.mouse.position.y * 0.015;

  };

  Tunnel.prototype.updateMaterialOffset = function() {
    // Update the offset of the material
    this.tubeMaterial.map.offset.x += this.speed;
  };

  Tunnel.prototype.updateCurve = function() {
    var index = 0,
        vertice_o = null,
        vertice = null;
    // For each vertice of the tube, move it a bit based on the spline
    for (var i = 0, j = this.tubeGeometry.vertices.length; i < j; i += 1) {
      // Get the original tube vertice
      vertice_o = this.tubeGeometry_o.vertices[i];
      // Get the visible tube vertice
      vertice = this.tubeGeometry.vertices[i];
      // Calculate index of the vertice based on the Z axis
      // The tube is made of 30 circles of vertices
      index = Math.floor(i / 30);
      // Update tube vertice
      vertice.x += ((vertice_o.x + this.splineMesh.geometry.vertices[index].x) - vertice.x) / 10;
      vertice.y += ((vertice_o.y + this.splineMesh.geometry.vertices[index].y) - vertice.y) / 5;
    }
    // Warn ThreeJs that the points have changed
    this.tubeGeometry.verticesNeedUpdate = true;

    // Update the points along the curve base on mouse position
    this.curve.points[2].x = -this.mouse.position.x * 0.2;
    this.curve.points[4].x = -this.mouse.position.x * 0.2;
    this.curve.points[2].y = this.mouse.position.y * 0.2;

    // Warn ThreeJs that the spline has changed
    this.splineMesh.geometry.verticesNeedUpdate = true;
    this.splineMesh.geometry.vertices = this.curve.getPoints(70);
  };

  Tunnel.prototype.render = function() {

    // Update material offset
    this.updateMaterialOffset();

    // Update camera position & rotation
    this.updateCameraPosition();

    // Update the tunnel
    this.updateCurve();

    // render the scene
    this.renderer.render(this.scene, this.camera);

    // Animation loop
    window.requestAnimationFrame(this.render.bind(this));
  };

  // Create a new loader
  var loader = new THREE.TextureLoader();
  // Prevent crossorigin issue
  loader.crossOrigin = "Anonymous";
  // Load the texture
  loader.load("img/demo6/stonePattern.jpg",
              function(texture){
    // When texture is loaded, init the scene
    document.body.classList.remove("loading");
    window.tunnelTexture = texture;
    window.tunnel = new Tunnel();
    window.tunnel2 = new Tunnel();
  });
<|endoftext|>


<commit_before>function Graphtacular (context, options) {
    this._context = context;
    this.data = (options.data || []);
    this.bar_padding = 10;
    this.bar_width = 0;
    this.animateId;
    this.bars = null;
    for(var i=0; i < this.data.length; i++) {
        var bar = this.data[i];
        if (this.bars == undefined) {
            this.bars = [];
        }
        this.bars.push(new Bar(this, bar.label, bar.value));
    };
    console.log(this.bars);
    this.animate(this);
}

Graphtacular.prototype.addBars = function(bars) {
    var self = this;
    bars.forEach(function (bar) {
        if (self.bars == undefined) {
            self.bars = [];
        }
        self.bars.push(new Bar(self, bar.label, bar.value, 0));
        console.log(self.bars);
    });
}

Graphtacular.prototype.changeBar = function(bar_name, value) {
    for (var i = 0; i < this.bars.length; i++) {
        var bar = this.bars[i];
        if(bar.label == bar_name) {
            bar.value = value;
        }
    }
};

Graphtacular.prototype.animate = function (self) {
    self.bar_width = (self._context.canvas.width / self.bars.length) - self.bar_padding;
    var width_changed = self.animateWidth(),
        height_finished = true;
    console.log(width_changed);
    if(!width_changed) {
        height_finished = self.animateHeight();
    }
    self.drawFrame();
    window.requestAnimationFrame(function () {
        self.animate(self);
    });
}

Graphtacular.prototype.drawFrame = function() {
    canvas.width = canvas.width;
    var x = this.bar_padding;
    this._context.fillStyle = "blue";
    for (var i = 0; i < this.bars.length; i++) {
        var bar = this.bars[i];
        var height = bar.height;
        var bar_height = this._context.canvas.height * (height / 100);
        bar_height = -Math.abs(bar_height);
        this._context.fillRect(x, 250, bar.width - this.bar_padding, bar_height);
        x += bar.width+ this.bar_padding;
    }
}

Graphtacular.prototype.animateWidth = function () {
    var changed = false;
    for (var i = 0; i < this.bars.length; i++) {
        var bar = this.bars[i];
        if (bar.width !== this.bar_width) {
            //console.log(bar.width, this.bar_width);
            changed = true;
            bar.width += (this.bar_width - bar.width) * 0.05;
            if (Math.abs(bar.width - this.bar_width) < 0.6) {
                console.log('setting ==');
                bar.width = this.bar_width;
            }
        }
    }
    return changed;
};

Graphtacular.prototype.animateHeight = function() {
    var changed = false;
    for (var i = 0; i < this.bars.length; i++) {
        var bar = this.bars[i];
        if (bar.height != bar.value) {
            changed = true;
            bar.height += (bar.value - bar.height) * 0.05;
            if (Math.abs(bar.height - bar.value) < 0.6) {
                bar.height = bar.value;
            }
        }
    };
    return changed;
};

function Bar (graph, label, value) {
    this.width = graph.bar_width;
    this.value = value;
    this.label = label;
    this.height = 0;
}<commit_msg>In the drawFrame function I changed it so it uses bar.height in calculating the bar height. Before I created a variable to hold that value which is no longer needed<commit_after>function Graphtacular (context, options) {
    this._context = context;
    this.data = (options.data || []);
    this.bar_padding = 10;
    this.bar_width = 0;
    this.animateId;
    this.bars = null;
    for(var i=0; i < this.data.length; i++) {
        var bar = this.data[i];
        if (this.bars == undefined) {
            this.bars = [];
        }
        this.bars.push(new Bar(this, bar.label, bar.value));
    };
    console.log(this.bars);
    this.animate(this);
}

Graphtacular.prototype.addBars = function(bars) {
    var self = this;
    bars.forEach(function (bar) {
        if (self.bars == undefined) {
            self.bars = [];
        }
        self.bars.push(new Bar(self, bar.label, bar.value, 0));
        console.log(self.bars);
    });
}

Graphtacular.prototype.changeBar = function(bar_name, value) {
    for (var i = 0; i < this.bars.length; i++) {
        var bar = this.bars[i];
        if(bar.label == bar_name) {
            bar.value = value;
        }
    }
};

Graphtacular.prototype.animate = function (self) {
    self.bar_width = (self._context.canvas.width / self.bars.length) - self.bar_padding;
    var width_changed = self.animateWidth(),
        height_finished = true;
    console.log(width_changed);
    if(!width_changed) {
        height_finished = self.animateHeight();
    }
    self.drawFrame();
    window.requestAnimationFrame(function () {
        self.animate(self);
    });
}

Graphtacular.prototype.drawFrame = function() {
    canvas.width = canvas.width;
    var x = this.bar_padding;
    this._context.fillStyle = "blue";
    for (var i = 0; i < this.bars.length; i++) {
        var bar = this.bars[i];
        var bar_height = this._context.canvas.height * (bar.height / 100);
        bar_height = -Math.abs(bar_height);
        this._context.fillRect(x, 250, bar.width - this.bar_padding, bar_height);
        x += bar.width+ this.bar_padding;
    }
}

Graphtacular.prototype.animateWidth = function () {
    var changed = false;
    for (var i = 0; i < this.bars.length; i++) {
        var bar = this.bars[i];
        if (bar.width !== this.bar_width) {
            //console.log(bar.width, this.bar_width);
            changed = true;
            bar.width += (this.bar_width - bar.width) * 0.05;
            if (Math.abs(bar.width - this.bar_width) < 0.6) {
                console.log('setting ==');
                bar.width = this.bar_width;
            }
        }
    }
    return changed;
};

Graphtacular.prototype.animateHeight = function() {
    var changed = false;
    for (var i = 0; i < this.bars.length; i++) {
        var bar = this.bars[i];
        if (bar.height != bar.value) {
            changed = true;
            bar.height += (bar.value - bar.height) * 0.05;
            if (Math.abs(bar.height - bar.value) < 0.6) {
                bar.height = bar.value;
            }
        }
    };
    return changed;
};

function Bar (graph, label, value) {
    this.width = graph.bar_width;
    this.value = value;
    this.label = label;
    this.height = 0;
}<|endoftext|>


<commit_before>var CyvasseWS_Protocol_Version = "1.0";

function loadGame(matchID) {
	if (!loadGame.alreadyLoaded) {
		loadGame.alreadyLoaded = true;

		Module.setStatus("Downloading.");

		var initGamePage = function() {
			$.getScript("/cyvasse.js");
			initLogBox();
		};

		// loadPage() is a global function from cyvasse-webapp.js
		// is there a way to explicitly handle this kind of dependency in JS?
		if(window.location.pathname.substr(0, 7) == "/match/")
			initGamePage();
		else
			loadPage("/match/" + matchID, initGamePage);
	}
	else {
		console.error("Tried to load cyvasse.js twice");
	}
}

// I don't want to repeat this all over again, but saving "console.log"
// in an object like any other function doesn't seem to work
function log(text) { console.log(text); }

function CyvasseWSClient(hostname, onopen) {
	this.websock = new WebSocket("ws://" + hostname + ":2516/");
	this.nextMessageID = 1;
	this.awaitingReply = [];
	this.cachedIngameRequests = [];

	//this.debug = true;

	var self = this;

	this.websock.onopen = function() {
		self.initComm(onopen);
	};

	this.websock.onmessage = function(msg) {
		if(self.debug === true) {
			console.log("[onmessage]");
			console.log(msg.data);
		}
		self.handleMessage(msg.data);
	};

	this.websock.onerror = function() {
		Module.setStatus("WebSocket communication error, see JavaScript console");
		Module.setStatus = log;
	};

	this.websock.onclose = function() {
		Module.setStatus("The connection to the server was closed.");
		Module.setStatus = log;
	};
}

CyvasseWSClient.prototype = {
	handleMessage: function(msgStr) {
		var msgObj = JSON.parse(msgStr);

		if(msgObj.msgType === "chatMsg") {
			Module.logbox.addChatMessage(msgObj.msgData);
			this.sendChatMsgAck(msgObj.msgID);
		}
		else if(msgObj.msgType === "chatMsgAck") {
			// TODO: Show tick next to chat message or something similar
		}
		else if(msgObj.msgType === "gameMsg") {
			if(this.handleMessageIngame === undefined) {
				console.log("Got a message for the game before it was loaded, caching.");
				this.cachedIngameRequests.push(msgData);
			}
			else {
					this.handleMessageIngame(msgData);
			}

			var sender;
			if(playersColorToSenderEnum(Module.gameMetaData.color) == SenderEnum.PLAYER_WHITE)
				sender = SenderEnum.PLAYER_BLACK;
			else
				sender = SenderEnum.PLAYER_WHITE;

			Module.logbox.addGameMessage(sender, msgObj);
		}
		else if(msgObj.msgType === "gameMsgAck") {

		}
		else if(msgObj.msgType === "gameMsgErr") {

		}
		else if(msgObj.msgType === "notification") {

		}
		else if(msgObj.msgType === "serverReply") {
			var replyData = msgObj.replyData;
			var answeredRequestData;

			for(var reqDataIdx in this.awaitingReply) {
				if(this.awaitingReply[reqDataIdx].messageID == msgObj.messageID) {
					// remove the request from this.awaitingReply
					// and save it to answeredRequests
					answeredRequestData = this.awaitingReply.splice(reqDataIdx, 1)[0];
					break;
				}
			}

			if(answeredRequestData === undefined)
				throw new Error("Got a reply to an unknown server request: " + JSON.stringify(msgObj));
			if(replyData.success === false) {
				switch(replyData.error) {
					case "gameNotFound":
						Module.setStatus("");

						// assert that we're on the game page
						$("#canvas").replaceWith("
Game not found
");
						break;
					//case "gameEmpty"
					//case "gameFull":
					// TODO: Show meaningful error messages for other common errors
					default:
						var answeredRequestJson = JSON.stringify(answeredRequestData);

						if(!replyData.error)
							throw new Error("Server request " + answeredRequestJson + " failed without error message");

						var errMsg = "Server request " + answeredRequestJson + " failed, error: " + replyData.error;
						if(replyData.errorDetail)
							errMsg += " (errorDetail: " + replyData.errorDetail + ")";

						throw new Error(errMsg);
				}

				return;
			}

			switch(answeredRequestData.action) {
				case "initComm":
					if(this.afterInitComm)
						this.afterInitComm();

					break;
				case "createGame":
					Module.gameMetaData.matchID  = replyData.matchID;
					Module.gameMetaData.playerID = replyData.playerID;
					loadGame(replyData.matchID);
					break;
				case "joinGame":
					Module.gameMetaData.color    = replyData.color;
					Module.gameMetaData.playerID = replyData.playerID;
					Module.gameMetaData.ruleSet  = replyData.ruleSet;

					if(window.location.pathname.substr(0, 7) == "/match/")
						Module.gameMetaData.matchID = getMatchID(window.location.pathname);

					loadGame(Module.gameMetaData.matchID);

					if(this.afterJoinGame)
						this.afterJoinGame();

					break;
				case "subscrGameListUpdates":
					// TODO
					break;
				//case "unsubscrGameListUpdates":
				//	break;
			}
		}
		else if(msgObj.msgType === "serverRequest") {
			// Do nothing, just assume this doesn't happen
		}
		else {
			// Ignore the message
			// TODO: Or maybe log an error somewhere?
		}
	},

	send: function(msgObj) {
		var msgData = msgObj;
		if(typeof msgObj === "object") {
			msgData = JSON.stringify(msgObj);
		}

		if(this.debug === true) {
			console.log("[send]");
			console.log(msgData);
		}
		this.websock.send(msgData);
	},

	sendRequest: function(requestData) {
		this.send({
			"msgType": "serverRequest",
			"msgID": this.nextMessageID++,
			"requestData": requestData
		});
		this.awaitingReply.push(requestData);
	},

	initComm: function(success) {
		this.sendRequest({
			"action": "initComm",
			"param": {
				"protocolVersion": CyvasseWS_Protocol_Version
			}
		});

		if(typeof success === "function")
			this.afterInitComm = success;
	},

	createGame: function(metaData) {
		this.sendRequest({
			"action": "createGame",
			"param": metaData
		});
	},

	joinGame: function(matchID, success) {
		Module.gameMetaData.matchID = matchID;

		this.sendRequest({
			"action": "joinGame",
			"param": {
				"matchID": matchID
			}
		});

		if(typeof success === "function")
			this.afterJoinGame = success;
	},

	subscrGameListUpdates: function(ruleSet, lists) {
		this.sendRequest({
			"action": "subscrGameListUpdates",
			"param": {
				"ruleSet": ruleSet,
				"lists": lists
			}
		});
	},

	unsubscrGameListUpdates: function(ruleSet, lists) {
		this.sendRequest({
			"action": "unsubscrGameListUpdates",
			"param": {
				"ruleSet": ruleSet,
				"lists": lists
			}
		});
	},

	sendChatMsg: function(content) {
		this.send({
			"msgType": "chatMsg",
			"msgID": this.nextMessageID++,
			"msgData": {
				"userInfo": {
					// TODO
				},
				"content": content
			}
		});
	},

	sendChatMsgAck: function(msgID) {
		this.send({
			"msgType": "chatMsgAck",
			"msgID": msgID
		});
	}
};
<commit_msg>Improved error handling for broken WebSocket communication<commit_after>var CyvasseWS_Protocol_Version = "1.0";

function loadGame(matchID) {
	if (!loadGame.alreadyLoaded) {
		loadGame.alreadyLoaded = true;

		Module.setStatus("Downloading.");

		var initGamePage = function() {
			$.getScript("/cyvasse.js");
			initLogBox();
		};

		// loadPage() is a global function from cyvasse-webapp.js
		// is there a way to explicitly handle this kind of dependency in JS?
		if(window.location.pathname.substr(0, 7) == "/match/")
			initGamePage();
		else
			loadPage("/match/" + matchID, initGamePage);
	}
	else {
		console.error("Tried to load cyvasse.js twice");
	}
}

// I don't want to repeat this all over again, but saving "console.log"
// in an object like any other function doesn't seem to work
function log(text) { console.log(text); }

function CyvasseWSClient(hostname, onopen) {
	this.websock = new WebSocket("ws://" + hostname + ":2516/");
	this.nextMessageID = 1;
	this.awaitingReply = [];
	this.cachedIngameRequests = [];

	this.connWasOpen = false;

	//this.debug = true;

	var self = this;

	this.websock.onopen = function() {
		self.connWasOpen = true;
		self.initComm(onopen);
	};

	this.websock.onmessage = function(msg) {
		if(self.debug === true) {
			console.log("[onmessage]");
			console.log(msg.data);
		}
		self.handleMessage(msg.data);
	};

	this.websock.onerror = function(ev) {
		if(self.connWasOpen) {
			Module.setStatus("WebSocket communication error, see JavaScript console");
			Module.setStatus = log;

			console.error("WebSocket communication error:");
			console.log(ev);
		}
		else {
			Module.setStatus("Couldn't establish a WebSocket connection");
		}
	};

	this.websock.onclose = function(ev) {
		if(self.connWasOpen) {
			if(ev.wasClean) {
				// Don't error if the disconnect was expected,
				// e.g. when the page is reloaded
				console.log("WebSocket connection closed:");
				console.log(ev);
			}
			else {
				Module.setStatus("The connection to the server was closed, see JavaScript console");
				Module.setStatus = log;

				console.error("WebSocket connection closed:");
				console.error(ev);
			}
		}
	};
}

CyvasseWSClient.prototype = {
	handleMessage: function(msgStr) {
		var msgObj = JSON.parse(msgStr);

		if(msgObj.msgType === "chatMsg") {
			Module.logbox.addChatMessage(msgObj.msgData);
			this.sendChatMsgAck(msgObj.msgID);
		}
		else if(msgObj.msgType === "chatMsgAck") {
			// TODO: Show tick next to chat message or something similar
		}
		else if(msgObj.msgType === "gameMsg") {
			if(this.handleMessageIngame === undefined) {
				console.log("Got a message for the game before it was loaded, caching.");
				this.cachedIngameRequests.push(msgData);
			}
			else {
					this.handleMessageIngame(msgData);
			}

			var sender;
			if(playersColorToSenderEnum(Module.gameMetaData.color) == SenderEnum.PLAYER_WHITE)
				sender = SenderEnum.PLAYER_BLACK;
			else
				sender = SenderEnum.PLAYER_WHITE;

			Module.logbox.addGameMessage(sender, msgObj);
		}
		else if(msgObj.msgType === "gameMsgAck") {

		}
		else if(msgObj.msgType === "gameMsgErr") {

		}
		else if(msgObj.msgType === "notification") {

		}
		else if(msgObj.msgType === "serverReply") {
			var replyData = msgObj.replyData;
			var answeredRequestData;

			for(var reqDataIdx in this.awaitingReply) {
				if(this.awaitingReply[reqDataIdx].messageID == msgObj.messageID) {
					// remove the request from this.awaitingReply
					// and save it to answeredRequests
					answeredRequestData = this.awaitingReply.splice(reqDataIdx, 1)[0];
					break;
				}
			}

			if(answeredRequestData === undefined)
				throw new Error("Got a reply to an unknown server request: " + JSON.stringify(msgObj));
			if(replyData.success === false) {
				switch(replyData.error) {
					case "gameNotFound":
						Module.setStatus("");

						// assert that we're on the game page
						$("#canvas").replaceWith("
Game not found
");
						break;
					//case "gameEmpty"
					//case "gameFull":
					// TODO: Show meaningful error messages for other common errors
					default:
						var answeredRequestJson = JSON.stringify(answeredRequestData);

						if(!replyData.error)
							throw new Error("Server request " + answeredRequestJson + " failed without error message");

						var errMsg = "Server request " + answeredRequestJson + " failed, error: " + replyData.error;
						if(replyData.errorDetail)
							errMsg += " (errorDetail: " + replyData.errorDetail + ")";

						throw new Error(errMsg);
				}

				return;
			}

			switch(answeredRequestData.action) {
				case "initComm":
					if(this.afterInitComm)
						this.afterInitComm();

					break;
				case "createGame":
					Module.gameMetaData.matchID  = replyData.matchID;
					Module.gameMetaData.playerID = replyData.playerID;
					loadGame(replyData.matchID);
					break;
				case "joinGame":
					Module.gameMetaData.color    = replyData.color;
					Module.gameMetaData.playerID = replyData.playerID;
					Module.gameMetaData.ruleSet  = replyData.ruleSet;

					if(window.location.pathname.substr(0, 7) == "/match/")
						Module.gameMetaData.matchID = getMatchID(window.location.pathname);

					loadGame(Module.gameMetaData.matchID);

					if(this.afterJoinGame)
						this.afterJoinGame();

					break;
				case "subscrGameListUpdates":
					// TODO
					break;
				//case "unsubscrGameListUpdates":
				//	break;
			}
		}
		else if(msgObj.msgType === "serverRequest") {
			// Do nothing, just assume this doesn't happen
		}
		else {
			// Ignore the message
			// TODO: Or maybe log an error somewhere?
		}
	},

	send: function(msgObj) {
		var msgData = msgObj;
		if(typeof msgObj === "object") {
			msgData = JSON.stringify(msgObj);
		}

		if(this.debug === true) {
			console.log("[send]");
			console.log(msgData);
		}
		this.websock.send(msgData);
	},

	sendRequest: function(requestData) {
		this.send({
			"msgType": "serverRequest",
			"msgID": this.nextMessageID++,
			"requestData": requestData
		});
		this.awaitingReply.push(requestData);
	},

	initComm: function(success) {
		this.sendRequest({
			"action": "initComm",
			"param": {
				"protocolVersion": CyvasseWS_Protocol_Version
			}
		});

		if(typeof success === "function")
			this.afterInitComm = success;
	},

	createGame: function(metaData) {
		this.sendRequest({
			"action": "createGame",
			"param": metaData
		});
	},

	joinGame: function(matchID, success) {
		Module.gameMetaData.matchID = matchID;

		this.sendRequest({
			"action": "joinGame",
			"param": {
				"matchID": matchID
			}
		});

		if(typeof success === "function")
			this.afterJoinGame = success;
	},

	subscrGameListUpdates: function(ruleSet, lists) {
		this.sendRequest({
			"action": "subscrGameListUpdates",
			"param": {
				"ruleSet": ruleSet,
				"lists": lists
			}
		});
	},

	unsubscrGameListUpdates: function(ruleSet, lists) {
		this.sendRequest({
			"action": "unsubscrGameListUpdates",
			"param": {
				"ruleSet": ruleSet,
				"lists": lists
			}
		});
	},

	sendChatMsg: function(content) {
		this.send({
			"msgType": "chatMsg",
			"msgID": this.nextMessageID++,
			"msgData": {
				"userInfo": {
					// TODO
				},
				"content": content
			}
		});
	},

	sendChatMsgAck: function(msgID) {
		this.send({
			"msgType": "chatMsgAck",
			"msgID": msgID
		});
	}
};
<|endoftext|>


<commit_before>import { equal } from '@ember/object/computed';
import Component from '@ember/component';
import { copy } from '@ember/object/internals';
import { isArray, A } from '@ember/array';
import layout from 'ember-bootstrap/templates/components/bs-button-group';
import SizeClass from 'ember-bootstrap/mixins/size-class';

/**
 Bootstrap-style button group, that visually groups buttons, and optionally adds radio/checkbox like behaviour.
 See http://getbootstrap.com/components/#btn-groups

 Use as a block level component with any number of [Components.Button](Components.Button.html) components provided as
 a yielded pre-configured contextual component:

 ```handlebars
 {{#bs-button-group as |bg|}}
   {{#bg.button}}1{{/bg.button}}
   {{#bg.button}}2{{/bg.button}}
   {{#bg.button}}3{{/bg.button}}
 {{/bs-button-group}}
 ```

 ### Radio-like behaviour

 Use the `type` property set to "radio" to make the child buttons toggle like radio buttons, i.e. only one button can be active.
 Set the `value` property of the buttons to something meaningful. The `value` property of the button group will then reflect
 the value of the active button:

 ```handlebars
 {{#bs-button-group value=buttonGroupValue type="radio" onChange=(action (mut buttonGroupValue)) as |bg|}}
   {{#bg.button type="default" value=1}}1{{/bg.button}}
   {{#bg.button type="default" value=2}}2{{/bg.button}}
   {{#bg.button type="default" value=3}}3{{/bg.button}}
 {{/bs-button-group}}

 You selected: {{buttonGroupValue}}!
 ```

 ### Checkbox-like behaviour

 Set `type` to "checkbox" to make any number of child buttons selectable. The `value` property will be an array
 of all the values of the active buttons:

 ```handlebars
 {{#bs-button-group value=buttonGroupValue type="checkbox" onChange=(action (mut buttonGroupValue)) as |bg|}}
   {{#bg.button type="default" value=1}}1{{/bg.button}}
   {{#bg.button type="default" value=2}}2{{/bg.button}}
   {{#bg.button type="default" value=3}}3{{/bg.button}}
 {{/bs-button-group}}

 You selected:
 <ul>
 {{#each value in buttonGroupValue}}
   <li>{{value}}</li>
 {{/each}}
 </ul>
 ```

 @class ButtonGroup
 @namespace Components
 @extends Ember.Component
 @uses Mixins.SizeClass
 @public
 */
export default Component.extend(SizeClass, {
  layout,
  ariaRole: 'group',
  classNameBindings: ['vertical:btn-group-vertical:btn-group', 'justified:btn-group-justified'],

  /**
   * @property buttonComponent
   * @type {String}
   * @private
   */
  buttonComponent: 'bs-button-group/button',

  /**
   * @property classTypePrefix
   * @type String
   * @default 'btn-group'
   * @protected
   */
  classTypePrefix: 'btn-group',

  /**
   * Set to true for a vertically stacked button group, see http://getbootstrap.com/components/#btn-groups-vertical
   *
   * @property vertical
   * @type boolean
   * @default false
   * @public
   */
  vertical: false,

  /**
   * Set to true for the buttons to stretch at equal sizes to span the entire width of its parent.
   *
   * *Important*: You have to wrap every button component in a `div class="btn-group">`:
   *
   * ```handlebars
   * <div class="btn-group" role="group">
   * {{#bs-button}}My Button{{/bs-button}}
   * </div>
   * ```
   *
   * See http://getbootstrap.com/components/#btn-groups-justified
   *
   * @property justified
   * @type boolean
   * @default false
   * @public
   */
  justified: false,

  /**
   * The type of the button group specifies how child buttons behave and how the `value` property will be computed:
   *
   * ### null
   * If `type` is not set (null), the button group will add no functionality besides Bootstrap styling
   *
   * ### radio
   * if `type` is set to "radio", the buttons will behave like radio buttons:
   * * the `value` property of the button group will reflect the `value` property of the active button
   * * thus only one button may be active
   *
   * ### checkbox
   * if `type` is set to "checkbox", the buttons will behave like checkboxes:
   * * any number of buttons may be active
   * * the `value` property of the button group will be an array containing the `value` properties of all active buttons
   *
   * @property type
   * @type string
   * @default null
   * @public
   */
  type: null,

  /**
   * The value of the button group, computed by its child buttons.
   * See the `type` property for how the value property is constructed.
   *
   * When you set the value, the corresponding buttons will be activated:
   * * use a single value for a radio button group to activate the button with the same value
   * * use an array of values for a checkbox button group to activate all the buttons with values contained in the array
   *
   * @property value
   * @type array
   * @public
   */
  value: undefined,

  /**
   * @property isRadio
   * @type boolean
   * @private
   */
  isRadio: equal('type', 'radio').readOnly(),

  /**
   * This action is called whenever the button group's value should be changed because the user clicked a button.
   * You will receive the new value of the button group (based on the `type` property), which you should use to update the
   * `value` property.
   *
   * @event onChange
   * @param {*} value
   * @public
   */
  onChange() {},

  actions: {
    buttonPressed(pressedValue) {
      let newValue;

      if (this.get('isRadio')) {
        newValue = pressedValue;
      } else {
        if (!isArray(this.get('value'))) {
          newValue = A([pressedValue]);
        } else {
          newValue = A(copy(this.get('value')));
          if (newValue.includes(pressedValue)) {
            newValue.removeObject(pressedValue);
          } else {
            newValue.pushObject(pressedValue);
          }
        }
      }

      this.get('onChange')(newValue);
    }
  }
});
<commit_msg>fix(ButtonGroup): copy method is deprecated<commit_after>import { equal } from '@ember/object/computed';
import Component from '@ember/component';
import { isArray, A } from '@ember/array';
import layout from 'ember-bootstrap/templates/components/bs-button-group';
import SizeClass from 'ember-bootstrap/mixins/size-class';

/**
 Bootstrap-style button group, that visually groups buttons, and optionally adds radio/checkbox like behaviour.
 See http://getbootstrap.com/components/#btn-groups

 Use as a block level component with any number of [Components.Button](Components.Button.html) components provided as
 a yielded pre-configured contextual component:

 ```handlebars
 {{#bs-button-group as |bg|}}
   {{#bg.button}}1{{/bg.button}}
   {{#bg.button}}2{{/bg.button}}
   {{#bg.button}}3{{/bg.button}}
 {{/bs-button-group}}
 ```

 ### Radio-like behaviour

 Use the `type` property set to "radio" to make the child buttons toggle like radio buttons, i.e. only one button can be active.
 Set the `value` property of the buttons to something meaningful. The `value` property of the button group will then reflect
 the value of the active button:

 ```handlebars
 {{#bs-button-group value=buttonGroupValue type="radio" onChange=(action (mut buttonGroupValue)) as |bg|}}
   {{#bg.button type="default" value=1}}1{{/bg.button}}
   {{#bg.button type="default" value=2}}2{{/bg.button}}
   {{#bg.button type="default" value=3}}3{{/bg.button}}
 {{/bs-button-group}}

 You selected: {{buttonGroupValue}}!
 ```

 ### Checkbox-like behaviour

 Set `type` to "checkbox" to make any number of child buttons selectable. The `value` property will be an array
 of all the values of the active buttons:

 ```handlebars
 {{#bs-button-group value=buttonGroupValue type="checkbox" onChange=(action (mut buttonGroupValue)) as |bg|}}
   {{#bg.button type="default" value=1}}1{{/bg.button}}
   {{#bg.button type="default" value=2}}2{{/bg.button}}
   {{#bg.button type="default" value=3}}3{{/bg.button}}
 {{/bs-button-group}}

 You selected:
 <ul>
 {{#each value in buttonGroupValue}}
   <li>{{value}}</li>
 {{/each}}
 </ul>
 ```

 @class ButtonGroup
 @namespace Components
 @extends Ember.Component
 @uses Mixins.SizeClass
 @public
 */
export default Component.extend(SizeClass, {
  layout,
  ariaRole: 'group',
  classNameBindings: ['vertical:btn-group-vertical:btn-group', 'justified:btn-group-justified'],

  /**
   * @property buttonComponent
   * @type {String}
   * @private
   */
  buttonComponent: 'bs-button-group/button',

  /**
   * @property classTypePrefix
   * @type String
   * @default 'btn-group'
   * @protected
   */
  classTypePrefix: 'btn-group',

  /**
   * Set to true for a vertically stacked button group, see http://getbootstrap.com/components/#btn-groups-vertical
   *
   * @property vertical
   * @type boolean
   * @default false
   * @public
   */
  vertical: false,

  /**
   * Set to true for the buttons to stretch at equal sizes to span the entire width of its parent.
   *
   * *Important*: You have to wrap every button component in a `div class="btn-group">`:
   *
   * ```handlebars
   * <div class="btn-group" role="group">
   * {{#bs-button}}My Button{{/bs-button}}
   * </div>
   * ```
   *
   * See http://getbootstrap.com/components/#btn-groups-justified
   *
   * @property justified
   * @type boolean
   * @default false
   * @public
   */
  justified: false,

  /**
   * The type of the button group specifies how child buttons behave and how the `value` property will be computed:
   *
   * ### null
   * If `type` is not set (null), the button group will add no functionality besides Bootstrap styling
   *
   * ### radio
   * if `type` is set to "radio", the buttons will behave like radio buttons:
   * * the `value` property of the button group will reflect the `value` property of the active button
   * * thus only one button may be active
   *
   * ### checkbox
   * if `type` is set to "checkbox", the buttons will behave like checkboxes:
   * * any number of buttons may be active
   * * the `value` property of the button group will be an array containing the `value` properties of all active buttons
   *
   * @property type
   * @type string
   * @default null
   * @public
   */
  type: null,

  /**
   * The value of the button group, computed by its child buttons.
   * See the `type` property for how the value property is constructed.
   *
   * When you set the value, the corresponding buttons will be activated:
   * * use a single value for a radio button group to activate the button with the same value
   * * use an array of values for a checkbox button group to activate all the buttons with values contained in the array
   *
   * @property value
   * @type array
   * @public
   */
  value: undefined,

  /**
   * @property isRadio
   * @type boolean
   * @private
   */
  isRadio: equal('type', 'radio').readOnly(),

  /**
   * This action is called whenever the button group's value should be changed because the user clicked a button.
   * You will receive the new value of the button group (based on the `type` property), which you should use to update the
   * `value` property.
   *
   * @event onChange
   * @param {*} value
   * @public
   */
  onChange() {},

  actions: {
    buttonPressed(pressedValue) {
      let newValue;

      if (this.get('isRadio')) {
        newValue = pressedValue;
      } else {
        if (!isArray(this.get('value'))) {
          newValue = A([pressedValue]);
        } else {
          newValue = A(this.get('value').slice());
          if (newValue.includes(pressedValue)) {
            newValue.removeObject(pressedValue);
          } else {
            newValue.pushObject(pressedValue);
          }
        }
      }

      this.get('onChange')(newValue);
    }
  }
});
<|endoftext|>


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

// MODULES //

import config from './../config.js';
import PACKAGE_DATA_CACHE from './caches/package_data.js';

// MAIN //

/**
* Retrieves package data for a specified documentation version.
*
* @private
* @param {string} version - documentation version
* @param {Callback} clbk - callback invoked upon retrieving package data
*/
function fetchPackageData( version, clbk ) {
	var total;
	var count;
	var o;

	total = 5;
	count = 0;

	o = PACKAGE_DATA_CACHE[ version ];
	if ( o && o.tree ) {
		done();
	} else {
		fetch( config.mount+version+'/package_tree_array.json' )
			.then( toJSON )
			.then( onTree )
			.catch( done );
	}
	if ( o && o.resources ) {
		done();
	} else {
		fetch( config.mount+version+'/package_resources.json' )
			.then( toJSON )
			.then( onResources )
			.catch( done );
	}
	if ( o && o.packages ) {
		done();
	} else {
		fetch( config.mount+version+'/package_list.json' )
			.then( toJSON )
			.then( onPackages )
			.catch( done );
	}
	if ( o && o.descriptions ) {
		done();
	} else {
		fetch( config.mount+version+'/package_desc.json' )
			.then( toJSON )
			.then( onDescriptions )
			.catch( done );
	}
	if ( o && o.namespaces ) {
		done();
	} else {
		fetch( config.mount+version+'/namespace_list.json' )
			.then( toJSON )
			.then( onNamespaces )
			.catch( done );
	}

	/**
	* Callback invoked upon receiving a JSON resource.
	*
	* @private
	* @param {Object} res - response
	* @returns {Promise} promise to resolve the response as JSON
	*/
	function toJSON( res ) {
		return res.json();
	}

	/**
	* Callback invoked upon resolving a package tree.
	*
	* @private
	* @param {Object} json - JSON object
	*/
	function onTree( json ) {
		if ( PACKAGE_DATA_CACHE[ version ] === void 0 ) {
			PACKAGE_DATA_CACHE[ version ] = {};
		}
		PACKAGE_DATA_CACHE[ version ].tree = json;
		done();
	}

	/**
	* Callback invoked upon resolving package resources.
	*
	* @private
	* @param {Object} json - JSON object
	*/
	function onResources( json ) {
		if ( PACKAGE_DATA_CACHE[ version ] === void 0 ) {
			PACKAGE_DATA_CACHE[ version ] = {};
		}
		PACKAGE_DATA_CACHE[ version ].resources = json;
		done();
	}

	/**
	* Callback invoked upon resolving a list of packages.
	*
	* @private
	* @param {StringArray} list - list of packages
	*/
	function onPackages( list ) {
		if ( PACKAGE_DATA_CACHE[ version ] === void 0 ) {
			PACKAGE_DATA_CACHE[ version ] = {};
		}
		PACKAGE_DATA_CACHE[ version ].packages = list;
		done();
	}

	/**
	* Callback invoked upon resolving package descriptions.
	*
	* @private
	* @param {Object} hash - hash containing package descriptions
	*/
	function onDescriptions( hash ) {
		if ( PACKAGE_DATA_CACHE[ version ] === void 0 ) {
			PACKAGE_DATA_CACHE[ version ] = {};
		}
		PACKAGE_DATA_CACHE[ version ].descriptions = hash;
		done();
	}

	/**
	* Callback invoked upon resolving a list of namespace packages.
	*
	* @private
	* @param {StringArray} list - list of namespace packages
	*/
	function onNamespaces( list ) {
		if ( PACKAGE_DATA_CACHE[ version ] === void 0 ) {
			PACKAGE_DATA_CACHE[ version ] = {};
		}
		PACKAGE_DATA_CACHE[ version ].namespaces = list;
		done();
	}

	/**
	* Callback invoked upon resolving a package resource.
	*
	* @private
	* @param {Error} [error] - error object
	* @returns {void}
	*/
	function done( error ) {
		if ( error ) {
			return clbk( error );
		}
		count += 1;
		if ( count === total ) {
			return clbk();
		}
	}
}

// EXPORTS //

export default fetchPackageData;
<commit_msg>Only download data necessary for application render<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2019 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// MODULES //

import config from './../config.js';
import PACKAGE_DATA_CACHE from './caches/package_data.js';

// MAIN //

/**
* Retrieves package data for a specified documentation version.
*
* @private
* @param {string} version - documentation version
* @param {Callback} clbk - callback invoked upon retrieving package data
*/
function fetchPackageData( version, clbk ) {
	var total;
	var count;
	var o;

	total = 3;
	count = 0;

	o = PACKAGE_DATA_CACHE[ version ];

	// Fetch data necessary for rendering the side menu...
	if ( o && o.tree ) {
		done();
	} else {
		fetch( config.mount+version+'/package_tree_array.json' )
			.then( toJSON )
			.then( onTree )
			.catch( done );
	}
	if ( o && o.resources ) {
		done();
	} else {
		fetch( config.mount+version+'/package_resources.json' )
			.then( toJSON )
			.then( onResources )
			.catch( done );
	}
	if ( o && o.namespaces ) {
		done();
	} else {
		fetch( config.mount+version+'/namespace_list.json' )
			.then( toJSON )
			.then( onNamespaces )
			.catch( done );
	}

	/**
	* Callback invoked upon receiving a JSON resource.
	*
	* @private
	* @param {Object} res - response
	* @returns {Promise} promise to resolve the response as JSON
	*/
	function toJSON( res ) {
		return res.json();
	}

	/**
	* Callback invoked upon resolving a package tree.
	*
	* @private
	* @param {Object} json - JSON object
	*/
	function onTree( json ) {
		if ( PACKAGE_DATA_CACHE[ version ] === void 0 ) {
			PACKAGE_DATA_CACHE[ version ] = {};
		}
		PACKAGE_DATA_CACHE[ version ].tree = json;
		done();
	}

	/**
	* Callback invoked upon resolving package resources.
	*
	* @private
	* @param {Object} json - JSON object
	*/
	function onResources( json ) {
		if ( PACKAGE_DATA_CACHE[ version ] === void 0 ) {
			PACKAGE_DATA_CACHE[ version ] = {};
		}
		PACKAGE_DATA_CACHE[ version ].resources = json;
		done();
	}

	/**
	* Callback invoked upon resolving a list of namespace packages.
	*
	* @private
	* @param {StringArray} list - list of namespace packages
	*/
	function onNamespaces( list ) {
		if ( PACKAGE_DATA_CACHE[ version ] === void 0 ) {
			PACKAGE_DATA_CACHE[ version ] = {};
		}
		PACKAGE_DATA_CACHE[ version ].namespaces = list;
		done();
	}

	/**
	* Callback invoked upon resolving a package resource.
	*
	* @private
	* @param {Error} [error] - error object
	* @returns {void}
	*/
	function done( error ) {
		if ( error ) {
			return clbk( error );
		}
		count += 1;
		if ( count === total ) {
			return clbk();
		}
	}
}

// EXPORTS //

export default fetchPackageData;
<|endoftext|>