<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

tvcm.require('tvcm.range');
tvcm.require('tvcm.ui.d3');
tvcm.require('tvcm.ui.dom_helpers');
tvcm.require('tvcm.ui.chart_base');

tvcm.requireStylesheet('tvcm.ui.pie_chart');

tvcm.exportTo('tvcm.ui', function() {
  var ChartBase = tvcm.ui.ChartBase;
  var getColorOfKey = tvcm.ui.getColorOfKey;

  var MIN_RADIUS = 100;

  /**
   * @constructor
   */
  var PieChart = tvcm.ui.define('pie-chart', ChartBase);

  PieChart.prototype = {
    __proto__: ChartBase.prototype,

    decorate: function() {
      ChartBase.prototype.decorate.call(this);
      this.classList.add('pie-chart');

      this.data_ = undefined;
      this.seriesKeys_ = undefined;

      var chartAreaSel = d3.select(this.chartAreaElement);
      var pieGroupSel = chartAreaSel.append('g')
        .attr('class', 'pie-group');
      this.pieGroup_ = pieGroupSel.node();

      this.pathsGroup_ = pieGroupSel.append('g')
        .attr('class', 'paths')
        .node();
      this.labelsGroup_ = pieGroupSel.append('g')
        .attr('class', 'labels')
        .node();
      this.linesGroup_ = pieGroupSel.append('g')
        .attr('class', 'lines')
        .node();
    },

    get data() {
      return this.data_;
    },

    /**
     * @param {Array} data Data for the chart, where each element in the array
     * must be of the form {label: str, value: number}.
     */
    set data(data) {
      if (data !== undefined) {
        // Figure out the label values in the data set. E.g. from
        //   [{label: 'a', ...}, {label: 'b', ...}]
        // we would commpute ['a', 'y']. These become the series keys.
        var seriesKeys = [];
        var seenSeriesKeys = {};
        data.forEach(function(d) {
          var k = d.label;
          if (seenSeriesKeys[k])
            throw new Error('Label ' + k + ' has been used already');
          seriesKeys.push(k);
          seenSeriesKeys[k] = true;
        }, this);
        this.seriesKeys_ = seriesKeys;
      } else {
        this.seriesKeys_ = undefined;
      }
      this.data_ = data;
      this.updateContents_();
    },

    get margin() {
      var margin = {top: 0, right: 0, bottom: 0, left: 0};
      if (this.chartTitle_)
        margin.top += 40;
      return margin;
    },

    getMinSize: function() {
      if (!tvcm.ui.isElementAttachedToDocument(this))
        throw new Error('Cannot measure when unattached');
      this.updateContents_();

      var labelSel = d3.select(this.labelsGroup_).selectAll('.label');
      var maxLabelWidth = -Number.MAX_VALUE;
      var leftTextHeightSum = 0;
      var rightTextHeightSum = 0;
      labelSel.each(function(l) {
        var r = this.getBoundingClientRect();
        maxLabelWidth = Math.max(maxLabelWidth, r.width);
        if (this.style.textAnchor == 'end') {
          leftTextHeightSum += r.height;
        } else {
          rightTextHeightSum += r.height;
        }
      });

      var titleWidth = this.querySelector(
          '#title').getBoundingClientRect().width;
      var margin = this.margin;
      var marginWidth = margin.left + margin.right;
      var marginHeight = margin.top + margin.bottom;
      return {
        width: Math.max(2 * MIN_RADIUS + 2 * maxLabelWidth,
                        titleWidth * 1.1) + marginWidth,
        height: marginHeight + Math.max(2 * MIN_RADIUS,
                                        leftTextHeightSum,
                                        rightTextHeightSum) * 1.25
      };
    },

    getLegendKeys_: function() {
      // This class creates its own legend, instead of using ChartBase.
      return undefined;
    },

    updateScales_: function(width, height) {
      if (this.data_ === undefined)
        return;
    },

    updateContents_: function() {
      ChartBase.prototype.updateContents_.call(this);
      if (!this.data_)
        return;

      var width = this.chartAreaSize.width;
      var height = this.chartAreaSize.height;
      var radius = Math.max(MIN_RADIUS, Math.min(width, height) / 2);

      d3.select(this.pieGroup_).attr(
          'transform',
          'translate(' + width / 2 + ',' + height / 2 + ')');

      // Bind the pie layout to its data
      var pieLayout = d3.layout.pie()
        .value(function(d) { return d.value; })
        .sort(null);

      var piePathsSel = d3.select(this.pathsGroup_)
          .datum(this.data_)
          .selectAll('path')
          .data(pieLayout);

      function midAngle(d) {
        return d.startAngle + (d.endAngle - d.startAngle) / 2;
      }

      var pathsArc = d3.svg.arc()
        .innerRadius(0)
        .outerRadius(radius - 30);

      var valueLabelArc = d3.svg.arc()
        .innerRadius(radius - 100)
        .outerRadius(radius - 30);

      var lineBeginArc = d3.svg.arc()
        .innerRadius(radius - 50)
        .outerRadius(radius - 50);

      var lineEndArc = d3.svg.arc()
        .innerRadius(radius)
        .outerRadius(radius);

      // Paths.
      piePathsSel.enter().append('path')
        .attr('class', 'arc')
        .attr('fill', function(d, i) {
            var origData = this.data_[i];
            var highlighted = (origData.label ===
                               this.currentHighlightedLegendKey);
            return getColorOfKey(origData.label, highlighted);
          }.bind(this))
        .attr('d', pathsArc)
        .on('click', function(d, i) {
            var origData = this.data_[i];
            if (origData.onClick)
              origData.onClick(d, i);
            d3.event.stopPropagation();
          }.bind(this))
        .on('mouseenter', function(d, i) {
            var origData = this.data_[i];
            this.pushTempHighlightedLegendKey(origData.label);
          }.bind(this))
        .on('mouseleave', function(d, i) {
            var origData = this.data_[i];
            this.popTempHighlightedLegendKey(origData.label);
          }.bind(this));

      // Value labels.
      piePathsSel.enter().append('text')
        .attr('class', 'arc-text')
        .attr('transform', function(d) {
            return 'translate(' + valueLabelArc.centroid(d) + ')';
          })
        .attr('dy', '.35em')
        .style('text-anchor', 'middle')
        .text(function(d, i) {
            var origData = this.data_[i];
            if (origData.valueText === undefined)
              return '';

            if (d.endAngle - d.startAngle < 0.4)
              return '';
            return origData.valueText;
          }.bind(this));

      piePathsSel.exit().remove();

      // Labels.
      var labelSel = d3.select(this.labelsGroup_).selectAll('.label')
          .data(pieLayout(this.data_));
      labelSel.enter()
          .append('text')
          .attr('class', 'label')
          .attr('dy', '.35em');

      labelSel.text(function(d) {
        if (d.data.label.length > 40)
          return d.data.label.substr(0, 40) + '...';
        return d.data.label;
      });
      labelSel.attr('transform', function(d) {
        var pos = lineEndArc.centroid(d);
        pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1);
        return 'translate(' + pos + ')';
      });
      labelSel.style('text-anchor', function(d) {
        return midAngle(d) < Math.PI ? 'start' : 'end';
      });

      // Lines.
      var lineSel = d3.select(this.linesGroup_).selectAll('.line')
          .data(pieLayout(this.data_));
      lineSel.enter()
        .append('polyline')
        .attr('class', 'line')
        .attr('dy', '.35em');
      lineSel.attr('points', function(d) {
        var pos = lineEndArc.centroid(d);
        pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1);
        return [lineBeginArc.centroid(d), lineEndArc.centroid(d), pos];
      });
    },

    updateHighlight_: function() {
      ChartBase.prototype.updateHighlight_.call(this);
      // Update color of pie segments.
      var pathsGroupSel = d3.select(this.pathsGroup_);
      var that = this;
      pathsGroupSel.selectAll('.arc').each(function(d, i) {
        var origData = that.data_[i];
        var highlighted = origData.label == that.currentHighlightedLegendKey;
        var color = getColorOfKey(origData.label, highlighted);
        this.style.fill = color;
      });
    }
  };

  return {
    PieChart: PieChart
  };
});
<commit_msg>Tweak sizinig heuristics for pie chart<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

tvcm.require('tvcm.range');
tvcm.require('tvcm.ui.d3');
tvcm.require('tvcm.ui.dom_helpers');
tvcm.require('tvcm.ui.chart_base');

tvcm.requireStylesheet('tvcm.ui.pie_chart');

