<commit_before>seedrandom = require("seedrandom")

const isType = (type) => {
    return (arg) => Object::toString.call(arg) == "[object #{ type }]"
};

const isFunc = isType("Function");

const isObject = isType("Object");

const randomBoundedFloat = (prng, min = 0, max = 1) => {
    spread = max - min
    return prng() * spread + min
};

const randomBoundedInteger = (prng, min = 0, max = 1) => {
    spread = 1 + max - min
    return Math.floor(prng() * spread) + min
};

const randomColor = (prng) => {
    byte = kind: "integer", min: 0, max: 255, prng: prng
    mutator = (bytes) => {
        [red, green, blue] = bytes
        return { red, green, blue }
    };

    return new Stochator(byte, byte, byte, mutator).next
};

const randomNormallyDistributedFloat = (prng, mean, stdev, min, max) => {
    seed = randomBoundedFloat(prng)
    float = inverseNormalCumulativeDistribution(seed) * stdev + mean
    return min != null && max != null ?
        Math.min(max, Math.max(min, float)) : float;
};

const randomCharacter = (prng, lowercase) => {
    [min, max] = lowercase ? [97, 122] : [65, 90];
    mutator = (charCode) => String.fromCharCode(charCode)
    return new Stochator({ kind: "integer", min, max, prng }, mutator).next
};

const randomSetMember = (prng, set) => {
    max = set.length - 1
    return set.get(randomBoundedInteger(prng, 0, max))
};

const randomSetMemberWithoutReplacement = (prng, set) => {
    return undefined unless set.get(0)
    set.length -= 1
    return set.pop(randomBoundedInteger(prng, 0, set.length))
};