tvcm.exportTo('tvcm.ui', function() {
  var ChartBase = tvcm.ui.ChartBase;
  var getColorOfKey = tvcm.ui.getColorOfKey;

  var MIN_RADIUS = 100;

  /**
   * @constructor
   */
  var PieChart = tvcm.ui.define('pie-chart', ChartBase);

  PieChart.prototype = {
    __proto__: ChartBase.prototype,

    decorate: function() {
      ChartBase.prototype.decorate.call(this);
      this.classList.add('pie-chart');

      this.data_ = undefined;
      this.seriesKeys_ = undefined;

      var chartAreaSel = d3.select(this.chartAreaElement);
      var pieGroupSel = chartAreaSel.append('g')
        .attr('class', 'pie-group');
      this.pieGroup_ = pieGroupSel.node();

      this.pathsGroup_ = pieGroupSel.append('g')
        .attr('class', 'paths')
        .node();
      this.labelsGroup_ = pieGroupSel.append('g')
        .attr('class', 'labels')
        .node();
      this.linesGroup_ = pieGroupSel.append('g')
        .attr('class', 'lines')
        .node();
    },

    get data() {
      return this.data_;
    },

    /**
     * @param {Array} data Data for the chart, where each element in the array
     * must be of the form {label: str, value: number}.
     */
    set data(data) {
      if (data !== undefined) {
        // Figure out the label values in the data set. E.g. from
        //   [{label: 'a', ...}, {label: 'b', ...}]
        // we would commpute ['a', 'y']. These become the series keys.
        var seriesKeys = [];
        var seenSeriesKeys = {};
        data.forEach(function(d) {
          var k = d.label;
          if (seenSeriesKeys[k])
            throw new Error('Label ' + k + ' has been used already');
          seriesKeys.push(k);
          seenSeriesKeys[k] = true;
        }, this);
        this.seriesKeys_ = seriesKeys;
      } else {
        this.seriesKeys_ = undefined;
      }
      this.data_ = data;
      this.updateContents_();
    },

    get margin() {
      var margin = {top: 0, right: 0, bottom: 0, left: 0};
      if (this.chartTitle_)
        margin.top += 40;
      return margin;
    },

    getMinSize: function() {
      if (!tvcm.ui.isElementAttachedToDocument(this))
        throw new Error('Cannot measure when unattached');
      this.updateContents_();

      var labelSel = d3.select(this.labelsGroup_).selectAll('.label');
      var maxLabelWidth = -Number.MAX_VALUE;
      var leftTextHeightSum = 0;
      var rightTextHeightSum = 0;
      labelSel.each(function(l) {
        var r = this.getBoundingClientRect();
        maxLabelWidth = Math.max(maxLabelWidth, r.width + 32);
        if (this.style.textAnchor == 'end') {
          leftTextHeightSum += r.height;
        } else {
          rightTextHeightSum += r.height;
        }
      });

      var titleWidth = this.querySelector(
          '#title').getBoundingClientRect().width;
      var margin = this.margin;
      var marginWidth = margin.left + margin.right;
      var marginHeight = margin.top + margin.bottom;
      return {
        width: Math.max(2 * MIN_RADIUS + 2 * maxLabelWidth,
                        titleWidth * 1.1) + marginWidth,
        height: marginHeight + Math.max(2 * MIN_RADIUS,
                                        leftTextHeightSum,
                                        rightTextHeightSum) * 1.25
      };
    },

    getLegendKeys_: function() {
      // This class creates its own legend, instead of using ChartBase.
      return undefined;
    },

    updateScales_: function(width, height) {
      if (this.data_ === undefined)
        return;
    },

    updateContents_: function() {
      ChartBase.prototype.updateContents_.call(this);
      if (!this.data_)
        return;

      var width = this.chartAreaSize.width;
      var height = this.chartAreaSize.height;
      var radius = Math.max(MIN_RADIUS, Math.min(width, height * 0.95) / 2);

      d3.select(this.pieGroup_).attr(
          'transform',
          'translate(' + width / 2 + ',' + height / 2 + ')');

      // Bind the pie layout to its data
      var pieLayout = d3.layout.pie()
        .value(function(d) { return d.value; })
        .sort(null);

      var piePathsSel = d3.select(this.pathsGroup_)
          .datum(this.data_)
          .selectAll('path')
          .data(pieLayout);

      function midAngle(d) {
        return d.startAngle + (d.endAngle - d.startAngle) / 2;
      }

      var pathsArc = d3.svg.arc()
        .innerRadius(0)
        .outerRadius(radius - 30);

      var valueLabelArc = d3.svg.arc()
        .innerRadius(radius - 100)
        .outerRadius(radius - 30);

      var lineBeginArc = d3.svg.arc()
        .innerRadius(radius - 50)
        .outerRadius(radius - 50);

      var lineEndArc = d3.svg.arc()
        .innerRadius(radius)
        .outerRadius(radius);

      // Paths.
      piePathsSel.enter().append('path')
        .attr('class', 'arc')
        .attr('fill', function(d, i) {
            var origData = this.data_[i];
            var highlighted = (origData.label ===
                               this.currentHighlightedLegendKey);
            return getColorOfKey(origData.label, highlighted);
          }.bind(this))
        .attr('d', pathsArc)
        .on('click', function(d, i) {
            var origData = this.data_[i];
            if (origData.onClick)
              origData.onClick(d, i);
            d3.event.stopPropagation();
          }.bind(this))
        .on('mouseenter', function(d, i) {
            var origData = this.data_[i];
            this.pushTempHighlightedLegendKey(origData.label);
          }.bind(this))
        .on('mouseleave', function(d, i) {
            var origData = this.data_[i];
            this.popTempHighlightedLegendKey(origData.label);
          }.bind(this));

      // Value labels.
      piePathsSel.enter().append('text')
        .attr('class', 'arc-text')
        .attr('transform', function(d) {
            return 'translate(' + valueLabelArc.centroid(d) + ')';
          })
        .attr('dy', '.35em')
        .style('text-anchor', 'middle')
        .text(function(d, i) {
            var origData = this.data_[i];
            if (origData.valueText === undefined)
              return '';

            if (d.endAngle - d.startAngle < 0.4)
              return '';
            return origData.valueText;
          }.bind(this));

      piePathsSel.exit().remove();

      // Labels.
      var labelSel = d3.select(this.labelsGroup_).selectAll('.label')
          .data(pieLayout(this.data_));
      labelSel.enter()
          .append('text')
          .attr('class', 'label')
          .attr('dy', '.35em');

      labelSel.text(function(d) {
        if (d.data.label.length > 40)
          return d.data.label.substr(0, 40) + '...';
        return d.data.label;
      });
      labelSel.attr('transform', function(d) {
        var pos = lineEndArc.centroid(d);
        pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1);
        return 'translate(' + pos + ')';
      });
      labelSel.style('text-anchor', function(d) {
        return midAngle(d) < Math.PI ? 'start' : 'end';
      });

      // Lines.
      var lineSel = d3.select(this.linesGroup_).selectAll('.line')
          .data(pieLayout(this.data_));
      lineSel.enter()
        .append('polyline')
        .attr('class', 'line')
        .attr('dy', '.35em');
      lineSel.attr('points', function(d) {
        var pos = lineEndArc.centroid(d);
        pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1);
        return [lineBeginArc.centroid(d), lineEndArc.centroid(d), pos];
      });
    },

    updateHighlight_: function() {
      ChartBase.prototype.updateHighlight_.call(this);
      // Update color of pie segments.
      var pathsGroupSel = d3.select(this.pathsGroup_);
      var that = this;
      pathsGroupSel.selectAll('.arc').each(function(d, i) {
        var origData = that.data_[i];
        var highlighted = origData.label == that.currentHighlightedLegendKey;
        var color = getColorOfKey(origData.label, highlighted);
        this.style.fill = color;
      });
    }
  };

  return {
    PieChart: PieChart
  };
});
<|endoftext|>


<commit_before>const Eris = require("eris");
const Base = require("../structures/Base.js");
const { inspect } = require('util');

/**
 *
 *
 * @class Cluster
 */
class Cluster {

    /**
     * Creates an instance of Cluster.
     * @param {any} clusterID
     * @memberof Cluster
     */
    constructor() {

        this.shards = 0;
        this.maxShards = 0;
        this.firstShardID = 0;
        this.lastShardID = 0;
        this.mainFile = null;
        this.clusterID = 0;
        this.clusterCount = 0;
        this.guilds = 0;
        this.users = 0;
        this.uptime = 0;
        this.exclusiveGuilds = 0;
        this.largeGuilds = 0;
        this.voiceChannels = 0;
        this.shardsStats = [];
        this.app = null;
        this.bot = null;
        this.test = false;

        console.log = (str) => process.send({ name: "log", msg: this.logOverride(str) });
        console.error = (str) => process.send({ name: "error", msg: this.logOverride(str) });
        console.warn = (str) => process.send({ name: "warn", msg: this.logOverride(str) });
        console.info = (str) => process.send({ name: "info", msg: this.logOverride(str) });
        console.debug = (str) => process.send({ name: "debug", msg: this.logOverride(str) });

    }

    logOverride(message) {
        if (typeof message == 'object') return inspect(message);
        else return message;
    }

    spawn() {
        process.on('uncaughtException', (err) => {
            process.send({ name: "error", msg: err.stack });
        });

        process.on('unhandledRejection', (reason, p) => {
            process.send({ name: "error", msg: `Unhandled rejection at: Promise  ${p} reason:  ${reason.stack}` });
        });

        process.on("message", msg => {
            if (msg.name) {
                switch (msg.name) {
                    case "connect": {
                        this.firstShardID = msg.firstShardID;
                        this.lastShardID = msg.lastShardID;
                        this.mainFile = msg.file;
                        this.clusterID = msg.id;
                        this.clusterCount = msg.clusterCount;
                        this.shards = (this.lastShardID - this.firstShardID) + 1;
                        this.maxShards = msg.maxShards;

                        if (this.shards < 1) return;

                        if (msg.test) {
                            this.test = true;
                        }

                        this.connect(msg.firstShardID, msg.lastShardID, this.maxShards, msg.token, "connect", msg.clientOptions);

                        break;
                    }
                    case "stats": {
                        process.send({
                            name: "stats", stats: {
                                guilds: this.guilds,
                                users: this.users,
                                uptime: this.uptime,
                                ram: process.memoryUsage().rss,
                                shards: this.shards,
                                exclusiveGuilds: this.exclusiveGuilds,
                                largeGuilds: this.largeGuilds,
                                voice: this.voiceChannels,
                                shardsStats: this.shardsStats
                            }
                        });

                        break;
                    }
                    case "fetchUser": {
                        if (!this.bot) return;
                        let id = msg.value;
                        let user = this.bot.users.get(id);
                        if (user) {
                            process.send({ name: "fetchReturn", value: user });
                        }

                        break;
                    }
                    case "fetchChannel": {
                        if (!this.bot) return;
                        let id = msg.value;
                        let channel = this.bot.getChannel(id);
                        if (channel) {
                            channel = channel.toJSON();
                            return process.send({ name: "fetchReturn", value: channel });
                        }

                        break;
                    }
                    case "fetchGuild": {
                        if (!this.bot) return;
                        let id = msg.value;
                        let guild = this.bot.guilds.get(id);
                        if (guild) {
                            guild = guild.toJSON();
                            process.send({ name: "fetchReturn", value: guild });
                        }

                        break;
                    }
                    case "fetchMember": {
                        if (!this.bot) return;
                        let [guildID, memberID] = msg.value;

                        let guild = this.bot.guilds.get(guildID);

                        if (guild) {
                            let member = guild.members.get(memberID);

                            if (member) {
                                member = member.toJSON();
                                process.send({ name: "fetchReturn", value: member });
                            }
                        }

                        break;
                    }
                    case "fetchReturn":
                        this.ipc.emit(msg.id, msg.value);
                        break;
                    case "restart":
                        process.exit(1);
                        break;
                }
            }
        });
    }

    /**
     *
     *
     * @param {any} firstShardID
     * @param {any} lastShardID
     * @param {any} maxShards
     * @param {any} token
     * @param {any} type
     * @memberof Cluster
     */
    connect(firstShardID, lastShardID, maxShards, token, type, clientOptions) {
        process.send({ name: "log", msg: `Connecting with ${this.shards} shard(s)` });

        let options = { autoreconnect: true, firstShardID: firstShardID, lastShardID: lastShardID, maxShards: maxShards };
        let optionss = Object.keys(options);
        optionss.forEach(key => {
            delete clientOptions[key];
        });

        Object.assign(options, clientOptions);

        const bot = new Eris(token, options);
        this.bot = bot;

        bot.on("connect", id => {
            process.send({ name: "log", msg: `Shard ${id} established connection!` });
        });

        bot.on("shardDisconnect", (err, id) => {
            process.send({ name: "log", msg: `Shard ${id} disconnected!` });
            let embed = {
                title: "Shard Status Update",
                description: `Shard ${id} disconnected!`
            }
            process.send({ name: "shard", embed: embed });
        });

        bot.on("shardReady", id => {
            process.send({ name: "log", msg: `Shard ${id} is ready!` });
            let embed = {
                title: "Shard Status Update",
                description: `Shard ${id} is ready!`
            }
            process.send({ name: "shard", embed: embed });
        });

        bot.on("shardResume", id => {
            process.send({ name: "log", msg: `Shard ${id} has resumed!` });
            let embed = {
                title: "Shard Status Update",
                description: `Shard ${id} resumed!`
            }
            process.send({ name: "shard", embed: embed });
        });

        bot.on("warn", (message, id) => {
            process.send({ name: "warn", msg: `Shard ${id} | ${message}` });
        });

        bot.on("error", (error, id) => {
            process.send({ name: "error", msg: `Shard ${id} | ${error.stack}` });
        });

        bot.once("ready", id => {
            this.loadCode(bot);

            this.startStats(bot);
        });

        bot.on("ready", id => {
            process.send({ name: "log", msg: `Shards ${this.firstShardID} - ${this.lastShardID} are ready!` });
            let embed = {
                title: `Cluster ${this.clusterID} is ready!`,
                description: `Shards ${this.firstShardID} - ${this.lastShardID}`
            }
            process.send({ name: "cluster", embed: embed });

            process.send({ name: "shardsStarted" });
        });

        if (!this.test) {
            bot.connect();
        } else {
            process.send({ name: "shardsStarted" });
            this.loadCode(bot);
        }
    }

    loadCode(bot) {
        let rootPath = process.cwd();
        rootPath = rootPath.replace(`\\`, "/");

        let path = `${rootPath}${this.mainFile}`;
        let app = require(path);
        if (app.prototype instanceof Base) {
            this.app = new app({ bot: bot, clusterID: this.clusterID });
            this.app.launch();
            this.ipc = this.app.ipc;
        } else {
            console.error("Your code has not been loaded! This is due to it not extending the Base class. Please extend the Base class!");
        }
    }

    startStats(bot) {
        setInterval(() => {
            this.guilds = bot.guilds.size;
            this.users = bot.users.size;
            this.uptime = bot.uptime;
            this.voiceChannels = bot.voiceConnections.size;
            this.largeGuilds = bot.guilds.filter(g => g.large).length;
            this.exclusiveGuilds = bot.guilds.filter(g => g.members.filter(m => m.bot).length === 1).length;
            this.shardsStats = [];
            this.bot.shards.forEach(shard => {
                this.shardsStats.push({
                    id: shard.id,
                    ready: shard.ready,
                    latency: shard.latency,
                    status: shard.status
                });
            });
        }, 1000 * 5);
    }
}

module.exports = Cluster;
<commit_msg>Hack in support for eris-additions<commit_after>let Eris;

try {
    Eris = require("eris-additions")(require("eris"));
} catch (err) {
    Eris = require("eris");
}

const Base = require("../structures/Base.js");
const { inspect } = require('util');

/**
 *
 *
 * @class Cluster
 */
class Cluster {

    /**
     * Creates an instance of Cluster.
     * @param {any} clusterID
     * @memberof Cluster
     */
    constructor() {

        this.shards = 0;
        this.maxShards = 0;
        this.firstShardID = 0;
        this.lastShardID = 0;
        this.mainFile = null;
        this.clusterID = 0;
        this.clusterCount = 0;
        this.guilds = 0;
        this.users = 0;
        this.uptime = 0;
        this.exclusiveGuilds = 0;
        this.largeGuilds = 0;
        this.voiceChannels = 0;
        this.shardsStats = [];
        this.app = null;
        this.bot = null;
        this.test = false;

        console.log = (str) => process.send({ name: "log", msg: this.logOverride(str) });
        console.error = (str) => process.send({ name: "error", msg: this.logOverride(str) });
        console.warn = (str) => process.send({ name: "warn", msg: this.logOverride(str) });
        console.info = (str) => process.send({ name: "info", msg: this.logOverride(str) });
        console.debug = (str) => process.send({ name: "debug", msg: this.logOverride(str) });

    }

    logOverride(message) {
        if (typeof message == 'object') return inspect(message);
        else return message;
    }

    spawn() {
        process.on('uncaughtException', (err) => {
            process.send({ name: "error", msg: err.stack });
        });

        process.on('unhandledRejection', (reason, p) => {
            process.send({ name: "error", msg: `Unhandled rejection at: Promise  ${p} reason:  ${reason.stack}` });
        });

        process.on("message", msg => {
            if (msg.name) {
                switch (msg.name) {
                    case "connect": {
                        this.firstShardID = msg.firstShardID;
                        this.lastShardID = msg.lastShardID;
                        this.mainFile = msg.file;
                        this.clusterID = msg.id;
                        this.clusterCount = msg.clusterCount;
                        this.shards = (this.lastShardID - this.firstShardID) + 1;
                        this.maxShards = msg.maxShards;

                        if (this.shards < 1) return;

                        if (msg.test) {
                            this.test = true;
                        }

                        this.connect(msg.firstShardID, msg.lastShardID, this.maxShards, msg.token, "connect", msg.clientOptions);

                        break;
                    }
                    case "stats": {
                        process.send({
                            name: "stats", stats: {
                                guilds: this.guilds,
                                users: this.users,
                                uptime: this.uptime,
                                ram: process.memoryUsage().rss,
                                shards: this.shards,
                                exclusiveGuilds: this.exclusiveGuilds,
                                largeGuilds: this.largeGuilds,
                                voice: this.voiceChannels,
                                shardsStats: this.shardsStats
                            }
                        });

                        break;
                    }
                    case "fetchUser": {
                        if (!this.bot) return;
                        let id = msg.value;
                        let user = this.bot.users.get(id);
                        if (user) {
                            process.send({ name: "fetchReturn", value: user });
                        }

                        break;
                    }
                    case "fetchChannel": {
                        if (!this.bot) return;
                        let id = msg.value;
                        let channel = this.bot.getChannel(id);
                        if (channel) {
                            channel = channel.toJSON();
                            return process.send({ name: "fetchReturn", value: channel });
                        }

                        break;
                    }
                    case "fetchGuild": {
                        if (!this.bot) return;
                        let id = msg.value;
                        let guild = this.bot.guilds.get(id);
                        if (guild) {
                            guild = guild.toJSON();
                            process.send({ name: "fetchReturn", value: guild });
                        }

                        break;
                    }
                    case "fetchMember": {
                        if (!this.bot) return;
                        let [guildID, memberID] = msg.value;

                        let guild = this.bot.guilds.get(guildID);

                        if (guild) {
                            let member = guild.members.get(memberID);

                            if (member) {
                                member = member.toJSON();
                                process.send({ name: "fetchReturn", value: member });
                            }
                        }

                        break;
                    }
                    case "fetchReturn":
                        this.ipc.emit(msg.id, msg.value);
                        break;
                    case "restart":
                        process.exit(1);
                        break;
                }
            }
        });
    }

    /**
     *
     *
     * @param {any} firstShardID
     * @param {any} lastShardID
     * @param {any} maxShards
     * @param {any} token
     * @param {any} type
     * @memberof Cluster
     */
    connect(firstShardID, lastShardID, maxShards, token, type, clientOptions) {
        process.send({ name: "log", msg: `Connecting with ${this.shards} shard(s)` });

        let options = { autoreconnect: true, firstShardID: firstShardID, lastShardID: lastShardID, maxShards: maxShards };
        let optionss = Object.keys(options);
        optionss.forEach(key => {
            delete clientOptions[key];
        });

        Object.assign(options, clientOptions);

        const bot = new Eris(token, options);
        this.bot = bot;

        bot.on("connect", id => {
            process.send({ name: "log", msg: `Shard ${id} established connection!` });
        });

        bot.on("shardDisconnect", (err, id) => {
            process.send({ name: "log", msg: `Shard ${id} disconnected!` });
            let embed = {
                title: "Shard Status Update",
                description: `Shard ${id} disconnected!`
            }
            process.send({ name: "shard", embed: embed });
        });

        bot.on("shardReady", id => {
            process.send({ name: "log", msg: `Shard ${id} is ready!` });
            let embed = {
                title: "Shard Status Update",
                description: `Shard ${id} is ready!`
            }
            process.send({ name: "shard", embed: embed });
        });

        bot.on("shardResume", id => {
            process.send({ name: "log", msg: `Shard ${id} has resumed!` });
            let embed = {
                title: "Shard Status Update",
                description: `Shard ${id} resumed!`
            }
            process.send({ name: "shard", embed: embed });
        });

        bot.on("warn", (message, id) => {
            process.send({ name: "warn", msg: `Shard ${id} | ${message}` });
        });

        bot.on("error", (error, id) => {
            process.send({ name: "error", msg: `Shard ${id} | ${error.stack}` });
        });

        bot.once("ready", id => {
            this.loadCode(bot);

            this.startStats(bot);
        });

        bot.on("ready", id => {
            process.send({ name: "log", msg: `Shards ${this.firstShardID} - ${this.lastShardID} are ready!` });
            let embed = {
                title: `Cluster ${this.clusterID} is ready!`,
                description: `Shards ${this.firstShardID} - ${this.lastShardID}`
            }
            process.send({ name: "cluster", embed: embed });

            process.send({ name: "shardsStarted" });
        });

        if (!this.test) {
            bot.connect();
        } else {
            process.send({ name: "shardsStarted" });
            this.loadCode(bot);
        }
    }