const randomWeightedSetMember = (prng, set, weights) => {
    [member, weightSum, float] = [undefined, 0, randomBoundedFloat(prng)]
    set.each((value, index) => {
        if (member) {
            return;
        }
        weight = weights.get(index)
        if (float <= weightSum + weight && float >= weightSum) {
            member = value
        }
        weightSum += weight
    )

    return member
};

const inverseNormalCumulativeDistribution = (probability) => {
    high = probability > 0.97575
    low = probability < 0.02425

    if (low || high) {
        numCoefficients = new Set([
            -7.784894002430293e-3, -3.223964580411365e-1, -2.400758277161838,
            -2.549732539343734, 4.374664141464968
        ])
        denomCoeffcients = new Set([
            7.784695709041462e-3, 3.224671290700398e-1,
            2.445134137142996, 3.754408661907416
        ])

        [numMaxExponent, denomMaxExponent] = [5, 4]
        coefficient = low ? 1 : -1;
        base = Math.sqrt(
            -2 * Math.log(low ? probability : 1 - probability)
        )
    } else {
        numCoefficients = new Set([
            -3.969683028665376e1, 2.209460984245205e2, -2.759285104469687e2,
            1.383577518672690e2, -3.066479806614716e1, 2.506628277459239
        ])
        denomCoeffcients = new Set([
            -5.447609879822406e1, 1.615858368580409e2, -1.556989798598866e2,
            6.680131188771972e1, -1.328068155288572e1
        ])

        [numMaxExponent, denomMaxExponent] = [5, 5]
        coefficient = probability - 0.5
        base = Math.pow(coefficient, 2)
    }

    mapMaxExp = (maxExp) => {
        return (value, index) => value * Math.pow(base, maxExp - index)
    };

    numerator = numCoefficients.map(mapMaxExp(numMaxExponent)).sum()
    denominator = denomCoeffcients.map(mapMaxExp(denomMaxExponent)).sum() + 1

    return coefficient * numerator / denominator
};

const shuffleSet = (prng, set) => {
    values = set.copy()
    for index in [values.length - 1...0]
        randomIndex = randomBoundedInteger(prng, 0, index)

        tmp = values[index]
        values[index] = values[randomIndex]
        values[randomIndex] = tmp

    return values
};

const floatGenerator = (prng, min, max, mean, stdev) => {
    if (mean && stdev) {
        return => randomNormallyDistributedFloat(prng, mean, stdev, min, max)
    } else {
        return => randomBoundedFloat(prng, min, max)
    }
};

const integerGenerator = (prng, min = 0, max = 1) => {
    return => randomBoundedInteger(prng, min, max)
};

const setGenerator = (prng, values, replacement = true, shuffle = false, weights = null) => {
    if (!values || !values.length) {
        throw Error("Must provide a 'values' array for a set generator.")
    }

    set = new Set(values)
    if (shuffle) {
        return => shuffleSet(prng, set)
    } else if (replacement) {
        if (weights) {
            weightsSet = new Set(weights)
            return => randomWeightedSetMember(prng, set, weightsSet)
        } else {
            return => randomSetMember(prng, set)
        }
    } else {
        return => randomSetMemberWithoutReplacement(prng, set)
    }
};

const createGenerator = (config) => {
    kind = config.kind || "float"

    defaultPrng = config.seed ? seedrandom : Math.random;
    basePrng = config.prng || defaultPrng
    prng = config.seed ? basePrng(config.seed) : basePrng

    generator = switch kind
        when "float"
            { min, max, mean, stdev } = config
            floatGenerator(prng, min, max, mean, stdev)
        when "integer"
            integerGenerator(prng, config.min, config.max)
        when "set"
            { values, replacement, shuffle, weights } = config
            setGenerator(prng, values, replacement, shuffle, weights)
        when "color", "rgb" then randomColor(prng)
        when "a-z", "A-Z" then randomCharacter(prng, kind is "a-z")
    if (!generator) {
        throw Error("#{ kind } not a recognized kind.")
    } else {
        return generator
    }
};

const getNextValueGenerator = (configs) => {
    configs[0] ?= {}
    generators = (createGenerator(config) for config in configs)
    if (generators.length is 1) {
        return => generators[0]()
    } else {
        return => (generator() for generator in generators)
    }
};

const class Stochator

    VERSION = "0.4"

    constructor: (configs..., mutator=null, name="next") => {
        // If the last arg is an object, all args are config args.
        // If the penultimate arg is an object, check whether the last arg
        // is a string (hence, the name) || a function (hence, the mutator).
        if (isObject(name)) {
            configs[configs.length..configs.length + 2] = [mutator, name]
            [mutator, name] = [null, "next"]
        } else if (isObject(mutator)) {
            configs[configs.length] = mutator
            [mutator, name] = isFunc(name) ? [name, "next"] : [null, name];
        }

        // If the mutator is provided, override the default identity func.
        if (mutator) {
            @mutate = (nextValue) => mutator(nextValue, @getValue())
        }

        // Transform the configs to a func to get the next value.
        getNext = getNextValueGenerator(configs)

        // Assign `name` to the next mutated value(s), after `times` iterations.
        // If `times` is 1, just return the value, otherwise return an array.
        @[name] = (times=1) => {
            values = (@setValue(@mutate(getNext())) for time in [1..times])
            return times == 1 ? values[0] : values;
        }

    getValue: (value) => @_value

    mutate: (value) => value

    setValue: (value) => @_value = value

    toString: => "[object Stochator]"

    _value: 0

if module and module.exports {
    module.exports = Stochator
} else {
    this.Stochator = Stochator
}
<commit_msg>Replace "@" with "this.".<commit_after>seedrandom = require("seedrandom")

const isType = (type) => {
    return (arg) => Object::toString.call(arg) == "[object #{ type }]"
};

const isFunc = isType("Function");

const isObject = isType("Object");

const randomBoundedFloat = (prng, min = 0, max = 1) => {
    spread = max - min
    return prng() * spread + min
};

const randomBoundedInteger = (prng, min = 0, max = 1) => {
    spread = 1 + max - min
    return Math.floor(prng() * spread) + min
};

const randomColor = (prng) => {
    byte = kind: "integer", min: 0, max: 255, prng: prng
    mutator = (bytes) => {
        [red, green, blue] = bytes
        return { red, green, blue }
    };

    return new Stochator(byte, byte, byte, mutator).next
};

const randomNormallyDistributedFloat = (prng, mean, stdev, min, max) => {
    seed = randomBoundedFloat(prng)
    float = inverseNormalCumulativeDistribution(seed) * stdev + mean
    return min != null && max != null ?
        Math.min(max, Math.max(min, float)) : float;
};

const randomCharacter = (prng, lowercase) => {
    [min, max] = lowercase ? [97, 122] : [65, 90];
    mutator = (charCode) => String.fromCharCode(charCode)
    return new Stochator({ kind: "integer", min, max, prng }, mutator).next
};

const randomSetMember = (prng, set) => {
    max = set.length - 1
    return set.get(randomBoundedInteger(prng, 0, max))
};

const randomSetMemberWithoutReplacement = (prng, set) => {
    return undefined unless set.get(0)
    set.length -= 1
    return set.pop(randomBoundedInteger(prng, 0, set.length))
};

const randomWeightedSetMember = (prng, set, weights) => {
    [member, weightSum, float] = [undefined, 0, randomBoundedFloat(prng)]
    set.each((value, index) => {
        if (member) {
            return;
        }
        weight = weights.get(index)
        if (float <= weightSum + weight && float >= weightSum) {
            member = value
        }
        weightSum += weight
    )

    return member
};

const inverseNormalCumulativeDistribution = (probability) => {
    high = probability > 0.97575
    low = probability < 0.02425

    if (low || high) {
        numCoefficients = new Set([
            -7.784894002430293e-3, -3.223964580411365e-1, -2.400758277161838,
            -2.549732539343734, 4.374664141464968
        ])
        denomCoeffcients = new Set([
            7.784695709041462e-3, 3.224671290700398e-1,
            2.445134137142996, 3.754408661907416
        ])

        [numMaxExponent, denomMaxExponent] = [5, 4]
        coefficient = low ? 1 : -1;
        base = Math.sqrt(
            -2 * Math.log(low ? probability : 1 - probability)
        )
    } else {
        numCoefficients = new Set([
            -3.969683028665376e1, 2.209460984245205e2, -2.759285104469687e2,
            1.383577518672690e2, -3.066479806614716e1, 2.506628277459239
        ])
        denomCoeffcients = new Set([
            -5.447609879822406e1, 1.615858368580409e2, -1.556989798598866e2,
            6.680131188771972e1, -1.328068155288572e1
        ])

        [numMaxExponent, denomMaxExponent] = [5, 5]
        coefficient = probability - 0.5
        base = Math.pow(coefficient, 2)
    }

    mapMaxExp = (maxExp) => {
        return (value, index) => value * Math.pow(base, maxExp - index)
    };

    numerator = numCoefficients.map(mapMaxExp(numMaxExponent)).sum()
    denominator = denomCoeffcients.map(mapMaxExp(denomMaxExponent)).sum() + 1

    return coefficient * numerator / denominator
};

const shuffleSet = (prng, set) => {
    values = set.copy()
    for index in [values.length - 1...0]
        randomIndex = randomBoundedInteger(prng, 0, index)

        tmp = values[index]
        values[index] = values[randomIndex]
        values[randomIndex] = tmp

    return values
};

const floatGenerator = (prng, min, max, mean, stdev) => {
    if (mean && stdev) {
        return => randomNormallyDistributedFloat(prng, mean, stdev, min, max)
    } else {
        return => randomBoundedFloat(prng, min, max)
    }
};

const integerGenerator = (prng, min = 0, max = 1) => {
    return => randomBoundedInteger(prng, min, max)
};

const setGenerator = (prng, values, replacement = true, shuffle = false, weights = null) => {
    if (!values || !values.length) {
        throw Error("Must provide a 'values' array for a set generator.")
    }

    set = new Set(values)
    if (shuffle) {
        return => shuffleSet(prng, set)
    } else if (replacement) {
        if (weights) {
            weightsSet = new Set(weights)
            return => randomWeightedSetMember(prng, set, weightsSet)
        } else {
            return => randomSetMember(prng, set)
        }
    } else {
        return => randomSetMemberWithoutReplacement(prng, set)
    }
};

const createGenerator = (config) => {
    kind = config.kind || "float"

    defaultPrng = config.seed ? seedrandom : Math.random;
    basePrng = config.prng || defaultPrng
    prng = config.seed ? basePrng(config.seed) : basePrng

    generator = switch kind
        when "float"
            { min, max, mean, stdev } = config
            floatGenerator(prng, min, max, mean, stdev)
        when "integer"
            integerGenerator(prng, config.min, config.max)
        when "set"
            { values, replacement, shuffle, weights } = config
            setGenerator(prng, values, replacement, shuffle, weights)
        when "color", "rgb" then randomColor(prng)
        when "a-z", "A-Z" then randomCharacter(prng, kind is "a-z")
    if (!generator) {
        throw Error("#{ kind } not a recognized kind.")
    } else {
        return generator
    }
};

const getNextValueGenerator = (configs) => {
    configs[0] ?= {}
    generators = (createGenerator(config) for config in configs)
    if (generators.length is 1) {
        return => generators[0]()
    } else {
        return => (generator() for generator in generators)
    }
};

const class Stochator

    VERSION = "0.4"

    constructor: (configs..., mutator=null, name="next") => {
        // If the last arg is an object, all args are config args.
        // If the penultimate arg is an object, check whether the last arg
        // is a string (hence, the name) || a function (hence, the mutator).
        if (isObject(name)) {
            configs[configs.length..configs.length + 2] = [mutator, name]
            [mutator, name] = [null, "next"]
        } else if (isObject(mutator)) {
            configs[configs.length] = mutator
            [mutator, name] = isFunc(name) ? [name, "next"] : [null, name];
        }

        // If the mutator is provided, override the default identity func.
        if (mutator) {
            this.mutate = (nextValue) => mutator(nextValue, this.getValue())
        }

        // Transform the configs to a func to get the next value.
        getNext = getNextValueGenerator(configs)

        // Assign `name` to the next mutated value(s), after `times` iterations.
        // If `times` is 1, just return the value, otherwise return an array.
        this[name] = (times=1) => {
            values = (this.setValue(this.mutate(getNext())) for time in [1..times])
            return times == 1 ? values[0] : values;
        }

    getValue: (value) => this._value

    mutate: (value) => value

    setValue: (value) => this._value = value

    toString: => "[object Stochator]"

    _value: 0

<|endoftext|>


<commit_before>module.exports = async (client, guild) => {
    // Get the default config settings
    const defSet = client.config.defaultSettings;

    const exists = await client.guildSettings.findOne({where: {guildID: guild.id}})
        .then(token => token !== null)
        .then(isUnique => isUnique);

    if (!exists) {
        // Adding a new row to the DB
        client.database.models.settings.create({
            guildID: guild.id,
            adminRole: defSet.adminRole,
            enableWelcome: defSet.enableWelcome,
            welcomeMessage: defSet.welcomeMessage,
            useEmbeds: defSet.useEmbeds,
            timezone: defSet.timezone,
            announceChan: defSet.announceChan,
            useEventPages: defSet.useEventPages,
            language: defSet.language
        })
            .then(() => {
                // Log that it joined another guild
                client.log('GuildCreate', `I joined ${guild.name}(${guild.id})`, 'Log', 'diff', '+');
            })
            .catch(error => { console.log(error, guild.id); });
        // Messages the guild owner to tell the how to set the bot up
        try {
            guild.owner.send(`Thank you for adding this SWGoHBot! Before using me, please configure the Admin role by running the following command:
\`${client.config.prefix}setconf adminRole add <AdminRoleName>\`.
This will allow anyone with that Discord role to edit the bot's settings.
Also run \`${client.config.prefix}setconf timezone <timezone>\` to be the timezone of your guild's activities (Default is \`America/Los_Angeles\`), and run \`${client.config.prefix}setconf announceChan <AnnouncementChannel>\` if you want to use the events/ announcements or event commands.
After that, you should be set to begin using SWGoHBot!`);
        } catch (e) {
            console.error('Broke trying to send guildCreate message: ' + e);
        }
    } else {
        // Log that it joined another guild (Again)
        client.log('GuildCreate', `I re-joined ${guild.name}(${guild.id})`, 'Log', 'diff', '+');
    }
};

<commit_msg>Missed one<commit_after>module.exports = async (client, guild) => {
    // Get the default config settings
    const defSet = client.config.defaultSettings;

    const exists = await client.database.models.guildSettings.findOne({where: {guildID: guild.id}})
        .then(token => token !== null)
        .then(isUnique => isUnique);

    if (!exists) {
        // Adding a new row to the DB
        client.database.models.settings.create({
            guildID: guild.id,
            adminRole: defSet.adminRole,
            enableWelcome: defSet.enableWelcome,
            welcomeMessage: defSet.welcomeMessage,
            useEmbeds: defSet.useEmbeds,
            timezone: defSet.timezone,
            announceChan: defSet.announceChan,
            useEventPages: defSet.useEventPages,
            language: defSet.language
        })
            .then(() => {
                // Log that it joined another guild
                client.log('GuildCreate', `I joined ${guild.name}(${guild.id})`, 'Log', 'diff', '+');
            })
            .catch(error => { console.log(error, guild.id); });
        // Messages the guild owner to tell the how to set the bot up
        try {
            guild.owner.send(`Thank you for adding this SWGoHBot! Before using me, please configure the Admin role by running the following command:
\`${client.config.prefix}setconf adminRole add <AdminRoleName>\`.
This will allow anyone with that Discord role to edit the bot's settings.
Also run \`${client.config.prefix}setconf timezone <timezone>\` to be the timezone of your guild's activities (Default is \`America/Los_Angeles\`), and run \`${client.config.prefix}setconf announceChan <AnnouncementChannel>\` if you want to use the events/ announcements or event commands.
After that, you should be set to begin using SWGoHBot!`);
        } catch (e) {
            console.error('Broke trying to send guildCreate message: ' + e);
        }
    } else {
        // Log that it joined another guild (Again)
        client.log('GuildCreate', `I re-joined ${guild.name}(${guild.id})`, 'Log', 'diff', '+');
    }
};

<|endoftext|>


<commit_before>//--------------------------------------------------------------------------

var Context      = require('./context.js'),
    Mouse        = require('./mouse.js'),
    Mover        = require('./mover.js'),
    MapRenderer  = require('../rendering/map-renderer.js'),
    LayerManager = require('../managers/layer-manager.js'),
    Layer        = require('../models/layer.js'),
    Composition  = require('../models/layers/composition.js'),
    Source       = require('../models/source.js'),
    Events       = require('../../libs/events.js'),
    utils        = require('../../../libs/utils.js'),
    _            = require('../../../libs/lodash.js'),
    TWEEN        = require('tween.js');

//--------------------------------------------------------------------------

/**
 * A MapView is the object you get when you create :
 *

 *
a [Map]{@link Maperial#createMap}

 *
an [Anchor]{@link #addAnchor}

 *
a Minifier

 *
a Magnifier

 *
a Lens

 *

 *
 * @constructor
 */
function MapView(maperial, options) {
    this.prepare(maperial, options);
    this.expose();
};

//--------------------------------------------------------------------------
//-     API
//--------------------------------------------------------------------------

MapView.prototype.expose = function () {

    //--------------------------------------------------------------------------
    //      Image Layers
    //--------------------------------------------------------------------------

    /**
     * @function
     */
    this.addOCMTransport = function () {
        return this.addImageLayer(Source.IMAGES_OCM_TRANSPORT);
    }.bind(this);

    /**
     * @function
     */
    this.addOCMLandscape = function () {
        return this.addImageLayer(Source.IMAGES_OCM_LANDSCAPE);
    }.bind(this);

    /**
     * @function
     */
    this.addWatercolor = function () {
        return this.addImageLayer(Source.IMAGES_STAMEN_WATERCOLOR);
    }.bind(this);

    /**
     * @function
     */
    this.addMapquest = function () {
        return this.addImageLayer(Source.IMAGES_MAPQUEST);
    }.bind(this);

    /**
     * @function
     */
    this.addSatellite = function () {
        return this.addImageLayer(Source.IMAGES_MAPQUEST_SATELLITE);
    }.bind(this);

    //--------------------------------------------------------------------------
    //      Maperial layers
    //--------------------------------------------------------------------------

    /**
     * @function
     */
    this.addShade = function () {
        return this.addShadeLayer();
    }.bind(this);

    /**
     * @function
     */
    this.addEarthLight = function () {
        return this.addImageLayer(Source.MAPERIAL_EARTHLIGHT);
    }.bind(this);

    /**
     * @function
     */
    this.addAerosol = function () {
        return this.addImageLayer(Source.MAPERIAL_AEROSOL);
    }.bind(this);

    /**
     * @function
     */
    this.addNDVI = function () {
        return this.addImageLayer(Source.MAPERIAL_NDVI);
    }.bind(this);

    /**
     * @function
     */
    this.addSRTM = function () {
        return this.addImageLayer(Source.MAPERIAL_SRTM);
    }.bind(this);

    /**
     * @function
     */
    this.addSST = function () {
        return this.addImageLayer(Source.MAPERIAL_SST);
    }.bind(this);

    //--------------------------------------------------------------------------
    //      Child MapViews
    //--------------------------------------------------------------------------

    /**
     * @function
     * @param {object} options
     * @param {float} options.width The anchor width, in pixels.
     *                              (Default : map.width/2)
     * @param {float} options.height The anchor height, in pixels.
     *                              (Default : map.height/2)
     * @param {float} options.top The anchor top gap inside the map, in pixels.
     *                              (Default : 0)
     * @param {float} options.left The anchor left gap inside the map, in pixels.
     *                              (Default : 0)
     *
     */
    this.addAnchor = function (options) {
        options = options || {};
        this.prepareChildOptions(options, {
            type : Maperial.ANCHOR
        });

        var width = (options.width || this.width / 2) + 'px';
        var height = (options.height || this.height / 2) + 'px';
        var left = (options.left || 10) + 'px';
        var top = (options.top || 10) + 'px';

        options.container.style.width = width;
        options.container.style.height = height;
        options.container.style.top = top;
        options.container.style.left = left;

        return this.createChild(options);

    }.bind(this);

    /**
     * @function
     * @param {object} options
     * @param {float} options.radius The lens radius, in pixels.
     *                              (Default : map.width * 0.1)
     * @param {float} options.top The lens center from the map top left, in pixels.
     *                              (Default : map.width * 0.5)
     * @param {float} options.left The lens center from the map top left, in pixels.
     *                              (Default : map.width * 0.5)
     *
     */
    this.addLens = function (options) {
        options = options || {};
        this.prepareChildOptions(options, {
            type : Maperial.LENS
        });

        var width = (options.radius * 2 || this.width / 2) + 'px';
        var height = (options.height || this.height / 2) + 'px';
        var left = (options.left || 10) + 'px';
        var top = (options.top || 10) + 'px';

        options.container.style.width = width;
        options.container.style.height = height;
        options.container.style.top = top;
        options.container.style.left = left;

        return this.createChild(options);

    }.bind(this);

    /**
     * @function
     */
    this.addMinifier = function (options) {
        options = options || {};
        options.diffZoom = options.diffZoom || 3;

        this.prepareChildOptions(options, {
            type: Maperial.MINIFIER,
        });

        var defaultTop = this.height - (options.height || 200 ) - 20;
        var width  = (options.width || 200 ) + 'px';
        var height = (options.height || 200 ) + 'px';
        var left   = (options.left || 20) + 'px';
        var top    = (options.top || defaultTop) + 'px';

        options.container.style.width  = width;
        options.container.style.height = height;
        options.container.style.top    = top;
        options.container.style.left   = left;

        var minifier = this.createChild(options);
        minifier.defaultLayer = minifier.layerManager.duplicate(this.layers);

        return minifier;
    }.bind(this);

    /**
     * @function
     */
    this.addMagnifier = function (options) {
        //@todo
    }.bind(this);

};

//--------------------------------------------------------------------------
//-     VIEW
//--------------------------------------------------------------------------

MapView.prototype.prepare = function (maperial, options) {
    console.log("  prepare MapView : " + options.container.id);

    //-------------------------------------------------------------
    // settings

    this.maperial = maperial;
    this.options = options;
    this.id = utils.generateUID() + "_" + this.options.container.id;
    this.container = options.container;
    this.type = options.type;

    //-------------------------------------------------------------
    // plug mixins in

    Events.call(this);

    //-------------------------------------------------------------
    // prepare the view

    this.prepareView();
    this.prepareCamera();

    //-------------------------------------------------------------
    // plug modules

    new Mouse(this);
    new Mover(this);

    //-------------------------------------------------------------

    // array to use push and splice
    this.layers = [];

    // hashmap : tiles[key] = tile
    this.tiles = {};

    // hashmap : dynamicalRenderers[dynamicalData.id] = dynamicalRenderer
    this.dynamicalRenderers = {};

    this.context = new Context(this);

    this.linkedMapViews = [];

    this.mapRenderer = new MapRenderer(this);
    this.layerManager = new LayerManager(this);

    //-------------------------------------------------------------

    this.shaders = [
        Composition.ALPHA_CLIP,
        Composition.ALPHA_BLEND,
        Composition.X_BLEND
    ];
};

//--------------------------------------------------------------------------
//-     CONTAINER
//--------------------------------------------------------------------------

MapView.prototype.prepareView = function () {
    this.canvas = document.createElement('canvas');
    this.container.classList.add(this.type);
    this.container.appendChild(this.canvas);

    this.refresh();
};

MapView.prototype.refresh = function () {
    this.canvas.width = this.width = this.container.clientWidth;
    this.canvas.height = this.height = this.container.clientHeight;
};

//--------------------------------------------------------------------------
//-     PLUGINS for API
//--------------------------------------------------------------------------

MapView.prototype.addImageLayer = function (sourceId) {
    return this.layerManager.addLayer(Layer.Images, sourceId);
};

//-----------------------------------------------------------------

MapView.prototype.addDynamicalLayer = function (dynamicalData, options) {

    //-------------------------------------------
    // Checking options

    var options = utils.prepareOptions(options, "style");
    if (!options) {
        console.log("Wrong call to addDynamicalLayer. Check the options");
    }

    //-------------------------------------------
    // Proceed

    return this.layerManager.addLayer(Layer.Dynamical, {
        mapView: this,
        dynamicalData: dynamicalData,
        style: options.style
    });

};

//-----------------------------------------------------------------

MapView.prototype.addHeatmapLayer = function (heatmapData, options) {

    options.colorbar = options.colorbar ||
        Maperial.colorbarManager.defaultColorbar(this);

    //-------------------------------------------
    // Proceed

    return this.layerManager.addLayer(Layer.Heat, {
        mapView: this,
        heatmapData: heatmapData,
        colorbar: options.colorbar,
        options: options
    });

};

//-----------------------------------------------------------------

// SHADE AND RASTER SHOULD JUST BE OPTIONS IN RETILER TYPE LAYER

MapView.prototype.addShadeLayer = function () {
    return this.layerManager.addLayer(Layer.Shade);
};

//-----------------------------------------------------------------

MapView.prototype.addRasterLayer = function (sourceId) {
    return this.layerManager.addLayer(Layer.Raster, sourceId);
};

//-----------------------------------------------------------------

MapView.prototype.addWMSLayer = function (sourceId) {

};

//-----------------------------------------------------------------

MapView.prototype.addOSMLayer = function (styleId) {
    if (!styleId)
        styleId = Maperial.DEFAULT_STYLE_UID;
};

//--------------------------------------------------------------------------
//-     Child tools
//--------------------------------------------------------------------------

MapView.prototype.prepareChildOptions = function (options, settings) {
    _.extend(options, settings);
    options.container = document.createElement('div');
    this.container.appendChild(options.container);
};

MapView.prototype.createChild = function (options) {
    var child = this.maperial.addMapView(options);
    this.link(child);
    this.options = options;
    child.refreshCamera({
        currentTarget : this
    });
    return child;
};

// links mapViews so that each Event may change the linkedMapViews
MapView.prototype.link = function (view) {
    this.linkedMapViews.forEach(function (link) {
        view.linkedMapViews.push(link);
        link.linkedMapViews.push(view);

        link.on(Maperial.EVENTS.MAP_MOVED, this.refreshCamera.bind(view));
        view.on(Maperial.EVENTS.MAP_MOVED, this.refreshCamera.bind(link));
    }.bind(this));

    view.linkedMapViews.push(this);
    this.linkedMapViews.push(view);

    this.on(Maperial.EVENTS.MAP_MOVED, this.refreshCamera.bind(view));
    view.on(Maperial.EVENTS.MAP_MOVED, this.refreshCamera.bind(this));
}

//--------------------------------------------------------------------------
//-     Camera
// TODO: create ./camera.js and move the following algo there
//--------------------------------------------------------------------------

MapView.prototype.prepareCamera = function () {
    this.on('zoom-in', function () {
        if ((this.options.zoomMax || 18) > this.context.zoom) {
            this.zoomCanvas(2);
            this.context.zoom++;
            this.trigger(Maperial.EVENTS.MAP_MOVED);
        }
    }.bind(this));

    this.on('zoom-out', function () {
        if ((this.options.zoomMin || 2) < this.context.zoom) {
            this.zoomCanvas(0.5);
            this.context.zoom--;
            this.trigger(Maperial.EVENTS.MAP_MOVED);
        }
    }.bind(this));
};

//--------------------------------------------------------------------------

MapView.prototype.refreshCamera = function (event) {

    var initiator = event.currentTarget;

    switch (this.type) {
        case Maperial.MINIFIER:
            this.context.zoom = initiator.context.zoom - this.options.diffZoom;
            this.context.centerM = initiator.context.centerM;
            break;

        case Maperial.MAGNIFIER:
            this.context.centerM = initiator.context.mouseM;
            break;

        case Maperial.MAIN:
        case Maperial.LENS:
        case Maperial.ANCHOR:
            this.context.zoom = initiator.context.zoom;

            var initiatorBox = initiator.container.getBoundingClientRect();
            var initiatorCenterX = initiatorBox.left + initiatorBox.width / 2;
            var initiatorCenterY = initiatorBox.top + initiatorBox.height / 2;

            var myBox = this.container.getBoundingClientRect();
            var myCenterX = myBox.left + myBox.width / 2;
            var myCenterY = myBox.top + myBox.height / 2;

            var initiatorCenterP = utils.centerInPixels(initiator.context);
            var newCenterP = {
                x: initiatorCenterP.x - initiatorCenterX + myCenterX,
                y: initiatorCenterP.y + initiatorCenterY - myCenterY
            };

            this.context.centerM = utils.pointInMeters(
                newCenterP,
                this.context
            );

            break;
    }

}

//--------------------------------------------------------------------------
// TODO: create ./zoomer.js and move the following algo there

MapView.prototype.zoomCanvas = function (scaleTo) {

    var canvas = cloneCanvas(this.canvas),
        div = document.createElement('div'),
        container = this.container;

    div.className = 'maperial-zoomer';
    div.style.position = 'absolute';
    div.style.top = '0';
    div.style.overflow = 'hidden';

    div.appendChild(canvas);
    container.appendChild(div);

    var from = {
            scale: 1
        },
        to = {
            scale: scaleTo
        },
        time = 600,
        tween = new TWEEN.Tween(from)
        .to(to, time)
        .easing(TWEEN.Easing.Circular.Out)
        .onUpdate(function () {
            var transform = 'scale(' + this.scale + ')';
            canvas.style.webkitTransform = transform;
            canvas.style.transform = transform;
        })
        .onComplete(function () {
            var from = {
                    alpha: 1
                },
                to = {
                    alpha: 0
                },
                time = 500,
                tween = new TWEEN.Tween(from)
                .to(to, time)
                .easing(TWEEN.Easing.Circular.In)
                .onUpdate(function () {
                    canvas.style.opacity = this.alpha;
                })
                .onComplete(function () {
                    container.removeChild(div);
                })
                .start();
        })
        .start();

}

function cloneCanvas(oldCanvas) {

    //create a new canvas
    var newCanvas = document.createElement('canvas');
    var context = newCanvas.getContext('2d');

    //set dimensions
    newCanvas.width = oldCanvas.width;
    newCanvas.height = oldCanvas.height;

    //+ translate3d pour recentrer.
    //chech taille du container VS taille du canvas...?
    newCanvas.style.position = 'relative';

    var dataURL = oldCanvas.toDataURL('image/jpeg', 0.5);
    var imageExported = new Image();

    // load image from data url
    imageExported.onload = function () {
        context.drawImage(this, 0, 0);
    };

    imageExported.src = dataURL;

    //return the new canvas
    return newCanvas;
}

//--------------------------------------------------------------------------

module.exports = MapView;
<commit_msg>image sources<commit_after>//--------------------------------------------------------------------------

var Context      = require('./context.js'),
    Mouse        = require('./mouse.js'),
    Mover        = require('./mover.js'),
    MapRenderer  = require('../rendering/map-renderer.js'),
    LayerManager = require('../managers/layer-manager.js'),
    Layer        = require('../models/layer.js'),
    Composition  = require('../models/layers/composition.js'),
    Source       = require('../models/source.js'),
    Events       = require('../../libs/events.js'),
    utils        = require('../../../libs/utils.js'),
    _            = require('../../../libs/lodash.js'),
    TWEEN        = require('tween.js');

//--------------------------------------------------------------------------

/**
 * A MapView is the object you get when you create :
 *

 *
a [Map]{@link Maperial#createMap}

 *
an [Anchor]{@link #addAnchor}

 *
a Minifier

 *
a Magnifier

 *
a Lens

 *

 *
 * @constructor
 */
function MapView(maperial, options) {
    this.prepare(maperial, options);
    this.expose();
};

//--------------------------------------------------------------------------
//-     API
//--------------------------------------------------------------------------

MapView.prototype.expose = function () {

    //--------------------------------------------------------------------------
    //      Image Layers
    //--------------------------------------------------------------------------

    /**
     * http://www.thunderforest.com/
     * @function
     */
    this.addOCMTransport = function () {
        return this.addImageLayer(Source.IMAGES_OCM_TRANSPORT);
    }.bind(this);

    /**
     * http://www.thunderforest.com/
     * @function
     */
    this.addOCMLandscape = function () {
        return this.addImageLayer(Source.IMAGES_OCM_LANDSCAPE);
    }.bind(this);

    /**
     * http://www.thunderforest.com/
     * @function
     */
    this.addOCMCycle = function () {
        return this.addImageLayer(Source.IMAGES_OCM_CYCLE);
    }.bind(this);

    /**
     * http://maps.stamen.com/
     * @function
     */
    this.addWatercolor = function () {
        return this.addImageLayer(Source.IMAGES_STAMEN_WATERCOLOR);
    }.bind(this);

    /**
     * http://maps.stamen.com/
     * @function
     */
    this.addTerrain = function () {
        return this.addImageLayer(Source.IMAGES_STAMEN_TERRAIN);
    }.bind(this);

    /**
     * http://maps.stamen.com/
     * @function
     */
    this.addToner = function () {
        return this.addImageLayer(Source.IMAGES_STAMEN_TONER);
    }.bind(this);

    /**
     * http://maps.stamen.com/
     * @function
     */
    this.addTonerBG = function () {
        return this.addImageLayer(Source.IMAGES_STAMEN_TONER_BG);
    }.bind(this);

    /**
     * @function
     */
    this.addMapquest = function () {
        return this.addImageLayer(Source.IMAGES_MAPQUEST);
    }.bind(this);

    /**
     * @function
     */
    this.addSatellite = function () {
        return this.addImageLayer(Source.IMAGES_MAPQUEST_SATELLITE);
    }.bind(this);

    /**
     * @function
     */
    this.addOSM = function () {
        return this.addImageLayer(Source.IMAGES_OSM);
    }.bind(this);

    //--------------------------------------------------------------------------
    //      Maperial layers
    //--------------------------------------------------------------------------

    /**
     * @function
     */
    this.addShade = function () {
        return this.addShadeLayer();
    }.bind(this);

    /**
     * @function
     */
    this.addEarthLight = function () {
        return this.addImageLayer(Source.MAPERIAL_EARTHLIGHT);
    }.bind(this);

    /**
     * @function
     */
    this.addAerosol = function () {
        return this.addImageLayer(Source.MAPERIAL_AEROSOL);
    }.bind(this);

    /**
     * @function
     */
    this.addNDVI = function () {
        return this.addImageLayer(Source.MAPERIAL_NDVI);
    }.bind(this);

    /**
     * @function
     */
    this.addSRTM = function () {
        return this.addImageLayer(Source.MAPERIAL_SRTM);
    }.bind(this);

    /**
     * @function
     */
    this.addSST = function () {
        return this.addImageLayer(Source.MAPERIAL_SST);
    }.bind(this);

    //--------------------------------------------------------------------------
    //      WMS layers
    //--------------------------------------------------------------------------

    /**
     * test WMS CLC
     * @function
     */
    this.addCorineLandCover = function () {
        return this.addImageLayer(Source.WMS_CORINE_LAND_COVER);
    }.bind(this);

    //--------------------------------------------------------------------------
    //      Child MapViews
    //--------------------------------------------------------------------------

    /**
     * @function
     * @param {object} options
     * @param {float} options.width The anchor width, in pixels.
     *                              (Default : map.width/2)
     * @param {float} options.height The anchor height, in pixels.
     *                              (Default : map.height/2)
     * @param {float} options.top The anchor top gap inside the map, in pixels.
     *                              (Default : 0)
     * @param {float} options.left The anchor left gap inside the map, in pixels.
     *                              (Default : 0)
     *
     */
    this.addAnchor = function (options) {
        options = options || {};
        this.prepareChildOptions(options, {
            type : Maperial.ANCHOR
        });

        var width = (options.width || this.width / 2) + 'px';
        var height = (options.height || this.height / 2) + 'px';
        var left = (options.left || 10) + 'px';
        var top = (options.top || 10) + 'px';

        options.container.style.width = width;
        options.container.style.height = height;
        options.container.style.top = top;
        options.container.style.left = left;

        return this.createChild(options);

    }.bind(this);

    /**
     * @function
     * @param {object} options
     * @param {float} options.radius The lens radius, in pixels.
     *                              (Default : map.width * 0.1)
     * @param {float} options.top The lens center from the map top left, in pixels.
     *                              (Default : map.width * 0.5)
     * @param {float} options.left The lens center from the map top left, in pixels.
     *                              (Default : map.width * 0.5)
     *
     */
    this.addLens = function (options) {
        options = options || {};
        this.prepareChildOptions(options, {
            type : Maperial.LENS
        });

        var width = (options.radius * 2 || this.width / 2) + 'px';
        var height = (options.height || this.height / 2) + 'px';
        var left = (options.left || 10) + 'px';
        var top = (options.top || 10) + 'px';

        options.container.style.width = width;
        options.container.style.height = height;
        options.container.style.top = top;
        options.container.style.left = left;

        return this.createChild(options);

    }.bind(this);

    /**
     * @function
     */
    this.addMinifier = function (options) {
        options = options || {};
        options.diffZoom = options.diffZoom || 3;

        this.prepareChildOptions(options, {
            type: Maperial.MINIFIER,
        });

        var defaultTop = this.height - (options.height || 200 ) - 20;
        var width  = (options.width || 200 ) + 'px';
        var height = (options.height || 200 ) + 'px';
        var left   = (options.left || 20) + 'px';
        var top    = (options.top || defaultTop) + 'px';

        options.container.style.width  = width;
        options.container.style.height = height;
        options.container.style.top    = top;
        options.container.style.left   = left;

        var minifier = this.createChild(options);
        minifier.defaultLayer = minifier.layerManager.duplicate(this.layers);

        return minifier;
    }.bind(this);

    /**
     * @function
     */
    this.addMagnifier = function (options) {
        //@todo
    }.bind(this);

};

//--------------------------------------------------------------------------
//-     VIEW
//--------------------------------------------------------------------------

MapView.prototype.prepare = function (maperial, options) {
    console.log("  prepare MapView : " + options.container.id);

    //-------------------------------------------------------------
    // settings

    this.maperial = maperial;
    this.options = options;
    this.id = utils.generateUID() + "_" + this.options.container.id;
    this.container = options.container;
    this.type = options.type;

    //-------------------------------------------------------------
    // plug mixins in

    Events.call(this);

    //-------------------------------------------------------------
    // prepare the view

    this.prepareView();
    this.prepareCamera();

    //-------------------------------------------------------------
    // plug modules

    new Mouse(this);
    new Mover(this);

    //-------------------------------------------------------------

    // array to use push and splice
    this.layers = [];

    // hashmap : tiles[key] = tile
    this.tiles = {};

    // hashmap : dynamicalRenderers[dynamicalData.id] = dynamicalRenderer
    this.dynamicalRenderers = {};

    this.context = new Context(this);

    this.linkedMapViews = [];

    this.mapRenderer = new MapRenderer(this);
    this.layerManager = new LayerManager(this);

    //-------------------------------------------------------------

    this.shaders = [
        Composition.ALPHA_CLIP,
        Composition.ALPHA_BLEND,
        Composition.X_BLEND
    ];
};

//--------------------------------------------------------------------------
//-     CONTAINER
//--------------------------------------------------------------------------

MapView.prototype.prepareView = function () {
    this.canvas = document.createElement('canvas');
    this.container.classList.add(this.type);
    this.container.appendChild(this.canvas);

    this.refresh();
};

MapView.prototype.refresh = function () {
    this.canvas.width = this.width = this.container.clientWidth;
    this.canvas.height = this.height = this.container.clientHeight;
};

//--------------------------------------------------------------------------
//-     PLUGINS for API
//--------------------------------------------------------------------------

MapView.prototype.addImageLayer = function (sourceId) {
    return this.layerManager.addLayer(Layer.Images, sourceId);
};

//-----------------------------------------------------------------

MapView.prototype.addDynamicalLayer = function (dynamicalData, options) {

    //-------------------------------------------
    // Checking options

    var options = utils.prepareOptions(options, "style");
    if (!options) {
        console.log("Wrong call to addDynamicalLayer. Check the options");
    }

    //-------------------------------------------
    // Proceed

    return this.layerManager.addLayer(Layer.Dynamical, {
        mapView: this,
        dynamicalData: dynamicalData,
        style: options.style
    });

};

//-----------------------------------------------------------------

MapView.prototype.addHeatmapLayer = function (heatmapData, options) {

    options.colorbar = options.colorbar ||
        Maperial.colorbarManager.defaultColorbar(this);

    //-------------------------------------------
    // Proceed

    return this.layerManager.addLayer(Layer.Heat, {
        mapView: this,
        heatmapData: heatmapData,
        colorbar: options.colorbar,
        options: options
    });

};

//-----------------------------------------------------------------

// SHADE AND RASTER SHOULD JUST BE OPTIONS IN RETILER TYPE LAYER

MapView.prototype.addShadeLayer = function () {
    return this.layerManager.addLayer(Layer.Shade);
};

//-----------------------------------------------------------------

MapView.prototype.addRasterLayer = function (sourceId) {
    return this.layerManager.addLayer(Layer.Raster, sourceId);
};

//-----------------------------------------------------------------

MapView.prototype.addWMSLayer = function (sourceId) {

};

//-----------------------------------------------------------------

MapView.prototype.addOSMLayer = function (styleId) {
    if (!styleId)
        styleId = Maperial.DEFAULT_STYLE_UID;
};

//--------------------------------------------------------------------------
//-     Child tools
//--------------------------------------------------------------------------

MapView.prototype.prepareChildOptions = function (options, settings) {
    _.extend(options, settings);
    options.container = document.createElement('div');
    this.container.appendChild(options.container);
};

MapView.prototype.createChild = function (options) {
    var child = this.maperial.addMapView(options);
    this.link(child);
    this.options = options;
    child.refreshCamera({
        currentTarget : this
    });
    return child;
};

// links mapViews so that each Event may change the linkedMapViews
MapView.prototype.link = function (view) {
    this.linkedMapViews.forEach(function (link) {
        view.linkedMapViews.push(link);
        link.linkedMapViews.push(view);

        link.on(Maperial.EVENTS.MAP_MOVED, this.refreshCamera.bind(view));
        view.on(Maperial.EVENTS.MAP_MOVED, this.refreshCamera.bind(link));
    }.bind(this));

    view.linkedMapViews.push(this);
    this.linkedMapViews.push(view);

    this.on(Maperial.EVENTS.MAP_MOVED, this.refreshCamera.bind(view));
    view.on(Maperial.EVENTS.MAP_MOVED, this.refreshCamera.bind(this));
}

//--------------------------------------------------------------------------
//-     Camera
// TODO: create ./camera.js and move the following algo there
//--------------------------------------------------------------------------

MapView.prototype.prepareCamera = function () {
    this.on('zoom-in', function () {
        if ((this.options.zoomMax || 18) > this.context.zoom) {
            this.zoomCanvas(2);
            this.context.zoom++;
            this.trigger(Maperial.EVENTS.MAP_MOVED);
        }
    }.bind(this));

    this.on('zoom-out', function () {
        if ((this.options.zoomMin || 2) < this.context.zoom) {
            this.zoomCanvas(0.5);
            this.context.zoom--;
            this.trigger(Maperial.EVENTS.MAP_MOVED);
        }
    }.bind(this));
};

//--------------------------------------------------------------------------

MapView.prototype.refreshCamera = function (event) {

    var initiator = event.currentTarget;

    switch (this.type) {
        case Maperial.MINIFIER:
            this.context.zoom = initiator.context.zoom - this.options.diffZoom;
            this.context.centerM = initiator.context.centerM;
            break;

        case Maperial.MAGNIFIER:
            this.context.centerM = initiator.context.mouseM;
            break;

        case Maperial.MAIN:
        case Maperial.LENS:
        case Maperial.ANCHOR:
            this.context.zoom = initiator.context.zoom;

            var initiatorBox = initiator.container.getBoundingClientRect();
            var initiatorCenterX = initiatorBox.left + initiatorBox.width / 2;
            var initiatorCenterY = initiatorBox.top + initiatorBox.height / 2;

            var myBox = this.container.getBoundingClientRect();
            var myCenterX = myBox.left + myBox.width / 2;
            var myCenterY = myBox.top + myBox.height / 2;

            var initiatorCenterP = utils.centerInPixels(initiator.context);
            var newCenterP = {
                x: initiatorCenterP.x - initiatorCenterX + myCenterX,
                y: initiatorCenterP.y + initiatorCenterY - myCenterY
            };

            this.context.centerM = utils.pointInMeters(
                newCenterP,
                this.context
            );

            break;
    }

}

//--------------------------------------------------------------------------
// TODO: create ./zoomer.js and move the following algo there

MapView.prototype.zoomCanvas = function (scaleTo) {

    var canvas = cloneCanvas(this.canvas),
        div = document.createElement('div'),
        container = this.container;

    div.className = 'maperial-zoomer';
    div.style.position = 'absolute';
    div.style.top = '0';
    div.style.overflow = 'hidden';

    div.appendChild(canvas);
    container.appendChild(div);

    var from = {
            scale: 1
        },
        to = {
            scale: scaleTo
        },
        time = 600,
        tween = new TWEEN.Tween(from)
        .to(to, time)
        .easing(TWEEN.Easing.Circular.Out)
        .onUpdate(function () {
            var transform = 'scale(' + this.scale + ')';
            canvas.style.webkitTransform = transform;
            canvas.style.transform = transform;
        })
        .onComplete(function () {
            var from = {
                    alpha: 1
                },
                to = {
                    alpha: 0
                },
                time = 500,
                tween = new TWEEN.Tween(from)
                .to(to, time)
                .easing(TWEEN.Easing.Circular.In)
                .onUpdate(function () {
                    canvas.style.opacity = this.alpha;
                })
                .onComplete(function () {
                    container.removeChild(div);
                })
                .start();
        })
        .start();

}

function cloneCanvas(oldCanvas) {

    //create a new canvas
    var newCanvas = document.createElement('canvas');
    var context = newCanvas.getContext('2d');

    //set dimensions
    newCanvas.width = oldCanvas.width;
    newCanvas.height = oldCanvas.height;

    //+ translate3d pour recentrer.
    //chech taille du container VS taille du canvas...?
    newCanvas.style.position = 'relative';

    var dataURL = oldCanvas.toDataURL('image/jpeg', 0.5);
    var imageExported = new Image();

    // load image from data url
    imageExported.onload = function () {
        context.drawImage(this, 0, 0);
    };

    imageExported.src = dataURL;

    //return the new canvas
    return newCanvas;
}

//--------------------------------------------------------------------------

module.exports = MapView;
<|endoftext|>


<commit_before>

(function() {

  /**
   * User stats embeded in the dashboard
   *
   * It shows the tables and the space used in the user account
   * You must set the username, the user id and the tables model,
   * if not, it won't work.
   *
   * Usage example:
   *
      this.tableStats = new cdb.admin.dashboard.TableStats({
        el: $('div.subheader'),
        tables: this.tables*,
        model: this.user**
      })

      *   It needs a table model to run correctly.
      **  It needs a table model to work properly.
   *
   */

  var TableStats = cdb.core.View.extend({

    defaults: {
      loaded: false
    },

    events: {
      'click section.warning a.close':  '_disableWarning'
    },

    initialize: function() {

      // If the user doesn't want to see the warning anymore
      this.warning = true;

      // If any change happened in the tables model, fetch the user stats
      this.options.tables.bind('add',     this._tableChange, this);
      this.options.tables.bind('remove',  this._tableChange, this);
      this.options.tables.bind('reset',   this._tableChange, this);

      // Any change, render this view
      this.model.bind('change', this.render, this);
    },

    /*
     * Table change function -> Fetch model!
     */
    _tableChange: function() {
      this.model.fetch();
    },

    render: function() {

      // Calculate quotas first
      this._calculateQuotas();

      // If there is no tables in this account, activate or desactivate
      if (this.model.get("table_count") > 0) {
        this._activate();
      } else {
        this._desactivate();
      }

      // If there is danger...
      if (this.model.attributes.byte_quota_status != "" || this.model.attributes.table_quota_status != "") {
        this._showWarning();
      } else {
        this._hideWarning();
      }

      // Rendering for the first time?
      if (!this.options.loaded) {
        this.options.loaded = !this.options.loaded;

        // D3 API Requests
        this.stats = this.stats = new cdb.admin.D3Stats({
          el: this.$el.find("li:eq(2)"),
          api_calls: this.model.attributes.api_calls
        });
      }

      // Animate the stats change
      this._animateChange();

      return this;
    },

    /*
     * Calculate user quotas (calculations will be in the model)
     */
    _calculateQuotas: function() {

      var attrs = this.model.attributes;

      // Check tables count quota status
      if (((attrs.table_count / attrs.table_quota) * 100) < 80) {
        attrs.table_quota_status = "";
      } else {
        if (((attrs.table_count / attrs.table_quota) * 100) < 90) {
          attrs.table_quota_status = "danger";
        } else {
          attrs.table_quota_status = "boom";
        }
      }

      // Check table space quota status
      if ((((attrs.byte_quota - attrs.remaining_byte_quota) / attrs.byte_quota) * 100) < 80) {
        attrs.byte_quota_status = "";
      } else {
        if ((((attrs.byte_quota - attrs.remaining_byte_quota) / attrs.byte_quota) * 100) < 90) {
          attrs.byte_quota_status = "danger";
        } else {
          attrs.byte_quota_status = "boom";
        }
      }

      this.model.attributes = attrs;
    },

    /*
     * Animate the changes in the view
     */
    _animateChange: function() {

      var attrs = this.model.attributes
        , $tables = this.$el.find("section.stats li:eq(0)")
        , $space = this.$el.find("section.stats li:eq(1)");

      // Tables change
      $tables.find("p").html("" + attrs.table_count + " of " + attrs.table_quota + " tables created");
      $tables.find("div.progress span")
        .removeAttr("class").addClass(attrs.table_quota_status)
        .animate({
          width: ((attrs.table_count / attrs.table_quota) * 100) + "%"
        },500);

      // Space change
      $space.find("p").html("" + (( attrs.byte_quota - attrs.remaining_byte_quota ) / (1024*1024)).toFixed(2) + " of " + (attrs.byte_quota / (1024*1024)).toFixed(0) + " used megabytes");
      $space.find("div.progress span")
        .removeAttr("class").addClass(attrs.byte_quota_status)
        .animate({
          width: (((attrs.byte_quota - attrs.remaining_byte_quota) / attrs.byte_quota) * 100) + "%"
        },500);
    },

    /*
     * Disabled the warning upgrade flash
     */
    _disableWarning: function(ev) {
      ev.preventDefault();
      this.warning = false;
      this._hideWarning();
    },

    /*
     * Show the warning upgrade flash
     */
    _showWarning: function() {
      if (this.warning)
        this.$el.find("section.warning").addClass("visible");
    },

    /*
     * Hide the warning upgrade flash
     */
    _hideWarning: function() {
      this.$el.find("section.warning").removeClass("visible");
    },

    /*
     * Activate the table stats
     */
    _activate: function() {
      this.$el.addClass("active");
    },

    /*
     * Desactivate the table stats
     */
    _desactivate: function() {
      this.$el.removeClass("active");
    }
  });

  cdb.admin.dashboard.TableStats = TableStats;
})();

<commit_msg>0.00 fixed to 0<commit_after>

(function() {

  /**
   * User stats embeded in the dashboard
   *
   * It shows the tables and the space used in the user account
   * You must set the username, the user id and the tables model,
   * if not, it won't work.
   *
   * Usage example:
   *
      this.tableStats = new cdb.admin.dashboard.TableStats({
        el: $('div.subheader'),
        tables: this.tables*,
        model: this.user**
      })

      *   It needs a table model to run correctly.
      **  It needs a table model to work properly.
   *
   */

  var TableStats = cdb.core.View.extend({

    defaults: {
      loaded: false
    },

    events: {
      'click section.warning a.close':  '_disableWarning'
    },

    initialize: function() {

      // If the user doesn't want to see the warning anymore
      this.warning = true;

      // If any change happened in the tables model, fetch the user stats
      this.options.tables.bind('add',     this._tableChange, this);
      this.options.tables.bind('remove',  this._tableChange, this);
      this.options.tables.bind('reset',   this._tableChange, this);

      // Any change, render this view
      this.model.bind('change', this.render, this);
    },

    /*
     * Table change function -> Fetch model!
     */
    _tableChange: function() {
      this.model.fetch();
    },

    render: function() {

      // Calculate quotas first
      this._calculateQuotas();

      // If there is no tables in this account, activate or desactivate
      if (this.model.get("table_count") > 0) {
        this._activate();
      } else {
        this._desactivate();
      }

      // If there is danger...
      if (this.model.attributes.byte_quota_status != "" || this.model.attributes.table_quota_status != "") {
        this._showWarning();
      } else {
        this._hideWarning();
      }

      // Rendering for the first time?
      if (!this.options.loaded) {
        this.options.loaded = !this.options.loaded;

        // D3 API Requests
        this.stats = this.stats = new cdb.admin.D3Stats({
          el: this.$el.find("li:eq(2)"),
          api_calls: this.model.attributes.api_calls
        });
      }

      // Animate the stats change
      this._animateChange();

      return this;
    },

    /*
     * Calculate user quotas (calculations will be in the model)
     */
    _calculateQuotas: function() {

      var attrs = this.model.attributes;

      // Check tables count quota status
      if (((attrs.table_count / attrs.table_quota) * 100) < 80) {
        attrs.table_quota_status = "";
      } else {
        if (((attrs.table_count / attrs.table_quota) * 100) < 90) {
          attrs.table_quota_status = "danger";
        } else {
          attrs.table_quota_status = "boom";
        }
      }

      // Check table space quota status
      if ((((attrs.byte_quota - attrs.remaining_byte_quota) / attrs.byte_quota) * 100) < 80) {
        attrs.byte_quota_status = "";
      } else {
        if ((((attrs.byte_quota - attrs.remaining_byte_quota) / attrs.byte_quota) * 100) < 90) {
          attrs.byte_quota_status = "danger";
        } else {
          attrs.byte_quota_status = "boom";
        }
      }

      this.model.attributes = attrs;
    },

    /*
     * Animate the changes in the view
     */
    _animateChange: function() {

      var attrs = this.model.attributes
        , $tables = this.$el.find("section.stats li:eq(0)")
        , $space = this.$el.find("section.stats li:eq(1)");

      // Tables change
      $tables.find("p").html("" + attrs.table_count + " of " + attrs.table_quota + " tables created");
      $tables.find("div.progress span")
        .removeAttr("class").addClass(attrs.table_quota_status)
        .animate({
          width: ((attrs.table_count / attrs.table_quota) * 100) + "%"
        },500);

      // Space change
      var remaining_quota = (( attrs.byte_quota - attrs.remaining_byte_quota ) / (1024*1024)).toFixed(2)
        , remaining_in_bytes = remaining_quota == 0.00 ? 0 : remaining_quota;

      $space.find("p").html("" + remaining_in_bytes + " of " + (attrs.byte_quota / (1024*1024)).toFixed(0) + " used megabytes");
      $space.find("div.progress span")
        .removeAttr("class").addClass(attrs.byte_quota_status)
        .animate({
          width: (((attrs.byte_quota - attrs.remaining_byte_quota) / attrs.byte_quota) * 100) + "%"
        },500);
    },

    /*
     * Disabled the warning upgrade flash
     */
    _disableWarning: function(ev) {
      ev.preventDefault();
      this.warning = false;
      this._hideWarning();
    },

    /*
     * Show the warning upgrade flash
     */
    _showWarning: function() {
      if (this.warning)
        this.$el.find("section.warning").addClass("visible");
    },

    /*
     * Hide the warning upgrade flash
     */
    _hideWarning: function() {
      this.$el.find("section.warning").removeClass("visible");
    },

    /*
     * Activate the table stats
     */
    _activate: function() {
      this.$el.addClass("active");
    },

    /*
     * Desactivate the table stats
     */
    _desactivate: function() {
      this.$el.removeClass("active");
    }
  });

  cdb.admin.dashboard.TableStats = TableStats;
})();

<|endoftext|>


<commit_before>const hooks = require('feathers-hooks-common');
const auth = require('@feathersjs/authentication');
const { Forbidden } = require('@feathersjs/errors');

const globalHooks = require('../../../hooks');

const checkPermissions = async (hook) => {
	const targetUser = await hook.app.service('users').get(hook.params.route.userid,
		{ query: { $populate: 'roles' } });
	const actingUser = await hook.app.service('users').get(hook.params.account.userId);

	const targetIsStudent = targetUser.roles[0].name === 'student';
	const targetIsTeacher = targetUser.roles[0].name === 'teacher';
	let hasPermission = false;

	if (targetIsStudent && actingUser.permissions.includes('STUDENT_SKIP_REGISTRATION')) {
		hasPermission = true;
	}
	if (targetIsTeacher && actingUser.permissions.includes('TEACHER_SKIP_REGISTRATION')) {
		hasPermission = true;
	}
	if (targetUser.schoolId !== actingUser.schoolId) hasPermission = false;
	if (!hasPermission) return Promise.reject(new Forbidden('you do not have permission to do this!'));

	return Promise.resolve(hook);
};

exports.before = {
	all: [auth.hooks.authenticate('jwt')],
	find: [hooks.disallow()],
	get: [hooks.disallow()],
	create: [globalHooks.ifNotLocal(checkPermissions)],
	update: [hooks.disallow()],
	patch: [hooks.disallow()],
	remove: [hooks.disallow()],
};

exports.after = {
	all: [],
	find: [],
	get: [],
	create: [],
	update: [],
	patch: [],
	remove: [],
};
<commit_msg>fix schoolId comparison<commit_after>const hooks = require('feathers-hooks-common');
const auth = require('@feathersjs/authentication');
const { Forbidden } = require('@feathersjs/errors');

const globalHooks = require('../../../hooks');

const checkPermissions = async (hook) => {
	const targetUser = await hook.app.service('users').get(hook.params.route.userid,
		{ query: { $populate: 'roles' } });
	const actingUser = await hook.app.service('users').get(hook.params.account.userId);

	const targetIsStudent = targetUser.roles[0].name === 'student';
	const targetIsTeacher = targetUser.roles[0].name === 'teacher';
	let hasPermission = false;

	if (targetIsStudent && actingUser.permissions.includes('STUDENT_SKIP_REGISTRATION')) {
		hasPermission = true;
	}
	if (targetIsTeacher && actingUser.permissions.includes('TEACHER_SKIP_REGISTRATION')) {
		hasPermission = true;
	}
	if (targetUser.schoolId.toString() !== actingUser.schoolId.toString()) hasPermission = false;
	if (!hasPermission) return Promise.reject(new Forbidden('you do not have permission to do this!'));

	return Promise.resolve(hook);
};

exports.before = {
	all: [auth.hooks.authenticate('jwt')],
	find: [hooks.disallow()],
	get: [hooks.disallow()],
	create: [globalHooks.ifNotLocal(checkPermissions)],
	update: [hooks.disallow()],
	patch: [hooks.disallow()],
	remove: [hooks.disallow()],
};

exports.after = {
	all: [],
	find: [],
	get: [],
	create: [],
	update: [],
	patch: [],
	remove: [],
};
<|endoftext|>