    loadCode(bot) {
        let rootPath = process.cwd();
        rootPath = rootPath.replace(`\\`, "/");

        let path = `${rootPath}${this.mainFile}`;
        let app = require(path);
        if (app.prototype instanceof Base) {
            this.app = new app({ bot: bot, clusterID: this.clusterID });
            this.app.launch();
            this.ipc = this.app.ipc;
        } else {
            console.error("Your code has not been loaded! This is due to it not extending the Base class. Please extend the Base class!");
        }
    }

    startStats(bot) {
        setInterval(() => {
            this.guilds = bot.guilds.size;
            this.users = bot.users.size;
            this.uptime = bot.uptime;
            this.voiceChannels = bot.voiceConnections.size;
            this.largeGuilds = bot.guilds.filter(g => g.large).length;
            this.exclusiveGuilds = bot.guilds.filter(g => g.members.filter(m => m.bot).length === 1).length;
            this.shardsStats = [];
            this.bot.shards.forEach(shard => {
                this.shardsStats.push({
                    id: shard.id,
                    ready: shard.ready,
                    latency: shard.latency,
                    status: shard.status
                });
            });
        }, 1000 * 5);
    }
}

module.exports = Cluster;
<|endoftext|>


<commit_before>/*
	Simple jQuery Slider is just what is says it is: a simple but powerfull jQuery slider.
	Copyright (C) 2013 - Dirk Groenen [Bitlabs Development]

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
function simpleSlider(e){function i(){clearInterval(n);n=setInterval(function(){t.nextSlide()},r.interval)}var t=this,n;t.currentSlide=0;t.totalSlides=0;e=e==undefined?{}:e;var r=$.extend({slidesContainer:".slider",slides:".slide",swipe:false,slideTracker:true,slideTrackerID:"slideposition",slideOnInterval:true,interval:5e3,swipe:true,animateDuration:1e3,animationEasing:"ease"},e);t.init=function(){$(r.slidesContainer).find(r.slides).each(function(e){$(this).attr("data-index",e);$(this).css({x:e*100+"%"})});t.totalSlides=$(r.slidesContainer).find(r.slides).length;if(r.slideTracker){$(r.slidesContainer).append("

");for(var e=0;e<t.totalSlides;e++){$(r.slidesContainer).find("#"+r.slideTrackerID+" ul").append('

')}$(r.slidesContainer).find("#"+r.slideTrackerID+' ul li[data-index="'+t.currentSlide+'"]').addClass("active");$(r.slidesContainer).find("#"+r.slideTrackerID+" ul li").click(function(){t.nextSlide($(this).data("index"))})}if(r.slideOnInterval){i()}if(r.swipe){$(r.slidesContainer).css("cursor","-webkit-grab");$(r.slidesContainer).css("cursor","-moz-grab");$(r.slidesContainer).css("cursor","grab");$(r.slidesContainer).mousedown(function(){$(r.slidesContainer).css("cursor","-webkit-grabbing");$(r.slidesContainer).css("cursor","-moz-grabbing");$(r.slidesContainer).css("cursor","grabbing")});$(r.slidesContainer).mouseup(function(){$(r.slidesContainer).css("cursor","-webkit-grab");$(r.slidesContainer).css("cursor","-moz-grab");$(r.slidesContainer).css("cursor","grab")});$(r.slidesContainer+" "+r.slides).swipe({swipeLeft:function(e,n,r,i,s){t.nextSlide()},swipeRight:function(e,n,r,i,s){t.prevSlide()}})}};t.prevSlide=function(){var e=t.currentSlide>0?t.currentSlide-=1:t.totalSlides-1;t.nextSlide(e)};t.nextSlide=function(e){if(e==undefined){t.currentSlide=t.currentSlide<t.totalSlides-1?t.currentSlide+=1:0}else{t.currentSlide=e}$(r.slidesContainer).find(r.slides).each(function(e){if($.support.transition)$(this).transition({x:($(this).data("index")-t.currentSlide)*100+"%"},r.animateDuration,r.animationEasing);else $(this).animate({left:($(this).data("index")-t.currentSlide)*100+"%"},r.animateDuration)});$(r.slidesContainer).find("#"+r.slideTrackerID+" ul li").removeClass("active");$(r.slidesContainer).find("#"+r.slideTrackerID+' ul li[data-index="'+t.currentSlide+'"]').addClass("active");if(r.slideOnInterval){i()}}}<commit_msg>Remove license from minified version<commit_after>function simpleSlider(e){function i(){clearInterval(n);n=setInterval(function(){t.nextSlide()},r.interval)}var t=this,n;t.currentSlide=0;t.totalSlides=0;e=e==undefined?{}:e;var r=$.extend({slidesContainer:".slider",slides:".slide",swipe:false,slideTracker:true,slideTrackerID:"slideposition",slideOnInterval:true,interval:5e3,swipe:true,animateDuration:1e3,animationEasing:"ease"},e);t.init=function(){$(r.slidesContainer).find(r.slides).each(function(e){$(this).attr("data-index",e);$(this).css({x:e*100+"%"})});t.totalSlides=$(r.slidesContainer).find(r.slides).length;if(r.slideTracker){$(r.slidesContainer).append("

");for(var e=0;e<t.totalSlides;e++){$(r.slidesContainer).find("#"+r.slideTrackerID+" ul").append('

')}$(r.slidesContainer).find("#"+r.slideTrackerID+' ul li[data-index="'+t.currentSlide+'"]').addClass("active");$(r.slidesContainer).find("#"+r.slideTrackerID+" ul li").click(function(){t.nextSlide($(this).data("index"))})}if(r.slideOnInterval){i()}if(r.swipe){$(r.slidesContainer).css("cursor","-webkit-grab");$(r.slidesContainer).css("cursor","-moz-grab");$(r.slidesContainer).css("cursor","grab");$(r.slidesContainer).mousedown(function(){$(r.slidesContainer).css("cursor","-webkit-grabbing");$(r.slidesContainer).css("cursor","-moz-grabbing");$(r.slidesContainer).css("cursor","grabbing")});$(r.slidesContainer).mouseup(function(){$(r.slidesContainer).css("cursor","-webkit-grab");$(r.slidesContainer).css("cursor","-moz-grab");$(r.slidesContainer).css("cursor","grab")});$(r.slidesContainer+" "+r.slides).swipe({swipeLeft:function(e,n,r,i,s){t.nextSlide()},swipeRight:function(e,n,r,i,s){t.prevSlide()}})}};t.prevSlide=function(){var e=t.currentSlide>0?t.currentSlide-=1:t.totalSlides-1;t.nextSlide(e)};t.nextSlide=function(e){if(e==undefined){t.currentSlide=t.currentSlide<t.totalSlides-1?t.currentSlide+=1:0}else{t.currentSlide=e}$(r.slidesContainer).find(r.slides).each(function(e){if($.support.transition)$(this).transition({x:($(this).data("index")-t.currentSlide)*100+"%"},r.animateDuration,r.animationEasing);else $(this).animate({left:($(this).data("index")-t.currentSlide)*100+"%"},r.animateDuration)});$(r.slidesContainer).find("#"+r.slideTrackerID+" ul li").removeClass("active");$(r.slidesContainer).find("#"+r.slideTrackerID+' ul li[data-index="'+t.currentSlide+'"]').addClass("active");if(r.slideOnInterval){i()}}}<|endoftext|>


<commit_before>define([
	"dojo/_base/array", // array.forEach
	"dojo/_base/declare", // declare
	"dojo/has", // has("dom-addeventlistener")
	"dojo/keys", // keys.ENTER keys.SPACE
	"dojo/on"
], function(array, declare, has, keys, on){

	// module:
	//		dijit/a11yclick

	// Keep track of where the last keydown event was, to help avoid generating
	// spurious ondijitclick events when:
	// 1. focus is on a <button> or <a>
	// 2. user presses then releases the ENTER key
	// 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
	// 4. onkeyup event fires, causing the ondijitclick handler to fire
	var lastKeyDownNode = null;
	if(has("dom-addeventlistener")){
		document.addEventListener('keydown', function(evt){
			lastKeyDownNode = evt.target;
		}, true);
	}else{
		// Fallback path for IE6-8
		(function(){
			var keydownCallback = function(evt){
				lastKeyDownNode = evt.srcElement;
			};
			document.attachEvent('onkeydown', keydownCallback);
			on(window, "unload", function(){
				document.detachEvent('onkeydown', keydownCallback);
			});
		})();
	}

	function clickKey(/*Event*/ e){
		return (e.keyCode === keys.ENTER || e.keyCode === keys.SPACE) &&
			!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey;
	}

	return function(node, listener){
		// summary:
		//		Custom a11yclick (a.k.a. ondijitclick) event
		//		which triggers on a mouse click, touch, or space/enter keyup.

		if(/input|button/i.test(node.nodeName)){
			// pass through, the browser already generates click event on SPACE/ENTER key
			return on(node, "click", listener);
		}else{
			// Don't fire the click event unless both the keydown and keyup occur on this node.
			// Avoids problems where focus shifted to this node or away from the node on keydown,
			// either causing this node to process a stray keyup event, or causing another node
			// to get a stray keyup event.

			var handles = [
				on(node, "keydown", function(e){
					//console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
					if(clickKey(e)){
						// needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
						lastKeyDownNode = e.target;

						// Prevent viewport scrolling on space key in IE<9.
						// (Reproducible on test_Button.html on any of the first dijit/form/Button examples)
						e.preventDefault();
					}
				}),

				on(node, "keyup", function(e){
					//console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
					if(clickKey(e) && e.target == lastKeyDownNode){	// === breaks greasemonkey
						//need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
						lastKeyDownNode = null;
						on.emit(e.target, "click", {
							cancelable: true,
							bubbles: true
						});
					}
				}),

				on(node, "click", function(e){
					// catch mouse clicks, plus the on.emit() calls from above and below
					listener.call(this, e);
				})
			];

			if(has("touch")){
				// touchstart-->touchend will automatically generate a click event, but there are problems
				// on iOS after focus has been programatically shifted (#14604, #14918), so setup a failsafe
				// if click doesn't fire naturally.

				var clickTimer;
				handles.push(
					on(node, "touchend", function(e){
						var target = e.target;
						clickTimer = setTimeout(function(){
							clickTimer = null;
							on.emit(target, "click", {
								cancelable: true,
								bubbles: true
							});
						}, 600);
					}),
					on(node, "click", function(e){
						// If browser generates a click naturally, clear the timer to fire a synthetic click event
						if(clickTimer){
							clearTimeout(clickTimer);
						}
					})
					// TODO: if the touchstart and touchend were <100ms apart, and then there's another touchstart
					// event <300ms after the touchend event, then clear the synthetic click timer, because user
					// is doing a zoom.   Alternately monitor screen.deviceXDPI (or something similar) to see if
					// zoom level has changed.
				);
			}

			return {
				remove: function(){
					array.forEach(handles, function(h){ h.remove(); });
					if(clickTimer){
						clearTimeout(clickTimer);
						clickTimer = null;
					}
				}
			};
		}
	};
});
<commit_msg>for performance, use event delegation in a11yclick, fixes #16782 !strict<commit_after>define([
	"dojo/_base/array", // array.forEach
	"dojo/_base/declare", // declare
	"dojo/has", // has("dom-addeventlistener")
	"dojo/keys", // keys.ENTER keys.SPACE
	"dojo/on"
], function(array, declare, has, keys, on){

	// module:
	//		dijit/a11yclick

	function marked(/*DOMNode*/ node){
		// Test if a node or its ancestor has been marked with the dojoClick property to indicate special processing
		do{
			if(node.dojoClick){ return true; }
		}while(node = node.parentNode);
	}

	function clickKey(/*Event*/ e){
		// Test if this keyboard event should be tracked as the start (if keyup) or end (if keydown) of a click event.
		// Only track for nodes marked to be tracked, and not for buttons or inputs since they handle keyboard click
		// natively.
		return (e.keyCode === keys.ENTER || e.keyCode === keys.SPACE) &&
			!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey && !/input|button/i.test(e.target.nodeName) &&
			marked(e.target);
	}

	var lastKeyDownNode;

	on(document, "keydown", function(e){
		//console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
		if(clickKey(e)){
			// needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
			lastKeyDownNode = e.target;

			// Prevent viewport scrolling on space key in IE<9.
			// (Reproducible on test_Button.html on any of the first dijit/form/Button examples)
			e.preventDefault();
		}
	});

	on(document, "keyup", function(e){
		//console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode));
		if(clickKey(e) && e.target == lastKeyDownNode){	// === breaks greasemonkey
			//need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
			lastKeyDownNode = null;

			on.emit(e.target, "click", {
				cancelable: true,
				bubbles: true
			});
		}
	});

	if(has("touch")){
		// touchstart-->touchend will automatically generate a click event, but there are problems
		// on iOS after focus has been programatically shifted (#14604, #14918), so setup a failsafe
		// if click doesn't fire naturally.

		var clickTimer;

		on(document, "touchend", function(e){
			var target = e.target;
			if(marked(target)){
				var naturalClickListener = on.once(target, "click", function(e){
					// If browser generates a click naturally, clear the timer to fire a synthetic click event
					if(clickTimer){
						clearTimeout(clickTimer);
						clickTimer = null;
					}
				});

				if(clickTimer){
					clearTimeout(clickTimer);
				}
				clickTimer = setTimeout(function(){
					clickTimer = null;
					naturalClickListener.remove();
					on.emit(target, "click", {
						cancelable: true,
						bubbles: true
					});
				}, 600);
			}
		});

		// TODO: if the touchstart and touchend were <100ms apart, and then there's another touchstart
		// event <300ms after the touchend event, then clear the synthetic click timer, because user
		// is doing a zoom.   Alternately monitor screen.deviceXDPI (or something similar) to see if
		// zoom level has changed.
	}

	return function(node, listener){
		// summary:
		//		Custom a11yclick (a.k.a. ondijitclick) event
		//		which triggers on a mouse click, touch, or space/enter keyup.

		node.dojoClick = true;

		return on(node, "click", listener);
	};
});
<|endoftext|>


<commit_before>/**
 * CaretPosition.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * This module contains logic for creating caret positions within a document a caretposition
 * is similar to a DOMRange object but it doesn't have two endpoints and is also more lightweight
 * since it's now updated live when the DOM changes.
 *
 * @private
 * @class tinymce.caret.CaretPosition
 * @example
 * var caretPos1 = new CaretPosition(container, offset);
 * var caretPos2 = CaretPosition.fromRangeStart(someRange);
 */
define("tinymce/caret/CaretPosition", [
	"tinymce/util/Fun",
	"tinymce/dom/NodeType",
	"tinymce/dom/DOMUtils",
	"tinymce/dom/RangeUtils",
	"tinymce/caret/CaretCandidate",
	"tinymce/geom/ClientRect",
	"tinymce/text/ExtendingChar"
], function(Fun, NodeType, DOMUtils, RangeUtils, CaretCandidate, ClientRect, ExtendingChar) {
	var isElement = NodeType.isElement,
		isCaretCandidate = CaretCandidate.isCaretCandidate,
		isBlock = NodeType.matchStyleValues('display', 'block table'),
		isFloated = NodeType.matchStyleValues('float', 'left right'),
		isValidElementCaretCandidate = Fun.and(isElement, isCaretCandidate, Fun.negate(isFloated)),
		isNotPre = Fun.negate(NodeType.matchStyleValues('white-space', 'pre pre-line pre-wrap')),
		isText = NodeType.isText,
		isBr = NodeType.isBr,
		nodeIndex = DOMUtils.nodeIndex,
		resolveIndex = RangeUtils.getNode;

	function isWhiteSpace(chr) {
		return chr && /[\r\n\t ]/.test(chr);
	}

	function isHiddenWhiteSpaceRange(range) {
		var container = range.startContainer,
			offset = range.startOffset,
			text;

		if (isWhiteSpace(range.toString()) && isNotPre(container.parentNode)) {
			text = container.data;

			if (isWhiteSpace(text[offset - 1]) || isWhiteSpace(text[offset + 1])) {
				return true;
			}
		}

		return false;
	}

	function getCaretPositionClientRects(caretPosition) {
		var clientRects = [], beforeNode, node;

		// Hack for older WebKit versions that doesn't
		// support getBoundingClientRect on BR elements
		function getBrClientRect(brNode) {
			var doc = brNode.ownerDocument,
				rng = doc.createRange(),
				nbsp = doc.createTextNode('\u00a0'),
				parentNode = brNode.parentNode,
				clientRect;

			parentNode.insertBefore(nbsp, brNode);
			rng.setStart(nbsp, 0);
			rng.setEnd(nbsp, 1);
			clientRect = ClientRect.clone(rng.getBoundingClientRect());
			parentNode.removeChild(nbsp);

			return clientRect;
		}

		function getBoundingClientRect(item) {
			var clientRect = ClientRect.clone(item.getBoundingClientRect());

			if (isBr(item) && clientRect.left === 0) {
				return getBrClientRect(item);
			}

			return clientRect;
		}

		function collapseAndInflateWidth(clientRect, toStart) {
			clientRect = ClientRect.collapse(clientRect, toStart);
			clientRect.width = 1;
			clientRect.right = clientRect.left + 1;

			return clientRect;
		}

		function addUniqueAndValidRect(clientRect) {
			if (clientRect.height === 0) {
				return;
			}

			if (clientRects.length > 0) {
				if (ClientRect.isEqual(clientRect, clientRects[clientRects.length - 1])) {
					return;
				}
			}

			clientRects.push(clientRect);
		}

		function addCharacterOffset(container, offset) {
			var range = container.ownerDocument.createRange();

			if (offset < container.data.length) {
				if (ExtendingChar.isExtendingChar(container.data[offset])) {
					return clientRects;
				}
			}

			if (offset > 0) {
				range.setStart(container, offset - 1);
				range.setEnd(container, offset);

				if (!isHiddenWhiteSpaceRange(range)) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(range), false));
				}
			}

			if (offset < container.data.length) {
				range.setStart(container, offset);
				range.setEnd(container, offset + 1);

				if (!isHiddenWhiteSpaceRange(range)) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(range), true));
				}
			}
		}

		if (isText(caretPosition.container())) {
			addCharacterOffset(caretPosition.container(), caretPosition.offset());
			return clientRects;
		}

		if (isElement(caretPosition.container())) {
			if (caretPosition.isAtEnd()) {
				node = resolveIndex(caretPosition.container(), caretPosition.offset());
				if (isText(node)) {
					addCharacterOffset(node, node.data.length);
				}

				if (isValidElementCaretCandidate(node) && !isBr(node)) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(node), false));
				}
			} else {
				node = resolveIndex(caretPosition.container(), caretPosition.offset());
				if (isText(node)) {
					addCharacterOffset(node, 0);
				}

				if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(node), false));
					return clientRects;
				}

				beforeNode = resolveIndex(caretPosition.container(), caretPosition.offset() - 1);
				if (isValidElementCaretCandidate(beforeNode) && !isBr(beforeNode)) {
					if (isBlock(beforeNode) || isBlock(node) || !isValidElementCaretCandidate(node)) {
						addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(beforeNode), false));
					}
				}

				if (isValidElementCaretCandidate(node)) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(node), true));
				}
			}
		}

		return clientRects;
	}

	function CaretPosition(container, offset, clientRects) {
		function isAtStart() {
			if (isText(container)) {
				return offset === 0;
			}

			return offset === 0;
		}

		function isAtEnd() {
			if (isText(container)) {
				return offset >= container.data.length;
			}

			return offset >= container.childNodes.length;
		}

		function toRange() {
			var range;

			range = container.ownerDocument.createRange();
			range.setStart(container, offset);
			range.setEnd(container, offset);

			return range;
		}

		function getClientRects() {
			if (!clientRects) {
				clientRects = getCaretPositionClientRects(new CaretPosition(container, offset));
			}

			return clientRects;
		}

		function isVisible() {
			return getClientRects().length > 0;
		}

		function isEqual(caretPosition) {
			return caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
		}

		function getNode(before) {
			return resolveIndex(container, before ? offset - 1 : offset);
		}

		return {
			container: Fun.constant(container),
			offset: Fun.constant(offset),
			isAtStart: isAtStart,
			isAtEnd: isAtEnd,
			toRange: toRange,
			getClientRects: getClientRects,
			isVisible: isVisible,
			isEqual: isEqual,
			getNode: getNode
		};
	}

	CaretPosition.fromRangeStart = function(range) {
		return new CaretPosition(range.startContainer, range.startOffset);
	};

	CaretPosition.fromRangeEnd = function(range) {
		return new CaretPosition(range.endContainer, range.endOffset);
	};

	CaretPosition.after = function(node) {
		return new CaretPosition(node.parentNode, nodeIndex(node) + 1);
	};

	CaretPosition.before = function(node) {
		return new CaretPosition(node.parentNode, nodeIndex(node));
	};

	return CaretPosition;
});<commit_msg>Fixed bug on IE where wrapping text breaks would produce an incorrect value.<commit_after>/**
 * CaretPosition.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * This module contains logic for creating caret positions within a document a caretposition
 * is similar to a DOMRange object but it doesn't have two endpoints and is also more lightweight
 * since it's now updated live when the DOM changes.
 *
 * @private
 * @class tinymce.caret.CaretPosition
 * @example
 * var caretPos1 = new CaretPosition(container, offset);
 * var caretPos2 = CaretPosition.fromRangeStart(someRange);
 */
define("tinymce/caret/CaretPosition", [
	"tinymce/util/Fun",
	"tinymce/dom/NodeType",
	"tinymce/dom/DOMUtils",
	"tinymce/dom/RangeUtils",
	"tinymce/caret/CaretCandidate",
	"tinymce/geom/ClientRect",
	"tinymce/text/ExtendingChar"
], function(Fun, NodeType, DOMUtils, RangeUtils, CaretCandidate, ClientRect, ExtendingChar) {
	var isElement = NodeType.isElement,
		isCaretCandidate = CaretCandidate.isCaretCandidate,
		isBlock = NodeType.matchStyleValues('display', 'block table'),
		isFloated = NodeType.matchStyleValues('float', 'left right'),
		isValidElementCaretCandidate = Fun.and(isElement, isCaretCandidate, Fun.negate(isFloated)),
		isNotPre = Fun.negate(NodeType.matchStyleValues('white-space', 'pre pre-line pre-wrap')),
		isText = NodeType.isText,
		isBr = NodeType.isBr,
		nodeIndex = DOMUtils.nodeIndex,
		resolveIndex = RangeUtils.getNode;

	function isWhiteSpace(chr) {
		return chr && /[\r\n\t ]/.test(chr);
	}

	function isHiddenWhiteSpaceRange(range) {
		var container = range.startContainer,
			offset = range.startOffset,
			text;

		if (isWhiteSpace(range.toString()) && isNotPre(container.parentNode)) {
			text = container.data;

			if (isWhiteSpace(text[offset - 1]) || isWhiteSpace(text[offset + 1])) {
				return true;
			}
		}

		return false;
	}

	function getCaretPositionClientRects(caretPosition) {
		var clientRects = [], beforeNode, node;

		// Hack for older WebKit versions that doesn't
		// support getBoundingClientRect on BR elements
		function getBrClientRect(brNode) {
			var doc = brNode.ownerDocument,
				rng = doc.createRange(),
				nbsp = doc.createTextNode('\u00a0'),
				parentNode = brNode.parentNode,
				clientRect;

			parentNode.insertBefore(nbsp, brNode);
			rng.setStart(nbsp, 0);
			rng.setEnd(nbsp, 1);
			clientRect = ClientRect.clone(rng.getBoundingClientRect());
			parentNode.removeChild(nbsp);

			return clientRect;
		}

		function getBoundingClientRect(item) {
			var clientRect, clientRects;

			clientRects = item.getClientRects();
			if (clientRects.length > 0) {
				clientRect = ClientRect.clone(clientRects[0]);
			} else {
				clientRect = ClientRect.clone(item.getBoundingClientRect());
			}

			if (isBr(item) && clientRect.left === 0) {
				return getBrClientRect(item);
			}

			return clientRect;
		}

		function collapseAndInflateWidth(clientRect, toStart) {
			clientRect = ClientRect.collapse(clientRect, toStart);
			clientRect.width = 1;
			clientRect.right = clientRect.left + 1;

			return clientRect;
		}

		function addUniqueAndValidRect(clientRect) {
			if (clientRect.height === 0) {
				return;
			}

			if (clientRects.length > 0) {
				if (ClientRect.isEqual(clientRect, clientRects[clientRects.length - 1])) {
					return;
				}
			}

			clientRects.push(clientRect);
		}

		function addCharacterOffset(container, offset) {
			var range = container.ownerDocument.createRange();

			if (offset < container.data.length) {
				if (ExtendingChar.isExtendingChar(container.data[offset])) {
					return clientRects;
				}
			}

			if (offset > 0) {
				range.setStart(container, offset - 1);
				range.setEnd(container, offset);

				if (!isHiddenWhiteSpaceRange(range)) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(range), false));
				}
			}

			if (offset < container.data.length) {
				range.setStart(container, offset);
				range.setEnd(container, offset + 1);

				if (!isHiddenWhiteSpaceRange(range)) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(range), true));
				}
			}
		}

		if (isText(caretPosition.container())) {
			addCharacterOffset(caretPosition.container(), caretPosition.offset());
			return clientRects;
		}

		if (isElement(caretPosition.container())) {
			if (caretPosition.isAtEnd()) {
				node = resolveIndex(caretPosition.container(), caretPosition.offset());
				if (isText(node)) {
					addCharacterOffset(node, node.data.length);
				}

				if (isValidElementCaretCandidate(node) && !isBr(node)) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(node), false));
				}
			} else {
				node = resolveIndex(caretPosition.container(), caretPosition.offset());
				if (isText(node)) {
					addCharacterOffset(node, 0);
				}

				if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(node), false));
					return clientRects;
				}

				beforeNode = resolveIndex(caretPosition.container(), caretPosition.offset() - 1);
				if (isValidElementCaretCandidate(beforeNode) && !isBr(beforeNode)) {
					if (isBlock(beforeNode) || isBlock(node) || !isValidElementCaretCandidate(node)) {
						addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(beforeNode), false));
					}
				}

				if (isValidElementCaretCandidate(node)) {
					addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(node), true));
				}
			}
		}

		return clientRects;
	}

	function CaretPosition(container, offset, clientRects) {
		function isAtStart() {
			if (isText(container)) {
				return offset === 0;
			}

			return offset === 0;
		}

		function isAtEnd() {
			if (isText(container)) {
				return offset >= container.data.length;
			}

			return offset >= container.childNodes.length;
		}

		function toRange() {
			var range;

			range = container.ownerDocument.createRange();
			range.setStart(container, offset);
			range.setEnd(container, offset);

			return range;
		}

		function getClientRects() {
			if (!clientRects) {
				clientRects = getCaretPositionClientRects(new CaretPosition(container, offset));
			}

			return clientRects;
		}

		function isVisible() {
			return getClientRects().length > 0;
		}

		function isEqual(caretPosition) {
			return caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
		}

		function getNode(before) {
			return resolveIndex(container, before ? offset - 1 : offset);
		}

		return {
			container: Fun.constant(container),
			offset: Fun.constant(offset),
			isAtStart: isAtStart,
			isAtEnd: isAtEnd,
			toRange: toRange,
			getClientRects: getClientRects,
			isVisible: isVisible,
			isEqual: isEqual,
			getNode: getNode
		};
	}

	CaretPosition.fromRangeStart = function(range) {
		return new CaretPosition(range.startContainer, range.startOffset);
	};

	CaretPosition.fromRangeEnd = function(range) {
		return new CaretPosition(range.endContainer, range.endOffset);
	};

	CaretPosition.after = function(node) {
		return new CaretPosition(node.parentNode, nodeIndex(node) + 1);
	};

	CaretPosition.before = function(node) {
		return new CaretPosition(node.parentNode, nodeIndex(node));
	};

	return CaretPosition;
});<|endoftext|>


<commit_before>define(['vendor/lodash'], function(_) {
    var LineChart = function() {
        var CIRCLE_RADIUS = 4,
            CIRCLE_ANIMATE_RADIUS = 6,
            CIRCLE_EVENT_RADIUS = 12;
        var self = this,
            paper = null,
            core = null,
            lineCore = null,
            options = null,
            width = null,
            height = null,
            plotItemsCircle = [],
            plotItemsEventCircle = [],
            plotItemsLine = [],
            seriesGroups = [],
            eventManager;

        self.config = function(_options) {
            options = _options;
            eventManager = options.eventManager;
            if(eventManager) {
                eventManager.register('plotItemClick');
                eventManager.register('plotItemMouseOver');
                eventManager.register('plotItemMouseOut');
                eventManager.register('plotItemActivate');
            }
        };

        self.setEventManager = function (_eventManager) {
            eventManager = _eventManager;
        };

        self.renderTo = function(_paper, _core, w, h) {
            paper = _paper;
            core = _core;
            width = w;
            height = h;
            draw(true, true && options.animateOnRender);
            for(var i=-1; ++i<plotItemsCircle.length;) {
                options.tooltip.addSeriesItems(options.series[i].seriesIndex, plotItemsEventCircle[i]);
            }
        };

        self.resizeTo = function(w, h) {
            width = w;
            height = h;
            draw(false, false);
        };

        self.updateSeries = function(w, h) {
            width = w;
            height = h;
            draw(false, true);
        };

        var draw = function(create, animate) {
            var series = options.series,
                yScale = options.yScale,
                dataLength = _.max(_.pluck(_.pluck(series, 'data'), 'length')),
                seriesWidth = (width / dataLength);
            if(create) {
                lineCore = paper.group('rc-line-chart', core);
                lineCore.node.setAttribute('class', 'rc-line-chart');
            }
            for(var i=-1; ++i<series.length;) {
                var data = series[i].data,
                    classes = series[i].color === 'auto' ? ' rc-series-' + series[i].seriesIndex + ' rc-plot-item' : '';
                if(create) {
                    seriesGroups[i] = paper.group('line-series-' + (i+1), lineCore);
                    seriesGroups[i].node.setAttribute('class', 'rc-series-' + series[i].seriesIndex);
                    plotItemsCircle[i] = [];
                    plotItemsLine[i] = [];
                    plotItemsEventCircle[i] = [];
                }
                for(var j=-1; ++j<data.length;) {
                    var circle = null,
                        line = null,
                        eventCircle = null;
                    if(options.dualAxis) {
                        yScale = options.yScale[series[i].yAxis || 'left'];
                    }
                    if(j !== data.length - 1) {
                        if(create) {
                            line = plotItemsLine[i][j] = paper.path('M' + ((seriesWidth * j) + seriesWidth / 2) + ',' + height +
                                                        'L' +  ((seriesWidth * (j+1)) + seriesWidth / 2) + ',' + height, seriesGroups[i]);
                            line.node.setAttribute('class', (series[i].classed || '') + classes);
                            if(!classes) {
                                line.attr({
                                    stroke: series[i].color,
                                    fill: 'none'
                                });
                            }
                        } else {
                            line = plotItemsLine[i][j];
                        }
                        if(data[j] && data[j+1]) {
                            line.attr('opacity', 1);
                        } else {
                            line.attr('opacity', 0);
                        }
                        line.animate({
                            path: 'M' + ((seriesWidth * j) + seriesWidth / 2) + ',' + (height - yScale.calc(data[j])) +
                                                        'L' +  ((seriesWidth * (j+1)) + seriesWidth / 2) + ',' + (height - yScale.calc(data[j+1]))
                        }, animate ? 500 : 0);
                    }
                    if(create) {
                        circle = plotItemsCircle[i][j] = paper.circle((seriesWidth * j) + seriesWidth / 2, height, CIRCLE_RADIUS, seriesGroups[i]);
                        circle.node.setAttribute('class', (series[i].classed || '') + classes);
                        var params = {
                            seriesIndex: series[i].seriesIndex,
                            labelIndex: j,
                            value: data[j],
                            label: labels[j]
                        };
                        circle.click(createClickCallback(params));
                        circle.mouseover(createOverCallback(params, circle));
                        circle.mouseout(createOutCallback(params, circle));
                        if(!classes) {
                            circle.attr({
                                stroke: series[i].color,
                                fill: '#FFF'
                            });
                        }
                        eventCircle = plotItemsEventCircle[i][j] = paper.circle((seriesWidth * j) + seriesWidth / 2, height, CIRCLE_EVENT_RADIUS, seriesGroups[i]);
                        eventCircle.node.setAttribute('class', (series[i].classed || '') + ' rc-series-' + i + ' rc-plot-item' + ' ' + (options.plotItemClasses || ''));
                        eventCircle.attr({opacity: 0});
                        eventCircle.click(createClickCallback(params));
                        eventCircle.mouseover(createOverCallback(params, circle));
                        eventCircle.mouseout(createOutCallback(params, circle));
                        !function(circle) {
                            eventCircle.mouseover(function() {
                                circle.animate({
                                    r: CIRCLE_ANIMATE_RADIUS
                                }, 100);
                            });
                            eventCircle.mouseout(function() {
                                circle.animate({
                                    r: CIRCLE_RADIUS
                                }, 100);
                            });
                        }(circle);

                    } else {
                        circle = plotItemsCircle[i][j];
                        eventCircle = plotItemsEventCircle[i][j];
                    }
                    if(data[j]) {
                        circle.attr('opacity', 1);
                    } else {
                        circle.attr('opacity', 0);
                    }
                    circle.animate({
                        cx: (seriesWidth * j) + seriesWidth / 2,
                        cy: height - yScale.calc(data[j])
                    }, animate ? 500 : 0);

                    eventCircle.attr({
                        cx: (seriesWidth * j) + seriesWidth / 2,
                        cy: height - yScale.calc(data[j])
                    });
                }
            }
        };

        var createClickCallback = function (params) {
            return function() {
                eventManager.trigger('plotItemClick', params);
                eventManager.trigger('plotItemActivate', params);
            };
        };
        var createOverCallback = function (params, $el) {
            return function() {
                var attr = $el.node.getAttribute('class');
                $el.node.setAttribute('class', attr + ' highlight');
                eventManager.trigger('plotItemMouseOver', params);
            };
        };
        var createOutCallback = function (params, $el) {
            return function() {
                var attr = $el.node.getAttribute('class');
                attr = attr.replace(' highlight', '');
                $el.node.setAttribute('class', attr);
                eventManager.trigger('plotItemMouseOut', params);
            };
        };
    };

    return LineChart;
});<commit_msg>Don't assume 0 doesn't exist RF-81 #close Fixed<commit_after>define(['vendor/lodash'], function(_) {
    var LineChart = function() {
        var CIRCLE_RADIUS = 4,
            CIRCLE_ANIMATE_RADIUS = 6,
            CIRCLE_EVENT_RADIUS = 12;
        var self = this,
            paper = null,
            core = null,
            lineCore = null,
            options = null,
            width = null,
            height = null,
            plotItemsCircle = [],
            plotItemsEventCircle = [],
            plotItemsLine = [],
            seriesGroups = [],
            eventManager;

        self.config = function(_options) {
            options = _options;
            eventManager = options.eventManager;
            if(eventManager) {
                eventManager.register('plotItemClick');
                eventManager.register('plotItemMouseOver');
                eventManager.register('plotItemMouseOut');
                eventManager.register('plotItemActivate');
            }
        };

        self.setEventManager = function (_eventManager) {
            eventManager = _eventManager;
        };

        self.renderTo = function(_paper, _core, w, h) {
            paper = _paper;
            core = _core;
            width = w;
            height = h;
            draw(true, true && options.animateOnRender);
            for(var i=-1; ++i<plotItemsCircle.length;) {
                options.tooltip.addSeriesItems(options.series[i].seriesIndex, plotItemsEventCircle[i]);
            }
        };

        self.resizeTo = function(w, h) {
            width = w;
            height = h;
            draw(false, false);
        };

        self.updateSeries = function(w, h) {
            width = w;
            height = h;
            draw(false, true);
        };

        var draw = function(create, animate) {
            var series = options.series,
                yScale = options.yScale,
                dataLength = _.max(_.pluck(_.pluck(series, 'data'), 'length')),
                seriesWidth = (width / dataLength);
            if(create) {
                lineCore = paper.group('rc-line-chart', core);
                lineCore.node.setAttribute('class', 'rc-line-chart');
            }
            for(var i=-1; ++i<series.length;) {
                var data = series[i].data,
                    classes = series[i].color === 'auto' ? ' rc-series-' + series[i].seriesIndex + ' rc-plot-item' : '';
                if(create) {
                    seriesGroups[i] = paper.group('line-series-' + (i+1), lineCore);
                    seriesGroups[i].node.setAttribute('class', 'rc-series-' + series[i].seriesIndex);
                    plotItemsCircle[i] = [];
                    plotItemsLine[i] = [];
                    plotItemsEventCircle[i] = [];
                }
                for(var j=-1; ++j<data.length;) {
                    var circle = null,
                        line = null,
                        eventCircle = null;
                    if(options.dualAxis) {
                        yScale = options.yScale[series[i].yAxis || 'left'];
                    }
                    if(j !== data.length - 1) {
                        if(create) {
                            line = plotItemsLine[i][j] = paper.path('M' + ((seriesWidth * j) + seriesWidth / 2) + ',' + height +
                                                        'L' +  ((seriesWidth * (j+1)) + seriesWidth / 2) + ',' + height, seriesGroups[i]);
                            line.node.setAttribute('class', (series[i].classed || '') + classes);
                            if(!classes) {
                                line.attr({
                                    stroke: series[i].color,
                                    fill: 'none'
                                });
                            }
                        } else {
                            line = plotItemsLine[i][j];
                        }
                        if(typeof(data[j] === "number")  && typeof(data[j+1] === "number")) {
                            line.attr('opacity', 1);
                        } else {
                            line.attr('opacity', 0);
                        }
                        line.animate({
                            path: 'M' + ((seriesWidth * j) + seriesWidth / 2) + ',' + (height - yScale.calc(data[j])) +
                                                        'L' +  ((seriesWidth * (j+1)) + seriesWidth / 2) + ',' + (height - yScale.calc(data[j+1]))
                        }, animate ? 500 : 0);
                    }
                    if(create) {
                        circle = plotItemsCircle[i][j] = paper.circle((seriesWidth * j) + seriesWidth / 2, height, CIRCLE_RADIUS, seriesGroups[i]);
                        circle.node.setAttribute('class', (series[i].classed || '') + classes);
                        var params = {
                            seriesIndex: series[i].seriesIndex,
                            labelIndex: j,
                            value: data[j],
                            label: labels[j]
                        };
                        circle.click(createClickCallback(params));
                        circle.mouseover(createOverCallback(params, circle));
                        circle.mouseout(createOutCallback(params, circle));
                        if(!classes) {
                            circle.attr({
                                stroke: series[i].color,
                                fill: '#FFF'
                            });
                        }
                        eventCircle = plotItemsEventCircle[i][j] = paper.circle((seriesWidth * j) + seriesWidth / 2, height, CIRCLE_EVENT_RADIUS, seriesGroups[i]);
                        eventCircle.node.setAttribute('class', (series[i].classed || '') + ' rc-series-' + i + ' rc-plot-item' + ' ' + (options.plotItemClasses || ''));
                        eventCircle.attr({opacity: 0});
                        eventCircle.click(createClickCallback(params));
                        eventCircle.mouseover(createOverCallback(params, circle));
                        eventCircle.mouseout(createOutCallback(params, circle));
                        !function(circle) {
                            eventCircle.mouseover(function() {
                                circle.animate({
                                    r: CIRCLE_ANIMATE_RADIUS
                                }, 100);
                            });
                            eventCircle.mouseout(function() {
                                circle.animate({
                                    r: CIRCLE_RADIUS
                                }, 100);
                            });
                        }(circle);

                    } else {
                        circle = plotItemsCircle[i][j];
                        eventCircle = plotItemsEventCircle[i][j];
                    }
                    if(typeof(data[j]) === "number") {
                        circle.attr('opacity', 1);
                    } else {
                        circle.attr('opacity', 0);
                    }
                    circle.animate({
                        cx: (seriesWidth * j) + seriesWidth / 2,
                        cy: height - yScale.calc(data[j])
                    }, animate ? 500 : 0);

                    eventCircle.attr({
                        cx: (seriesWidth * j) + seriesWidth / 2,
                        cy: height - yScale.calc(data[j])
                    });
                }
            }
        };

        var createClickCallback = function (params) {
            return function() {
                eventManager.trigger('plotItemClick', params);
                eventManager.trigger('plotItemActivate', params);
            };
        };
        var createOverCallback = function (params, $el) {
            return function() {
                var attr = $el.node.getAttribute('class');
                $el.node.setAttribute('class', attr + ' highlight');
                eventManager.trigger('plotItemMouseOver', params);
            };
        };
        var createOutCallback = function (params, $el) {
            return function() {
                var attr = $el.node.getAttribute('class');
                attr = attr.replace(' highlight', '');
                $el.node.setAttribute('class', attr);
                eventManager.trigger('plotItemMouseOut', params);
            };
        };
    };

    return LineChart;
});<|endoftext|>


<commit_before><commit_msg>adding the raw property to the include to get the raw version from github<commit_after><|endoftext|>


<commit_before>
import MigrationProvider from "./database-migrator/MigrationProvider";

/**
 * Utility for migrating the database to newer versions.
 */
const migrator = new MigrationProvider();

/**
 * Name of the database to connect to.
 */
const DB_NAME = "subscriptionFeed";

/**
 * Current version of the database.
 */
const DB_VERSION = 1;

/**
 * Delay in milliseconds between reconnecting to the database. The connection
 * is lost usually when a {@code versionchange} event occurs on the database.
 */
const RECONNECT_DELAY = 200;

/**
 * Private field symbols.
 */
const FIELDS = Object.freeze({
  database: Symbol("database"),
  errorObservers: Symbol("errorObservers")
});

/**
 * Provider of database connection and automatic database upgrator.
 */
export default class Database {
  /**
   * Initializes the database connection.
   */
  constructor() {
    /**
     * The database connection promise.
     *
     * @type {Promise<IDBDatabase>}
     */
    this[FIELDS.database] = connect().then((database) => {
      database.onversionchange = () => reconnect(this);
      database.onerror = (error) => executeErrorObservers(this, error);
      return database;
    });

    /**
     * List of currently registered error observers.
     *
     * @type {function(Error)[]}
     */
    this[FIELDS.errorObservers] = [];
  }

  /**
   * Retrieves the current database connection. It is recommended not to cache
   * the returned connection as it may be replaced in time.
   *
   * @return {IDBDatabase} The current database connection.
   */
  async getConnection(): IDBDatabase {
    return await this[FIELDS.database];
  }

  /**
   * Registers the provided error observer to be executed whenever an error is
   * encounterer that is not captured on transaction or operation level.
   * Registering the same observer multiple times has no effect.
   *
   * @param {function(Error)} observer The observer to register.
   */
  addErrorObserver(observer: Function): void {
    if (this[FIELDS.errorObservers].indexOf(observer) > -1) {
      return;
    }

    this[FIELDS.errorObservers].push(observer);
  }

  /**
   * Removes the specified error observer from the registered error observers.
   *
   * @param {function(Error)} observer The observer to unregister.
   */
  removeErrorObserver(observer: Function): void {
    let index = this[FIELDS.errorObservers].indexOf(observer);
    if (index > -1) {
      this[FIELDS.errorObservers].splice(index, 1);
    }
  }
}

/**
 * Executes the error observers registered on the provided database instance.
 *
 * @param {Database} instance The instance on which the error observers are
 *        registered.
 * @param {Error} error The encountered error.
 */
function executeErrorObservers(instance: Database, error): void {
  instance[FIELDS.errorObservers].forEach((observer) => {
    try {
      observer(error);
    } catch (observerError) {
      console.error(
        "The registered error observer threw an error",
        observerError,
        observerError.stack,
        "Error passed to the observer:",
        error,
        error instanceof Error ? error.stack : "[stack unknown]"
      );
    }
  });

  if (!instance[FIELDS.errorObservers].length) {
    console.error(
      "Encountered an error while no error observers are registered",
      error,
      error instanceof Error ? error.stack : "[stack unknown]"
    );
  }
}

/**
 * Closes the current connection to the IndexedDB datbase in the provided
 * instance and then resets the connection field to a new promise that
 * reconnects to the database after {@code RECONNECT_DELAY} milliseconds.
 *
 * @param {Database} instance The instance that should have its connection
 *        reset.
 */
function reconnect(instance: Database): void {
  instance[FIELDS.database].then((database) => database.close());

  instance[FIELDS.database] = new Promise((resolve) => {
    setTimeout(resolve, RECONNECT_DELAY); // give it some time to upgrade
  }).
  then(connect).
  then((database) => {
    database.onversionchange = () => reconnect(instance);
    database.onerror = (error) => executeErrorObservers(instance, error);
    return database;
  });
}

/**
 * Connects to the database and performs database version migration if needed.
 *
 * @return {Promise<IDBDatabase>} Promise resolved to the database connection.
 */
function connect(): Promise {
  return new Promise((resolve, reject) => {
    let openRequest = indexedDB.open(DB_NAME, DB_VERSION);
    openRequest.onerror = reject;
    openRequest.onblocked = () => reject("Cannot upgrade database version " +
        "because the database is still in use");
    openRequest.onsuccess = () => resolve(openRequest.result);

    openRequest.onupgradeneeded = (event) => {
      let database = event.target.result;
      migrator.migrate(database);
    };
  });
}
<commit_msg>Improved handling of errors during database migration<commit_after>
import MigrationProvider from "./database-migrator/MigrationProvider";

/**
 * Utility for migrating the database to newer versions.
 */
const migrator = new MigrationProvider();

/**
 * Name of the database to connect to.
 */
const DB_NAME = "subscriptionFeed";

/**
 * Current version of the database.
 */
const DB_VERSION = 1;

/**
 * Delay in milliseconds between reconnecting to the database. The connection
 * is lost usually when a {@code versionchange} event occurs on the database.
 */
const RECONNECT_DELAY = 200;

/**
 * Private field symbols.
 */
const FIELDS = Object.freeze({
  database: Symbol("database"),
  errorObservers: Symbol("errorObservers")
});

/**
 * Provider of database connection and automatic database upgrator.
 */
export default class Database {
  /**
   * Initializes the database connection.
   */
  constructor() {
    /**
     * The database connection promise.
     *
     * @type {Promise<IDBDatabase>}
     */
    this[FIELDS.database] = connect().then((database) => {
      database.onversionchange = () => reconnect(this);
      database.onerror = (error) => executeErrorObservers(this, error);
      return database;
    });

    /**
     * List of currently registered error observers.
     *
     * @type {function(Error)[]}
     */
    this[FIELDS.errorObservers] = [];
  }

  /**
   * Retrieves the current database connection. It is recommended not to cache
   * the returned connection as it may be replaced in time.
   *
   * @return {IDBDatabase} The current database connection.
   */
  async getConnection(): IDBDatabase {
    return await this[FIELDS.database];
  }

  /**
   * Registers the provided error observer to be executed whenever an error is
   * encounterer that is not captured on transaction or operation level.
   * Registering the same observer multiple times has no effect.
   *
   * @param {function(Error)} observer The observer to register.
   */
  addErrorObserver(observer: Function): void {
    if (this[FIELDS.errorObservers].indexOf(observer) > -1) {
      return;
    }

    this[FIELDS.errorObservers].push(observer);
  }

  /**
   * Removes the specified error observer from the registered error observers.
   *
   * @param {function(Error)} observer The observer to unregister.
   */
  removeErrorObserver(observer: Function): void {
    let index = this[FIELDS.errorObservers].indexOf(observer);
    if (index > -1) {
      this[FIELDS.errorObservers].splice(index, 1);
    }
  }
}

/**
 * Executes the error observers registered on the provided database instance.
 *
 * @param {Database} instance The instance on which the error observers are
 *        registered.
 * @param {Error} error The encountered error.
 */
function executeErrorObservers(instance: Database, error): void {
  instance[FIELDS.errorObservers].forEach((observer) => {
    try {
      observer(error);
    } catch (observerError) {
      console.error(
        "The registered error observer threw an error",
        observerError,
        observerError.stack,
        "Error passed to the observer:",
        error,
        error instanceof Error ? error.stack : "[stack unknown]"
      );
    }
  });

  if (!instance[FIELDS.errorObservers].length) {
    console.error(
      "Encountered an error while no error observers are registered",
      error,
      error instanceof Error ? error.stack : "[stack unknown]"
    );
  }
}

/**
 * Closes the current connection to the IndexedDB datbase in the provided
 * instance and then resets the connection field to a new promise that
 * reconnects to the database after {@code RECONNECT_DELAY} milliseconds.
 *
 * @param {Database} instance The instance that should have its connection
 *        reset.
 */
function reconnect(instance: Database): void {
  instance[FIELDS.database].then((database) => database.close());

  instance[FIELDS.database] = new Promise((resolve) => {
    setTimeout(resolve, RECONNECT_DELAY); // give it some time to upgrade
  }).
  then(connect).
  then((database) => {
    database.onversionchange = () => reconnect(instance);
    database.onerror = (error) => executeErrorObservers(instance, error);
    return database;
  });
}

/**
 * Connects to the database and performs database version migration if needed.
 *
 * @return {Promise<IDBDatabase>} Promise resolved to the database connection.
 */
function connect(): Promise {
  return new Promise((resolve, reject) => {
    let openRequest = indexedDB.open(DB_NAME, DB_VERSION);
    openRequest.onerror = reject;
    openRequest.onblocked = () => reject("Cannot upgrade database version " +
        "because the database is still in use");
    openRequest.onsuccess = () => resolve(openRequest.result);

    openRequest.onupgradeneeded = (event) => {
      let database = event.target.result;
      try {
        migrator.migrate(database);
      } catch (e) {
        reject(e);
      }
    };
  });
}
<|endoftext|>