<commit_before>(function() {
  var MutationObserver, Util, WeakMap, getComputedStyle, getComputedStyleRX,
    bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
    indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

  Util = (function() {
    function Util() {}

    Util.prototype.extend = function(custom, defaults) {
      var key, value;
      for (key in defaults) {
        value = defaults[key];
        if (custom[key] == null) {
          custom[key] = value;
        }
      }
      return custom;
    };

    Util.prototype.isMobile = function(agent) {
      return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(agent);
    };

    Util.prototype.createEvent = function(event, bubble, cancel, detail) {
      var customEvent;
      if (bubble == null) {
        bubble = false;
      }
      if (cancel == null) {
        cancel = false;
      }
      if (detail == null) {
        detail = null;
      }
      if (document.createEvent != null) {
        customEvent = document.createEvent('CustomEvent');
        customEvent.initCustomEvent(event, bubble, cancel, detail);
      } else if (document.createEventObject != null) {
        customEvent = document.createEventObject();
        customEvent.eventType = event;
      } else {
        customEvent.eventName = event;
      }
      return customEvent;
    };

    Util.prototype.emitEvent = function(elem, event) {
      if (elem.dispatchEvent != null) {
        return elem.dispatchEvent(event);
      } else if (event in (elem != null)) {
        return elem[event]();
      } else if (("on" + event) in (elem != null)) {
        return elem["on" + event]();
      }
    };

    Util.prototype.addEvent = function(elem, event, fn) {
      if (elem.addEventListener != null) {
        return elem.addEventListener(event, fn, false);
      } else if (elem.attachEvent != null) {
        return elem.attachEvent("on" + event, fn);
      } else {
        return elem[event] = fn;
      }
    };

    Util.prototype.removeEvent = function(elem, event, fn) {
      if (elem.removeEventListener != null) {
        return elem.removeEventListener(event, fn, false);
      } else if (elem.detachEvent != null) {
        return elem.detachEvent("on" + event, fn);
      } else {
        return delete elem[event];
      }
    };

    Util.prototype.innerHeight = function() {
      if ('innerHeight' in window) {
        return window.innerHeight;
      } else {
        return document.documentElement.clientHeight;
      }
    };

    return Util;

  })();

  WeakMap = this.WeakMap || this.MozWeakMap || (WeakMap = (function() {
    function WeakMap() {
      this.keys = [];
      this.values = [];
    }

    WeakMap.prototype.get = function(key) {
      var i, item, j, len, ref;
      ref = this.keys;
      for (i = j = 0, len = ref.length; j < len; i = ++j) {
        item = ref[i];
        if (item === key) {
          return this.values[i];
        }
      }
    };

    WeakMap.prototype.set = function(key, value) {
      var i, item, j, len, ref;
      ref = this.keys;
      for (i = j = 0, len = ref.length; j < len; i = ++j) {
        item = ref[i];
        if (item === key) {
          this.values[i] = value;
          return;
        }
      }
      this.keys.push(key);
      return this.values.push(value);
    };

    return WeakMap;

  })());

  MutationObserver = this.MutationObserver || this.WebkitMutationObserver || this.MozMutationObserver || (MutationObserver = (function() {
    function MutationObserver() {
      if (typeof console !== "undefined" && console !== null) {
        console.warn('MutationObserver is not supported by your browser.');
      }
      if (typeof console !== "undefined" && console !== null) {
        console.warn('WOW.js cannot detect dom mutations, please call .sync() after loading new content.');
      }
    }

    MutationObserver.notSupported = true;

    MutationObserver.prototype.observe = function() {};

    return MutationObserver;

  })());

  getComputedStyle = this.getComputedStyle || function(el, pseudo) {
    this.getPropertyValue = function(prop) {
      var ref;
      if (prop === 'float') {
        prop = 'styleFloat';
      }
      if (getComputedStyleRX.test(prop)) {
        prop.replace(getComputedStyleRX, function(_, _char) {
          return _char.toUpperCase();
        });
      }
      return ((ref = el.currentStyle) != null ? ref[prop] : void 0) || null;
    };
    return this;
  };

  getComputedStyleRX = /(\-([a-z]){1})/g;

  this.WOW = (function() {
    WOW.prototype.defaults = {
      boxClass: 'wow',
      animateClass: 'animated',
      offset: 0,
      mobile: true,
      live: true,
      callback: null,
      scrollContainer: null
    };

    function WOW(options) {
      if (options == null) {
        options = {};
      }
      this.scrollCallback = bind(this.scrollCallback, this);
      this.scrollHandler = bind(this.scrollHandler, this);
      this.resetAnimation = bind(this.resetAnimation, this);
      this.start = bind(this.start, this);
      this.scrolled = true;
      this.config = this.util().extend(options, this.defaults);
      if (options.scrollContainer != null) {
        this.config.scrollContainer = document.querySelector(options.scrollContainer);
      }
      this.animationNameCache = new WeakMap();
      this.wowEvent = this.util().createEvent(this.config.boxClass);
    }

    WOW.prototype.init = function() {
      var ref;
      this.element = window.document.documentElement;
      if ((ref = document.readyState) === "interactive" || ref === "complete") {
        this.start();
      } else {
        this.util().addEvent(document, 'DOMContentLoaded', this.start);
      }
      return this.finished = [];
    };

    WOW.prototype.start = function() {
      var box, j, len, ref;
      this.stopped = false;
      this.boxes = (function() {
        var j, len, ref, results;
        ref = this.element.querySelectorAll("." + this.config.boxClass);
        results = [];
        for (j = 0, len = ref.length; j < len; j++) {
          box = ref[j];
          results.push(box);
        }
        return results;
      }).call(this);
      this.all = (function() {
        var j, len, ref, results;
        ref = this.boxes;
        results = [];
        for (j = 0, len = ref.length; j < len; j++) {
          box = ref[j];
          results.push(box);
        }
        return results;
      }).call(this);
      if (this.boxes.length) {
        if (this.disabled()) {
          this.resetStyle();
        } else {
          ref = this.boxes;
          for (j = 0, len = ref.length; j < len; j++) {
            box = ref[j];
            this.applyStyle(box, true);
          }
        }
      }
      if (!this.disabled()) {
        this.util().addEvent(this.config.scrollContainer || window, 'scroll', this.scrollHandler);
        this.util().addEvent(window, 'resize', this.scrollHandler);
        this.interval = setInterval(this.scrollCallback, 50);
      }
      if (this.config.live) {
        return new MutationObserver((function(_this) {
          return function(records) {
            var k, len1, node, record, results;
            results = [];
            for (k = 0, len1 = records.length; k < len1; k++) {
              record = records[k];
              results.push((function() {
                var l, len2, ref1, results1;
                ref1 = record.addedNodes || [];
                results1 = [];
                for (l = 0, len2 = ref1.length; l < len2; l++) {
                  node = ref1[l];
                  results1.push(this.doSync(node));
                }
                return results1;
              }).call(_this));
            }
            return results;
          };
        })(this)).observe(document.body, {
          childList: true,
          subtree: true
        });
      }
    };

    WOW.prototype.stop = function() {
      this.stopped = true;
      this.util().removeEvent(this.config.scrollContainer || window, 'scroll', this.scrollHandler);
      this.util().removeEvent(window, 'resize', this.scrollHandler);
      if (this.interval != null) {
        return clearInterval(this.interval);
      }
    };

    WOW.prototype.sync = function(element) {
      if (MutationObserver.notSupported) {
        return this.doSync(this.element);
      }
    };

    WOW.prototype.doSync = function(element) {
      var box, j, len, ref, results;
      if (element == null) {
        element = this.element;
      }
      if (element.nodeType !== 1) {
        return;
      }
      element = element.parentNode || element;
      ref = element.querySelectorAll("." + this.config.boxClass);
      results = [];
      for (j = 0, len = ref.length; j < len; j++) {
        box = ref[j];
        if (indexOf.call(this.all, box) < 0) {
          this.boxes.push(box);
          this.all.push(box);
          if (this.stopped || this.disabled()) {
            this.resetStyle();
          } else {
            this.applyStyle(box, true);
          }
          results.push(this.scrolled = true);
        } else {
          results.push(void 0);
        }
      }
      return results;
    };

    WOW.prototype.show = function(box) {
      this.applyStyle(box);
      box.className = box.className + " " + this.config.animateClass;
      if (this.config.callback != null) {
        this.config.callback(box);
      }
      this.util().emitEvent(box, this.wowEvent);
      this.util().addEvent(box, 'animationend', this.resetAnimation);
      this.util().addEvent(box, 'oanimationend', this.resetAnimation);
      this.util().addEvent(box, 'webkitAnimationEnd', this.resetAnimation);
      this.util().addEvent(box, 'MSAnimationEnd', this.resetAnimation);
      return box;
    };

    WOW.prototype.applyStyle = function(box, hidden) {
      var delay, duration, iteration;
      duration = box.getAttribute('data-wow-duration');
      delay = box.getAttribute('data-wow-delay');
      iteration = box.getAttribute('data-wow-iteration');
      return this.animate((function(_this) {
        return function() {
          return _this.customStyle(box, hidden, duration, delay, iteration);
        };
      })(this));
    };

    WOW.prototype.animate = (function() {
      if ('requestAnimationFrame' in window) {
        return function(callback) {
          return window.requestAnimationFrame(callback);
        };
      } else {
        return function(callback) {
          return callback();
        };
      }
    })();

    WOW.prototype.resetStyle = function() {
      var box, j, len, ref, results;
      ref = this.boxes;
      results = [];
      for (j = 0, len = ref.length; j < len; j++) {
        box = ref[j];
        results.push(box.style.visibility = 'visible');
      }
      return results;
    };

    WOW.prototype.resetAnimation = function(event) {
      var target;
      if (event.type.toLowerCase().indexOf('animationend') >= 0) {
        target = event.target || event.srcElement;
        return target.className = target.className.replace(this.config.animateClass, '').trim();
      }
    };

    WOW.prototype.customStyle = function(box, hidden, duration, delay, iteration) {
      if (hidden) {
        this.cacheAnimationName(box);
      }
      box.style.visibility = hidden ? 'hidden' : 'visible';
      if (duration) {
        this.vendorSet(box.style, {
          animationDuration: duration
        });
      }
      if (delay) {
        this.vendorSet(box.style, {
          animationDelay: delay
        });
      }
      if (iteration) {
        this.vendorSet(box.style, {
          animationIterationCount: iteration
        });
      }
      this.vendorSet(box.style, {
        animationName: hidden ? 'none' : this.cachedAnimationName(box)
      });
      return box;
    };

    WOW.prototype.vendors = ["moz", "webkit"];

    WOW.prototype.vendorSet = function(elem, properties) {
      var name, results, value, vendor;
      results = [];
      for (name in properties) {
        value = properties[name];
        elem["" + name] = value;
        results.push((function() {
          var j, len, ref, results1;
          ref = this.vendors;
          results1 = [];
          for (j = 0, len = ref.length; j < len; j++) {
            vendor = ref[j];
            results1.push(elem["" + vendor + (name.charAt(0).toUpperCase()) + (name.substr(1))] = value);
          }
          return results1;
        }).call(this));
      }
      return results;
    };

    WOW.prototype.vendorCSS = function(elem, property) {
      var j, len, ref, result, style, vendor;
      style = getComputedStyle(elem);
      result = style.getPropertyCSSValue(property);
      ref = this.vendors;
      for (j = 0, len = ref.length; j < len; j++) {
        vendor = ref[j];
        result = result || style.getPropertyCSSValue("-" + vendor + "-" + property);
      }
      return result;
    };

    WOW.prototype.animationName = function(box) {
      var animationName, error;
      try {
        animationName = this.vendorCSS(box, 'animation-name').cssText;
      } catch (error) {
        animationName = getComputedStyle(box).getPropertyValue('animation-name');
      }
      if (animationName === 'none') {
        return '';
      } else {
        return animationName;
      }
    };

    WOW.prototype.cacheAnimationName = function(box) {
      return this.animationNameCache.set(box, this.animationName(box));
    };

    WOW.prototype.cachedAnimationName = function(box) {
      return this.animationNameCache.get(box);
    };

    WOW.prototype.scrollHandler = function() {
      return this.scrolled = true;
    };

    WOW.prototype.scrollCallback = function() {
      var box;
      if (this.scrolled) {
        this.scrolled = false;
        this.boxes = (function() {
          var j, len, ref, results;
          ref = this.boxes;
          results = [];
          for (j = 0, len = ref.length; j < len; j++) {
            box = ref[j];
            if (!(box)) {
              continue;
            }
            if (this.isVisible(box)) {
              this.show(box);
              continue;
            }
            results.push(box);
          }
          return results;
        }).call(this);
        if (!(this.boxes.length || this.config.live)) {
          return this.stop();
        }
      }
    };

    WOW.prototype.offsetTop = function(element) {
      var top;
      while (element.offsetTop === void 0) {
        element = element.parentNode;
      }
      top = element.offsetTop;
      while (element = element.offsetParent) {
        top += element.offsetTop;
      }
      return top;
    };

    WOW.prototype.isVisible = function(box) {
      var bottom, offset, top, viewBottom, viewTop;
      offset = box.getAttribute('data-wow-offset') || this.config.offset;
      viewTop = (this.config.scrollContainer && this.config.scrollContainer.scrollTop) || window.pageYOffset;
      viewBottom = viewTop + Math.min(this.element.clientHeight, this.util().innerHeight()) - offset;
      top = this.offsetTop(box);
      bottom = top + box.clientHeight;
      return top <= viewBottom && bottom >= viewTop;
    };

    WOW.prototype.util = function() {
      return this._util != null ? this._util : this._util = new Util();
    };

    WOW.prototype.disabled = function() {
      return !this.config.mobile && this.util().isMobile(navigator.userAgent);
    };

    return WOW;

  })();

}).call(this);
<commit_msg>Delete wow.js<commit_after><|endoftext|>


<commit_before>const path = require('path');
const Star = require('../models/stars');
const Queue = require('./Queue');

class Starboard {
	constructor(guild) {
		this.client = guild.client;
		this.guild = guild;
		this.stars = new Map();
		this.queue = new Queue();
		this.initiated = false;

		Star.findAll({ where: { guildID: this.guild.id } }).then(stars => {
			for (const star of stars) {
				this.stars.set(star.messageID, star);
			}

			this.initiated = true;
		});
	}

	get channel() {
		const channelID = this.client.settings.get(this.guild, 'starboardChannelID');
		return this.guild.channels.get(channelID);
	}

	add(message, starredBy) {
		return new Promise(resolve => {
			this.queue.add(() => this.addStar(message, starredBy).then(resolve));
		});
	}

	async addStar(message, starredBy) {
		if (!this.initiated) {
			return 'Starboard has not fully loaded, please wait.';
		}

		const blacklist = this.client.settings.get(message.guild, 'blacklist', []);
		if (blacklist.includes(starredBy.id)) {
			return 'You have been blacklisted from using the starboard';
		}

		if (!this.channel) {
			const prefix = this.client.commandHandler.prefix(message);
			return `There isn't a starboard channel to use. Set one using the \`${prefix}starboard\` command!`;
		}

		if (message.author.id === starredBy.id) {
			return 'You can\'t star your own messages.';
		}

		const missingPerms = this.missingPermissions();
		if (missingPerms) {
			return missingPerms;
		}

		if (this.stars.has(message.id)) {
			const star = this.stars.get(message.id);
			if (star.starredBy.includes(starredBy.id)) {
				return 'You have already starred this message before; You can\'t star it again.';
			}
		}

		if (!this.stars.has(message.id)) {
			const starboardMessage = await this.channel.send({ embed: this.buildStarboardEmbed(message) });

			const star = await Star.create({
				messageID: message.id,
				authorID: message.author.id,
				channelID: message.channel.id,
				guildID: this.guild.id,
				starboardMessageID: starboardMessage.id,
				starredBy: [starredBy.id]
			});

			this.stars.set(message.id, star);
			return undefined;
		}

		const star = this.stars.get(message.id);
		const newStarredBy = star.starredBy.concat([starredBy.id]);

		const embed = this.buildStarboardEmbed(message, newStarredBy.length);
		const starboardMessage = await this.channel.fetchMessage(star.starboardMessageID)
			.then(msg => msg.edit({ embed }))
			.catch(() => this.channel.send({ embed }));

		const newStar = await star.update({
			starCount: newStarredBy.length,
			starredBy: newStarredBy,
			starboardMessageID: starboardMessage.id
		});

		this.stars.set(message.id, newStar);
		return undefined;
	}

	remove(message, unstarredBy) {
		return new Promise(resolve => {
			this.queue.add(() => this.removeStar(message, unstarredBy).then(resolve));
		});
	}

	async removeStar(message, unstarredBy) {
		if (!this.initiated) {
			return 'Starboard has not fully loaded, please wait.';
		}

		const blacklist = this.client.settings.get(message.guild, 'blacklist', []);
		if (blacklist.includes(unstarredBy.id)) return undefined;
		if (message.author.id === unstarredBy.id) return undefined;

		if (!this.channel) {
			const prefix = this.client.commandHandler.prefix(message);
			return `There isn't a starboard channel to use. Set one using the \`${prefix}starboard\` command!`;
		}

		const star = this.stars.get(message.id);
		if (!star || !star.starredBy.includes(unstarredBy.id)) {
			return 'You can\'t remove any star from this message because you never gave it one in the first place.';
		}

		const missingPerms = this.missingPermissions();
		if (missingPerms) {
			return missingPerms;
		}

		if (message.reactions.has('⭐') && message.reactions.get('⭐').users.has(unstarredBy.id)) {
			await message.reactions.get('⭐').remove(unstarredBy);
		}

		const newStarredBy = star.starredBy.filter(id => id !== unstarredBy.id);

		if (newStarredBy.length) {
			const embed = this.buildStarboardEmbed(message, newStarredBy.length);
			const starboardMessage = await this.channel.fetchMessage(star.starboardMessageID)
				.then(msg => msg.edit({ embed }))
				.catch(() => this.channel.send({ embed }));

			const newStar = await star.update({
				starCount: newStarredBy.length,
				starredBy: newStarredBy,
				starboardMessageID: starboardMessage.id
			});

			this.stars.set(message.id, newStar);
			return undefined;
		}

		await this.channel.fetchMessage(star.starboardMessageID).then(msg => msg.delete()).catch(() => null);
		await star.destroy();
		this.stars.delete(message.id);
		return undefined;
	}

	delete(message) {
		return new Promise(resolve => {
			this.queue.add(() => this.deleteStar(message).then(resolve));
		});
	}

	async deleteStar(message) {
		if (!this.initiated) {
			return 'Starboard has not fully loaded, please wait.';
		}

		const star = this.stars.get(message.id);
		if (!star) return undefined;

		const missingPerms = this.missingPermissions();
		if (missingPerms) {
			return missingPerms;
		}

		const starboardMessage = await this.channel.fetchMessage(star.starboardMessageID);
		if (!starboardMessage) return undefined;

		await starboardMessage.delete();
		await star.destroy();
		this.stars.delete(message.id);
		return undefined;
	}

	destroy() {
		return Star.destroy({ where: { guildID: this.guild.id } });
	}

	missingPermissions() {
		const missingPermissions = this.client.listenerHandler.modules.get('commandBlocked').missingPermissions;
		const str = missingPermissions(this.channel, this.client.user, [
			'READ_MESSAGES',
			'MANAGE_MESSAGES',
			'READ_MESSAGE_HISTORY',
			'SEND_MESSAGES',
			'EMBED_LINKS'
		]);

		if (!str) return undefined;
		return `I'm missing ${str} in ${this.channel}.`;
	}

	buildStarboardEmbed(message, starCount = 1) {
		const star = Starboard.getStarEmoji(starCount);
		const embed = this.client.util.embed()
			.setColor(0xFFAC33)
			.addField('Author', message.author, true)
			.addField('Channel', message.channel, true)
			.setThumbnail(message.author.displayAvatarURL)
			.setTimestamp(message.createdAt)
			.setFooter(`${star} ${starCount} | ${message.id}`);

		if (message.content) {
			let content = message.content.substring(0, 1000);
			if (message.content.length > 1000) content += '...';
			embed.addField('Message', content);
		}

		const attachment = Starboard.findAttachment(message);
		if (attachment) {
			embed.setImage(attachment);
		}

		return embed;
	}

	static findAttachment(message) {
		let attachmentImage;
		const extensions = ['.png', '.jpg', '.jpeg', '.gif', '.webp'];
		const linkRegex = /https?:\/\/(?:\w+\.)?[\w-]+\.[\w]{2,3}(?:\/[\w-_.]+)+\.(?:png|jpg|jpeg|gif|webp)/;

		if (message.attachments.some(attachment => extensions.includes(path.extname(attachment.url)))) {
			attachmentImage = message.attachments.first().url;
		}

		if (!attachmentImage) {
			const linkMatch = message.content.match(linkRegex);
			if (linkMatch && extensions.includes(path.extname(linkMatch[0]))) {
				attachmentImage = linkMatch[0];
			}
		}

		return attachmentImage;
	}

	static getStarEmoji(count) {
		return count < 3
			? '⭐'
			: count < 5
				? '🌟'
				: count < 10
					? '✨'
					: '🌌';
	}
}

module.exports = Starboard;
<commit_msg>Fix message delete in delete<commit_after>const path = require('path');
const Star = require('../models/stars');
const Queue = require('./Queue');

class Starboard {
	constructor(guild) {
		this.client = guild.client;
		this.guild = guild;
		this.stars = new Map();
		this.queue = new Queue();
		this.initiated = false;

		Star.findAll({ where: { guildID: this.guild.id } }).then(stars => {
			for (const star of stars) {
				this.stars.set(star.messageID, star);
			}

			this.initiated = true;
		});
	}

	get channel() {
		const channelID = this.client.settings.get(this.guild, 'starboardChannelID');
		return this.guild.channels.get(channelID);
	}

	add(message, starredBy) {
		return new Promise(resolve => {
			this.queue.add(() => this.addStar(message, starredBy).then(resolve));
		});
	}

	async addStar(message, starredBy) {
		if (!this.initiated) {
			return 'Starboard has not fully loaded, please wait.';
		}

		const blacklist = this.client.settings.get(message.guild, 'blacklist', []);
		if (blacklist.includes(starredBy.id)) {
			return 'You have been blacklisted from using the starboard';
		}

		if (!this.channel) {
			const prefix = this.client.commandHandler.prefix(message);
			return `There isn't a starboard channel to use. Set one using the \`${prefix}starboard\` command!`;
		}

		if (message.author.id === starredBy.id) {
			return 'You can\'t star your own messages.';
		}

		const missingPerms = this.missingPermissions();
		if (missingPerms) {
			return missingPerms;
		}

		if (this.stars.has(message.id)) {
			const star = this.stars.get(message.id);
			if (star.starredBy.includes(starredBy.id)) {
				return 'You have already starred this message before; You can\'t star it again.';
			}
		}

		if (!this.stars.has(message.id)) {
			const starboardMessage = await this.channel.send({ embed: this.buildStarboardEmbed(message) });

			const star = await Star.create({
				messageID: message.id,
				authorID: message.author.id,
				channelID: message.channel.id,
				guildID: this.guild.id,
				starboardMessageID: starboardMessage.id,
				starredBy: [starredBy.id]
			});

			this.stars.set(message.id, star);
			return undefined;
		}

		const star = this.stars.get(message.id);
		const newStarredBy = star.starredBy.concat([starredBy.id]);

		const embed = this.buildStarboardEmbed(message, newStarredBy.length);
		const starboardMessage = await this.channel.fetchMessage(star.starboardMessageID)
			.then(msg => msg.edit({ embed }))
			.catch(() => this.channel.send({ embed }));

		const newStar = await star.update({
			starCount: newStarredBy.length,
			starredBy: newStarredBy,
			starboardMessageID: starboardMessage.id
		});

		this.stars.set(message.id, newStar);
		return undefined;
	}

	remove(message, unstarredBy) {
		return new Promise(resolve => {
			this.queue.add(() => this.removeStar(message, unstarredBy).then(resolve));
		});
	}

	async removeStar(message, unstarredBy) {
		if (!this.initiated) {
			return 'Starboard has not fully loaded, please wait.';
		}

		const blacklist = this.client.settings.get(message.guild, 'blacklist', []);
		if (blacklist.includes(unstarredBy.id)) return undefined;
		if (message.author.id === unstarredBy.id) return undefined;

		if (!this.channel) {
			const prefix = this.client.commandHandler.prefix(message);
			return `There isn't a starboard channel to use. Set one using the \`${prefix}starboard\` command!`;
		}

		const star = this.stars.get(message.id);
		if (!star || !star.starredBy.includes(unstarredBy.id)) {
			return 'You can\'t remove any star from this message because you never gave it one in the first place.';
		}

		const missingPerms = this.missingPermissions();
		if (missingPerms) {
			return missingPerms;
		}

		if (message.reactions.has('⭐') && message.reactions.get('⭐').users.has(unstarredBy.id)) {
			await message.reactions.get('⭐').remove(unstarredBy);
		}

		const newStarredBy = star.starredBy.filter(id => id !== unstarredBy.id);

		if (newStarredBy.length) {
			const embed = this.buildStarboardEmbed(message, newStarredBy.length);
			const starboardMessage = await this.channel.fetchMessage(star.starboardMessageID)
				.then(msg => msg.edit({ embed }))
				.catch(() => this.channel.send({ embed }));

			const newStar = await star.update({
				starCount: newStarredBy.length,
				starredBy: newStarredBy,
				starboardMessageID: starboardMessage.id
			});

			this.stars.set(message.id, newStar);
			return undefined;
		}

		await this.channel.fetchMessage(star.starboardMessageID).then(msg => msg.delete()).catch(() => null);
		await star.destroy();
		this.stars.delete(message.id);
		return undefined;
	}

	delete(message) {
		return new Promise(resolve => {
			this.queue.add(() => this.deleteStar(message).then(resolve));
		});
	}

	async deleteStar(message) {
		if (!this.initiated) {
			return 'Starboard has not fully loaded, please wait.';
		}

		const star = this.stars.get(message.id);
		if (!star) return undefined;

		const missingPerms = this.missingPermissions();
		if (missingPerms) {
			return missingPerms;
		}

		const starboardMessage = await this.channel.fetchMessage(star.starboardMessageID).catch(() => null);
		if (starboardMessage) {
			await starboardMessage.delete();
		}

		await star.destroy();
		this.stars.delete(message.id);
		return undefined;
	}

	destroy() {
		return Star.destroy({ where: { guildID: this.guild.id } });
	}

	missingPermissions() {
		const missingPermissions = this.client.listenerHandler.modules.get('commandBlocked').missingPermissions;
		const str = missingPermissions(this.channel, this.client.user, [
			'READ_MESSAGES',
			'MANAGE_MESSAGES',
			'READ_MESSAGE_HISTORY',
			'SEND_MESSAGES',
			'EMBED_LINKS'
		]);

		if (!str) return undefined;
		return `I'm missing ${str} in ${this.channel}.`;
	}

	buildStarboardEmbed(message, starCount = 1) {
		const star = Starboard.getStarEmoji(starCount);
		const embed = this.client.util.embed()
			.setColor(0xFFAC33)
			.addField('Author', message.author, true)
			.addField('Channel', message.channel, true)
			.setThumbnail(message.author.displayAvatarURL)
			.setTimestamp(message.createdAt)
			.setFooter(`${star} ${starCount} | ${message.id}`);

		if (message.content) {
			let content = message.content.substring(0, 1000);
			if (message.content.length > 1000) content += '...';
			embed.addField('Message', content);
		}

		const attachment = Starboard.findAttachment(message);
		if (attachment) {
			embed.setImage(attachment);
		}

		return embed;
	}

	static findAttachment(message) {
		let attachmentImage;
		const extensions = ['.png', '.jpg', '.jpeg', '.gif', '.webp'];
		const linkRegex = /https?:\/\/(?:\w+\.)?[\w-]+\.[\w]{2,3}(?:\/[\w-_.]+)+\.(?:png|jpg|jpeg|gif|webp)/;

		if (message.attachments.some(attachment => extensions.includes(path.extname(attachment.url)))) {
			attachmentImage = message.attachments.first().url;
		}

		if (!attachmentImage) {
			const linkMatch = message.content.match(linkRegex);
			if (linkMatch && extensions.includes(path.extname(linkMatch[0]))) {
				attachmentImage = linkMatch[0];
			}
		}

		return attachmentImage;
	}

	static getStarEmoji(count) {
		return count < 3
			? '⭐'
			: count < 5
				? '🌟'
				: count < 10
					? '✨'
					: '🌌';
	}
}

module.exports = Starboard;
<|endoftext|>


<commit_before>(function (window, $, undefined) {
  'use strict';
  String.prototype.toBool = function () {
    switch (this.toLowerCase()) {
    case 'false':
    case 'no':
    case '0':
    case '':
      return false;
    default:
      return true;
    }
  };
  var SoftwareUpdateModel = function SoftwareUpdateModel(updateChecker, configManager) {
    var self = this;

    self.showAlerts = ko.observable(false);
    self.branches = ko.observableArray();
    self.isSaved = ko.observable(false);

    self.changeSelectedBranches = function() {
      var selected = [];
      self.branches().forEach(function(branch) {
        if (branch.selected() === true) {
          selected.push(branch.name);
        }
      });
      configManager.setSelectedBranches( { branches: selected });
      self.isSaved(true);
      setTimeout(function() {self.isSaved(false)}, 2000);
      return true;
    };

    configManager.getShowAlerts(function(showAlerts){
      self.showAlerts(showAlerts)
    });

    self.showAlerts.subscribe(function(newValue){
      if (self.showAlerts()) {
        updateChecker.getBranches(function (branches) {
          configManager.getSelectedBranches(function (selectedBranches) {
            self.branches.removeAll();
            var selected = selectedBranches.branches ? selectedBranches.branches : branches;
            if (selected.length === 0) { selected = branches; }
            branches.forEach(function (branch) {
              var branchConfig = selected.filter(function (b) {
                return b == branch;
              });
              self.branches.push({ name: branch, selected: ko.observable(branchConfig.length > 0)});
            });
            self.changeSelectedBranches();
          });
        })
      }
      configManager.setShowAlerts(self.showAlerts());
      self.isSaved(true);
      setTimeout(function() {self.isSaved(false)}, 2000);
      return true;
    });

  };

  var SoftwareUpdater = function SoftwareUpdater(cockpit) {
    var self = this;

    var configManager = new SoftwareUpdaterConfig();

    var checker = new SoftwareUpdateChecker(configManager);
    this.model = new SoftwareUpdateModel(checker, configManager);

    console.log('Loading Software update plugin.');
    this.cockpit = cockpit;

    $('#plugin-settings').append('

');
    $('body').prepend('

');
    //this technique forces relative path to the js file instead of the excution directory
    var jsFileLocation = urlOfJsFile('software-update.js');
    $('#software-update-settings').load(jsFileLocation + '../settings.html', function () {
      ko.applyBindings(self.model, document.getElementById('software-update-settings'));
    });
    $('#software-update-alert-container').load(jsFileLocation + '../ui-templates.html', function () {
    });
    $('body').append('

');
    $('#proxy-container').hide();

    //var logoTitleModel = { cockpitVersion: ko.observable('N/A'), bbSerial: ko.observable('N/A') };
    var logoTitleModel = {};
    logoTitleModel.cockpitVersion = ko.observable('N/A');
    logoTitleModel.bbSerial = ko.observable('N/A');
     $('a.brand').attr('data-bind', 'attr: {title: "Version: " + cockpitVersion() + "\\nBB Serial: " + bbSerial()}');
    $.get(configManager.dashboardUrl() + '/plugin/software/installed/openrov-cockpit', function(data) {
        if (data.length > 0) {
          logoTitleModel.cockpitVersion(data[0].package + ' - ' + data[0].version);
          console.log('Cockpit version: ' + logoTitleModel.cockpitVersion());
        }
       })
      .fail(function() { console.log('Error getting the cockpit version') });
    $.get(configManager.dashboardUrl() + '/plugin/software/bbserial', function(data) {
         logoTitleModel.bbSerial(data.bbSerial);
         console.log('BB Serial: ' + logoTitleModel.bbSerial());
       })
      .fail(function() { console.log('Error getting the cockpit version') });
    ko.applyBindings(logoTitleModel, $('a.brand')[0]);

    self.model.showAlerts.subscribe(function(newValue) {
      if (newValue) {
        setTimeout(function() {
          checkForUpdates(checker);
        }, 10000);
      }
    });

    setTimeout(
      function() {
        $.post(configManager.dashboardUrl() + '/plugin/software/update/run')
          .done(function() {
            console.log('Started apt-get update on cockpit');
            checkForUpdates(checker);
           })
          .fail(function() { console.log('Error starting apt-get update on cockpit') });
      }, 2 * 60 * 1000); //two minutes

      function checkForUpdates(checker) {
        checker.checkForUpdates(function (updates) {
          if (updates && updates.length > 0) {
            var model = { packages: updates, dashboardUrl: configManager.dashboardUrl }
            var container = $('#software-update-alert-container');
            ko.applyBindings(model, container[0]);
            container.removeClass('hide');
          }
        });

    }

  };
  window.Cockpit.plugins.push(SoftwareUpdater);
}(window, jQuery));
<commit_msg>Fix update notification<commit_after>(function (window, $, undefined) {
  'use strict';
  String.prototype.toBool = function () {
    switch (this.toLowerCase()) {
    case 'false':
    case 'no':
    case '0':
    case '':
      return false;
    default:
      return true;
    }
  };
  var SoftwareUpdateModel = function SoftwareUpdateModel(updateChecker, configManager) {
    var self = this;

    self.showAlerts = ko.observable(false);
    self.branches = ko.observableArray();
    self.isSaved = ko.observable(false);

    self.changeSelectedBranches = function() {
      var selected = [];
      self.branches().forEach(function(branch) {
        if (branch.selected() === true) {
          selected.push(branch.name);
        }
      });
      configManager.setSelectedBranches( { branches: selected });
      self.isSaved(true);
      setTimeout(function() {self.isSaved(false)}, 2000);
      return true;
    };

    configManager.getShowAlerts(function(showAlerts){
      self.showAlerts(showAlerts);
      subscribeToShowAlerts();
    });
    getBranches();

    function subscribeToShowAlerts() {
      var showAlertsSubscription = undefined;
      showAlertsSubscription = self.showAlerts.subscribe(function(newValue){
        if (self.showAlerts()) {
          getBranches();
          showAlertsSubscription.dispose();
        }
        configManager.setShowAlerts(self.showAlerts());
        self.isSaved(true);
        setTimeout(function() {self.isSaved(false)}, 2000);
        return true;
      });
    }

    function getBranches() {
      updateChecker.getBranches(function (branches) {
          configManager.getSelectedBranches(function (selectedBranches) {
            self.branches.removeAll();
            var selected = selectedBranches.branches ? selectedBranches.branches : branches;
            if (selected.length === 0) { selected = branches; }
            branches.forEach(function (branch) {
              var branchConfig = selected.filter(function (b) {
                return b == branch;
              });
              self.branches.push({ name: branch, selected: ko.observable(branchConfig.length > 0)});
            });
            self.changeSelectedBranches();
          });
        })
      }

  };

  var SoftwareUpdater = function SoftwareUpdater(cockpit) {
    var self = this;

    var configManager = new SoftwareUpdaterConfig();

    var checker = new SoftwareUpdateChecker(configManager);
    this.model = new SoftwareUpdateModel(checker, configManager);

    console.log('Loading Software update plugin.');
    this.cockpit = cockpit;

    $('#plugin-settings').append('

');
    $('body').prepend('

');
    //this technique forces relative path to the js file instead of the excution directory
    var jsFileLocation = urlOfJsFile('software-update.js');
    $('#software-update-settings').load(jsFileLocation + '../settings.html', function () {
      ko.applyBindings(self.model, document.getElementById('software-update-settings'));
    });
    $('#software-update-alert-container').load(jsFileLocation + '../ui-templates.html', function () {
    });
    $('body').append('

');
    $('#proxy-container').hide();

    var logoTitleModel = {};
    logoTitleModel.cockpitVersion = ko.observable('N/A');
    logoTitleModel.bbSerial = ko.observable('N/A');
    $('a.brand').attr('data-bind', 'attr: {title: "Version: " + cockpitVersion() + "\\nBB Serial: " + bbSerial()}');

    $.get(configManager.dashboardUrl() + '/plugin/software/installed/openrov-cockpit', function(data) {
        if (data.length > 0) {
          logoTitleModel.cockpitVersion(data[0].package + ' - ' + data[0].version);
          console.log('Cockpit version: ' + logoTitleModel.cockpitVersion());
        }
       })
      .fail(function() { console.log('Error getting the cockpit version') });
    $.get(configManager.dashboardUrl() + '/plugin/software/bbserial', function(data) {
         logoTitleModel.bbSerial(data.bbSerial);
         console.log('BB Serial: ' + logoTitleModel.bbSerial());
       })
      .fail(function() { console.log('Error getting the cockpit version') });
    ko.applyBindings(logoTitleModel, $('a.brand')[0]);

    self.model.showAlerts.subscribe(function(newValue) {
      if ((self.model.showAlerts() !== newValue) && newValue === true) {
        setTimeout(function() {
          checkForUpdates(checker);
        }, 5000);
      }
    });

    setTimeout(
      function() {
        $.post(configManager.dashboardUrl() + '/plugin/software/update/run')
          .done(function() {
            console.log('Started apt-get update on cockpit');
            checkForUpdates(checker);
           })
          .fail(function() { console.log('Error starting apt-get update on cockpit') });
      }, 2 * 60 * 1000); //two minutes

    function checkForUpdates(checker) {
      checker.checkForUpdates(function (updates) {
        if (updates && updates.length > 0) {
          var model = { packages: updates, dashboardUrl: configManager.dashboardUrl }
          var container = $('#software-update-alert-container');
          ko.applyBindings(model, container[0]);
          container.removeClass('hide');
        }
      });

    }

  };
  window.Cockpit.plugins.push(SoftwareUpdater);
}(window, jQuery));
<|endoftext|>


<commit_before>import { resolveIfNotPlain } from 'es-module-loader/core/resolve.js';
import { baseURI, isBrowser, isWindows, addToError, global, createSymbol, resolvedPromise } from 'es-module-loader/core/common.js';
import RegisterLoader from 'es-module-loader/core/register-loader.js';
import { ModuleNamespace } from 'es-module-loader/core/loader-polyfill.js';

export { baseURI, isBrowser, isWindows, addToError, global, resolveIfNotPlain, ModuleNamespace, resolvedPromise }

export function noop () {};

export var emptyModule = new ModuleNamespace({});

export function protectedCreateNamespace (bindings) {
  if (bindings instanceof ModuleNamespace)
    return bindings;
  if (typeof bindings !== 'object')
    throw new TypeError('Cannot create a module namespace from an object of type "' + typeof bindings + '".');
  return new ModuleNamespace(bindings);
}

export var CONFIG = createSymbol('loader-config');
export var METADATA = createSymbol('metadata');
export var PLAIN_RESOLVE = createSymbol('plain-resolve');
export var PLAIN_RESOLVE_SYNC = createSymbol('plain-resolve-sync');

export var isWorker = typeof window === 'undefined' && typeof self !== 'undefined' && typeof importScripts !== 'undefined';

export function warn (msg, force) {
  if (force || this.warnings && typeof console !== 'undefined' && console.warn)
    console.warn(msg);
}

var parentModuleContext;
export function loadNodeModule (key, baseURL) {
  if (key[0] === '.')
    throw new Error('Node module ' + key + ' can\'t be loaded as it is not a package require.');

  if (!parentModuleContext) {
    var Module = this._nodeRequire('module');
    var base = baseURL.substr(isWindows ? 8 : 7);
    parentModuleContext = new Module(base);
    parentModuleContext.paths = Module._nodeModulePaths(base);
  }
  return parentModuleContext.require(key);
}

export function extend (a, b) {
  for (var p in b) {
    if (!Object.hasOwnProperty.call(b, p))
      continue;
    a[p] = b[p];
  }
  return a;
}

export function prepend (a, b) {
  for (var p in b) {
    if (!Object.hasOwnProperty.call(b, p))
      continue;
    if (a[p] === undefined)
      a[p] = b[p];
  }
  return a;
}

// meta first-level extends where:
// array + array appends
// object + object extends
// other properties replace
export function extendMeta (a, b, _prepend) {
  for (var p in b) {
    if (!Object.hasOwnProperty.call(b, p))
      continue;
    var val = b[p];
    if (a[p] === undefined)
      a[p] = val;
    else if (val instanceof Array && a[p] instanceof Array)
      a[p] = [].concat(_prepend ? val : a[p]).concat(_prepend ? a[p] : val);
    else if (typeof val == 'object' && val !== null && typeof a[p] == 'object')
      a[p] = (_prepend ? prepend : extend)(extend({}, a[p]), val);
    else if (!_prepend)
      a[p] = val;
  }
}

var supportsPreload = isBrowser && (function () {
  var relList = document.createElement('link').relList;
  if (relList && relList.supports) {
    try {
      return relList.supports('preload');
    }
    catch (e) {}
  }
  return false;
})();

export function preloadScript (url) {
  var link = document.createElement('link');
  if (supportsPreload) {
    link.rel = 'preload';
    link.as = 'script';
  }
  else {
    link.rel = 'prefetch';
  }
  link.href = url;
  document.head.appendChild(link);
  document.head.removeChild(link);
}

function workerImport (src, resolve, reject) {
  try {
    importScripts(src);
  }
  catch (e) {
    reject(e);
  }
  resolve();
}

if (isBrowser) {
  var loadingScripts = [];
  var onerror = window.onerror;
  window.onerror = function globalOnerror (msg, src) {
    for (var i = 0; i < loadingScripts.length; i++) {
      if (loadingScripts[i].src !== src)
        continue;
      loadingScripts[i].err(msg);
      return;
    }
    onerror.apply(this, arguments);
  };
}

export function scriptLoad (src, crossOrigin, integrity, resolve, reject) {
  // percent encode just "#" for HTTP requests
  src = src.replace(/#/g, '%23');

  // subresource integrity is not supported in web workers
  if (isWorker)
    return workerImport(src, resolve, reject);

  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.charset = 'utf-8';
  script.async = true;

  if (crossOrigin)
    script.crossOrigin = crossOrigin;
  if (integrity)
    script.integrity = integrity;

  script.addEventListener('load', load, false);
  script.addEventListener('error', error, false);

  script.src = src;
  document.head.appendChild(script);

  function load () {
    resolve();
    cleanup();
  }

  // note this does not catch execution errors
  function error (err) {
    cleanup();
    reject(new Error('Fetching ' + src));
  }

  function cleanup () {
    for (var i = 0; i < loadingScripts.length; i++) {
      if (loadingScripts[i].err === error) {
        loadingScripts.splice(i, 1);
        break;
      }
    }
    script.removeEventListener('load', load, false);
    script.removeEventListener('error', error, false);
    document.head.removeChild(script);
  }
}

export function readMemberExpression (p, value) {
  var pParts = p.split('.');
  while (pParts.length)
    value = value[pParts.shift()];
  return value;
}

// separate out paths cache as a baseURL lock process
export function applyPaths (baseURL, paths, key) {
  var mapMatch = getMapMatch(paths, key);
  if (mapMatch) {
    var target = paths[mapMatch] + key.substr(mapMatch.length);

    var resolved = resolveIfNotPlain(target, baseURI);
    if (resolved !== undefined)
      return resolved;

    return baseURL + target;
  }
  else if (key.indexOf(':') !== -1) {
    return key;
  }
  else {
    return baseURL + key;
  }
}

function checkMap (p) {
  var name = this.name;
  // can add ':' here if we want paths to match the behaviour of map
  if (name.substr(0, p.length) === p && (name.length === p.length || name[p.length] === '/' || p[p.length - 1] === '/' || p[p.length - 1] === ':')) {
    var curLen = p.split('/').length;
    if (curLen > this.len) {
      this.match = p;
      this.len = curLen;
    }
  }
}

export function getMapMatch (map, name) {
  if (Object.hasOwnProperty.call(map, name))
    return name;

  var bestMatch = {
    name: name,
    match: undefined,
    len: 0
  };

  Object.keys(map).forEach(checkMap, bestMatch);

  return bestMatch.match;
}

// RegEx adjusted from https://github.com/jbrantly/yabble/blob/master/lib/yabble.js#L339
export var cjsRequireRegEx = /(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF."'])require\s*\(\s*("[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')\s*\)/g;
<commit_msg>update depCache preload to support safari<commit_after>import { resolveIfNotPlain } from 'es-module-loader/core/resolve.js';
import { baseURI, isBrowser, isWindows, addToError, global, createSymbol, resolvedPromise } from 'es-module-loader/core/common.js';
import RegisterLoader from 'es-module-loader/core/register-loader.js';
import { ModuleNamespace } from 'es-module-loader/core/loader-polyfill.js';

export { baseURI, isBrowser, isWindows, addToError, global, resolveIfNotPlain, ModuleNamespace, resolvedPromise }

export function noop () {};

export var emptyModule = new ModuleNamespace({});

export function protectedCreateNamespace (bindings) {
  if (bindings instanceof ModuleNamespace)
    return bindings;
  if (typeof bindings !== 'object')
    throw new TypeError('Cannot create a module namespace from an object of type "' + typeof bindings + '".');
  return new ModuleNamespace(bindings);
}

export var CONFIG = createSymbol('loader-config');
export var METADATA = createSymbol('metadata');
export var PLAIN_RESOLVE = createSymbol('plain-resolve');
export var PLAIN_RESOLVE_SYNC = createSymbol('plain-resolve-sync');

export var isWorker = typeof window === 'undefined' && typeof self !== 'undefined' && typeof importScripts !== 'undefined';

export function warn (msg, force) {
  if (force || this.warnings && typeof console !== 'undefined' && console.warn)
    console.warn(msg);
}

var parentModuleContext;
export function loadNodeModule (key, baseURL) {
  if (key[0] === '.')
    throw new Error('Node module ' + key + ' can\'t be loaded as it is not a package require.');

  if (!parentModuleContext) {
    var Module = this._nodeRequire('module');
    var base = baseURL.substr(isWindows ? 8 : 7);
    parentModuleContext = new Module(base);
    parentModuleContext.paths = Module._nodeModulePaths(base);
  }
  return parentModuleContext.require(key);
}

export function extend (a, b) {
  for (var p in b) {
    if (!Object.hasOwnProperty.call(b, p))
      continue;
    a[p] = b[p];
  }
  return a;
}

export function prepend (a, b) {
  for (var p in b) {
    if (!Object.hasOwnProperty.call(b, p))
      continue;
    if (a[p] === undefined)
      a[p] = b[p];
  }
  return a;
}

// meta first-level extends where:
// array + array appends
// object + object extends
// other properties replace
export function extendMeta (a, b, _prepend) {
  for (var p in b) {
    if (!Object.hasOwnProperty.call(b, p))
      continue;
    var val = b[p];
    if (a[p] === undefined)
      a[p] = val;
    else if (val instanceof Array && a[p] instanceof Array)
      a[p] = [].concat(_prepend ? val : a[p]).concat(_prepend ? a[p] : val);
    else if (typeof val == 'object' && val !== null && typeof a[p] == 'object')
      a[p] = (_prepend ? prepend : extend)(extend({}, a[p]), val);
    else if (!_prepend)
      a[p] = val;
  }
}

var supportsPreload = false, supportsPrefetch = false;
if (isBrowser)
  (function () {
    var relList = document.createElement('link').relList;
    if (relList && relList.supports) {
      supportsPrefetch = true;
      try {
        supportsPreload = relList.supports('preload');
      }
      catch (e) {}
    }
  })();

export function preloadScript (url) {
  // fallback to old fashioned image technique which still works in safari
  if (!supportsPreload && !supportsPrefetch) {
    var preloadImage = new Image();
    preloadImage.src = url;
    return;
  }

  var link = document.createElement('link');
  if (supportsPreload) {
    link.rel = 'preload';
    link.as = 'script';
  }
  else {
    // this works for all except Safari (detected by relList.supports lacking)
    link.rel = 'prefetch';
  }
  link.href = url;
  document.head.appendChild(link);
  document.head.removeChild(link);
}

function workerImport (src, resolve, reject) {
  try {
    importScripts(src);
  }
  catch (e) {
    reject(e);
  }
  resolve();
}

if (isBrowser) {
  var loadingScripts = [];
  var onerror = window.onerror;
  window.onerror = function globalOnerror (msg, src) {
    for (var i = 0; i < loadingScripts.length; i++) {
      if (loadingScripts[i].src !== src)
        continue;
      loadingScripts[i].err(msg);
      return;
    }
    onerror.apply(this, arguments);
  };
}

export function scriptLoad (src, crossOrigin, integrity, resolve, reject) {
  // percent encode just "#" for HTTP requests
  src = src.replace(/#/g, '%23');

  // subresource integrity is not supported in web workers
  if (isWorker)
    return workerImport(src, resolve, reject);

  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.charset = 'utf-8';
  script.async = true;

  if (crossOrigin)
    script.crossOrigin = crossOrigin;
  if (integrity)
    script.integrity = integrity;

  script.addEventListener('load', load, false);
  script.addEventListener('error', error, false);

  script.src = src;
  document.head.appendChild(script);

  function load () {
    resolve();
    cleanup();
  }

  // note this does not catch execution errors
  function error (err) {
    cleanup();
    reject(new Error('Fetching ' + src));
  }

  function cleanup () {
    for (var i = 0; i < loadingScripts.length; i++) {
      if (loadingScripts[i].err === error) {
        loadingScripts.splice(i, 1);
        break;
      }
    }
    script.removeEventListener('load', load, false);
    script.removeEventListener('error', error, false);
    document.head.removeChild(script);
  }
}

export function readMemberExpression (p, value) {
  var pParts = p.split('.');
  while (pParts.length)
    value = value[pParts.shift()];
  return value;
}

// separate out paths cache as a baseURL lock process
export function applyPaths (baseURL, paths, key) {
  var mapMatch = getMapMatch(paths, key);
  if (mapMatch) {
    var target = paths[mapMatch] + key.substr(mapMatch.length);

    var resolved = resolveIfNotPlain(target, baseURI);
    if (resolved !== undefined)
      return resolved;

    return baseURL + target;
  }
  else if (key.indexOf(':') !== -1) {
    return key;
  }
  else {
    return baseURL + key;
  }
}

function checkMap (p) {
  var name = this.name;
  // can add ':' here if we want paths to match the behaviour of map
  if (name.substr(0, p.length) === p && (name.length === p.length || name[p.length] === '/' || p[p.length - 1] === '/' || p[p.length - 1] === ':')) {
    var curLen = p.split('/').length;
    if (curLen > this.len) {
      this.match = p;
      this.len = curLen;
    }
  }
}

export function getMapMatch (map, name) {
  if (Object.hasOwnProperty.call(map, name))
    return name;

  var bestMatch = {
    name: name,
    match: undefined,
    len: 0
  };

  Object.keys(map).forEach(checkMap, bestMatch);

  return bestMatch.match;
}

// RegEx adjusted from https://github.com/jbrantly/yabble/blob/master/lib/yabble.js#L339
export var cjsRequireRegEx = /(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF."'])require\s*\(\s*("[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')\s*\)/g;
<|endoftext|>


<commit_before>// Y86 assembler
//      by mingkaidox

var need_reg = ['2', '3', '4', '5', '6', 'A', 'B'];
var need_imm = ['3', '4', '5', '7', '8'];

var icode2byte = {
    'halt'  :   '00',
    'nop'   :   '10',
    'rrmovl':   '20',
    'cmovle':   '21',
    'cmovl' :   '22',
    'cmove' :   '23',
    'cmovne':   '24',
    'cmovge':   '25',
    'cmovg' :   '26',
    'irmovl':   '30',
    'rmmovl':   '40',
    'mrmovl':   '50',
    'addl'  :   '60',
    'subl'  :   '61',
    'andl'  :   '62',
    'xorl'  :   '63',
    'jmp'   :   '70',
    'jle'   :   '71',
    'jl'    :   '72',
    'je'    :   '73',
    'jne'   :   '74',
    'jge'   :   '75',
    'jg'    :   '76',
    'call'  :   '80',
    'ret'   :   '90',
    'pushl' :   'A0',
    'popl'  :   'B0',
};

var reg2num = {
    '%eax'  :   '0',
    '%ecx'  :   '1',
    '%edx'  :   '2',
    '%ebx'  :   '3',
    '%esi'  :   '6',
    '%edi'  :   '7',
    '%esp'  :   '4',
    '%ebp'  :   '5',
}

// express imm in bytes (little-endian)
var imm2bytes = function (imm) {

    // check args
    if (undefined == imm) return null;
    if (null == imm) return null;
    if (0 == imm.length) return null;

    // check imm $
    if (imm[0] != '$') return null;
    imm = imm.substr(1);

    // check hex format
    var hex = (imm.indexOf('0x') == 0 || imm.indexOf('0X') == 0);
    if (hex) {
        // remove prefix
        imm = imm.substr(2);
    } else {
        // to hex
        imm = parseInt(imm).toString(16);
    }

    imm = ('00000000' + imm).slice(-8);
    // to litte endian
    imm = imm[6] + imm[7] + ' ' + imm[4] + imm[5] + ' '
        + imm[2] + imm[3] + ' ' + imm[0] + imm[1];
    return imm;
};

var immreg_seperator = function(immreg) {
    var imm = immreg.match(/((0x)|)\w+/gi);
    if (imm.length < 1) return [];
    if (imm[0] != '$') imm[0] = '$' + imm[0];
    imm = imm2bytes(imm[0]);
    var reg = immreg.match(/\(\%\w+\)/g);
    if (reg.length < 1) return [];
    reg = reg[0].slice(1,-1);
    reg = reg2num[reg];
    return [imm, reg];
}

var lables = {}; // store labels
var pc = 0;

var assemble_inst = function(instr) {
    if (instr.length == 0) return {addr:pc, inst: '', err:'INVALID_INST'};
    if (instr[0].length == 0) return {addr:pc, inst: '', err:'INVALID_INST'};
    if ('.pos' === instr[0]) {
        pc = parseInt(instr[1]);
        return {addr:pc, inst:''};
    }
    if (instr[0].indexOf(':') != -1) {
        var offset = instr[0].indexOf(':');
        labels[instr[0].slice(0, offset)] = pc;
        if (':' == instr[0][instr[0].length - 1]) {
            instr = instr.slice(1);
        } else {
            instr[0] = instr[0].split(':')[1];
        }
    }
    icode = icode2byte[instr[0]];
    if (undefined == icode)
        return {addr:pc, inst: '', err:'INVALID_INST'};

    var asm = icode;
    var regA = 'F';
    var regB = 'F';
    var imm = '';
    if ('40' === icode) {
        regA = reg2num[instr[1]];
        immreg = immreg_seperator(instr[2])
        if (immreg.length < 2)
            return {addr:pc, inst: '', err:'INVALID_IMMREG'};
        imm = immreg[0];
        regB = immreg[1];
    }
    if ('50' === icode) {
        regA = reg2num[instr[2]];
        immreg = immreg_seperator(instr[1])
        if (immreg.length < 2)
            return {addr:pc, inst: '', err:'INVALID_IMMREG'};
        imm = immreg[0];
        regB = immreg[1];
    }
    if (['2', '6', 'A', 'B'].indexOf(icode[0]) != -1) {
        regA = reg2num[instr[1]];
    }
    if (['2', '3', '6'].indexOf(icode[0]) != -1) {
        regB = reg2num[instr[2]];
    }
    if (['7', '8', '3'].indexOf(icode[0]) != -1) {
        if (icode[0] == '7' || icode[0] == '8') {
            if (undefined == labels[instr[1]]) {
            } else {
                //
                instr[1] = "$" + labels[instr[1]];
            }
        }
        imm = imm2bytes(instr[1]);
    }
    var pc_inc = 1;
    if (need_reg.indexOf(icode[0]) != -1) {
        asm += ' ' + regA + regB;
        pc_inc++;
    }
    if (need_imm.indexOf(icode[0]) != -1) {
        asm += ' ' + imm;
        pc_inc+=4;
    }
    var ret = {addr:pc, inst:asm};
    pc += pc_inc;
    return ret;
    //return asm;
};

var assemble = function (code) {
    //
    labels = {};
    pc = 0;

    console.log(code);
    // split
    codes = code.split('\n').map(function(e) {
        if (e.indexOf('#') != -1) {
            e = e.slice(0, e.indexOf('#'));
        }
        e = e.trim(' ');
        return e.split(/[\s,]+/);
    });
    // collect labels
    codes.map(assemble_inst);
    // process
    pc = 0;
    instrs = codes.map(assemble_inst);
    var imem = [];
    instrs.map(function(e) {
        if (undefined != e.err) return;
        var inst = e.inst.split(/\s+/).join('');
        var addr = e.addr;
        while (inst.length >= 2) {
            imem[addr] = inst.slice(0,2);
            addr += 1;
            inst = inst.slice(2);
        }
    });
    for (var i=0; i<imem.length; ++i) {
        if (undefined == imem[i]) {
            imem[i] = '00';
        }
    }
    imem = imem.join('');
    var ret = {
        imem: imem,
        instrs: instrs.map(function(e) {
            if (undefined != e.err) return '';
            return '0x' + e.addr.toString(16) + ':\t' + e.inst;
        }).join('\n')
    };
    return ret;
};
<commit_msg>add negative number support<commit_after>// Y86 assembler
//      by mingkaidox

var need_reg = ['2', '3', '4', '5', '6', 'A', 'B'];
var need_imm = ['3', '4', '5', '7', '8'];

var icode2byte = {
    'halt'  :   '00',
    'nop'   :   '10',
    'rrmovl':   '20',
    'cmovle':   '21',
    'cmovl' :   '22',
    'cmove' :   '23',
    'cmovne':   '24',
    'cmovge':   '25',
    'cmovg' :   '26',
    'irmovl':   '30',
    'rmmovl':   '40',
    'mrmovl':   '50',
    'addl'  :   '60',
    'subl'  :   '61',
    'andl'  :   '62',
    'xorl'  :   '63',
    'jmp'   :   '70',
    'jle'   :   '71',
    'jl'    :   '72',
    'je'    :   '73',
    'jne'   :   '74',
    'jge'   :   '75',
    'jg'    :   '76',
    'call'  :   '80',
    'ret'   :   '90',
    'pushl' :   'A0',
    'popl'  :   'B0',
};

var reg2num = {
    '%eax'  :   '0',
    '%ecx'  :   '1',
    '%edx'  :   '2',
    '%ebx'  :   '3',
    '%esi'  :   '6',
    '%edi'  :   '7',
    '%esp'  :   '4',
    '%ebp'  :   '5',
}

// express imm in bytes (little-endian)
var imm2bytes = function (imm) {

    // check args
    if (undefined == imm) return null;
    if (null == imm) return null;
    if (0 == imm.length) return null;

    // check imm $
    if (imm[0] != '$') return null;
    imm = imm.substr(1);

    var neg = false;
    if (imm[0] == '-') {
        neg = true;
        imm = imm.substr(1);
    }

    // check hex format
    var hex = (imm.indexOf('0x') == 0 || imm.indexOf('0X') == 0);
    if (hex) {
        // remove prefix
        imm = imm.substr(2);
    } else {
        // to hex
        imm = parseInt(imm).toString(16);
    }
    if (neg) {
        imm = (0x100000000 - parseInt(imm, 16)).toString(16);
    }

    imm = ('00000000' + imm).slice(-8);
    // to litte endian
    imm = imm[6] + imm[7] + ' ' + imm[4] + imm[5] + ' '
        + imm[2] + imm[3] + ' ' + imm[0] + imm[1];
    return imm;
};

var immreg_seperator = function(immreg) {
    var imm = immreg.match(/((0x)|)\w+/gi);
    if (imm.length < 1) return [];
    if (imm[0] != '$') imm[0] = '$' + imm[0];
    imm = imm2bytes(imm[0]);
    var reg = immreg.match(/\(\%\w+\)/g);
    if (reg.length < 1) return [];
    reg = reg[0].slice(1,-1);
    reg = reg2num[reg];
    return [imm, reg];
}

var lables = {}; // store labels
var pc = 0;

var assemble_inst = function(instr) {
    if (instr.length == 0) return {addr:pc, inst: '', err:'INVALID_INST'};
    if (instr[0].length == 0) return {addr:pc, inst: '', err:'INVALID_INST'};
    if ('.pos' === instr[0]) {
        pc = parseInt(instr[1]);
        return {addr:pc, inst:''};
    }
    if (instr[0].indexOf(':') != -1) {
        var offset = instr[0].indexOf(':');
        labels[instr[0].slice(0, offset)] = pc;
        if (':' == instr[0][instr[0].length - 1]) {
            instr = instr.slice(1);
        } else {
            instr[0] = instr[0].split(':')[1];
        }
    }
    icode = icode2byte[instr[0]];
    if (undefined == icode)
        return {addr:pc, inst: '', err:'INVALID_INST'};

    var asm = icode;
    var regA = 'F';
    var regB = 'F';
    var imm = '';
    if ('40' === icode) {
        regA = reg2num[instr[1]];
        immreg = immreg_seperator(instr[2])
        if (immreg.length < 2)
            return {addr:pc, inst: '', err:'INVALID_IMMREG'};
        imm = immreg[0];
        regB = immreg[1];
    }
    if ('50' === icode) {
        regA = reg2num[instr[2]];
        immreg = immreg_seperator(instr[1])
        if (immreg.length < 2)
            return {addr:pc, inst: '', err:'INVALID_IMMREG'};
        imm = immreg[0];
        regB = immreg[1];
    }
    if (['2', '6', 'A', 'B'].indexOf(icode[0]) != -1) {
        regA = reg2num[instr[1]];
    }
    if (['2', '3', '6'].indexOf(icode[0]) != -1) {
        regB = reg2num[instr[2]];
    }
    if (['7', '8', '3'].indexOf(icode[0]) != -1) {
        if (icode[0] == '7' || icode[0] == '8') {
            if (undefined == labels[instr[1]]) {
            } else {
                //
                instr[1] = "$" + labels[instr[1]];
            }
        }
        imm = imm2bytes(instr[1]);
    }
    var pc_inc = 1;
    if (need_reg.indexOf(icode[0]) != -1) {
        asm += ' ' + regA + regB;
        pc_inc++;
    }
    if (need_imm.indexOf(icode[0]) != -1) {
        asm += ' ' + imm;
        pc_inc+=4;
    }
    var ret = {addr:pc, inst:asm};
    pc += pc_inc;
    return ret;
    //return asm;
};

var assemble = function (code) {
    //
    labels = {};
    pc = 0;

    console.log(code);
    // split
    codes = code.split('\n').map(function(e) {
        if (e.indexOf('#') != -1) {
            e = e.slice(0, e.indexOf('#'));
        }
        e = e.trim(' ');
        return e.split(/[\s,]+/);
    });
    // collect labels
    codes.map(assemble_inst);
    // process
    pc = 0;
    instrs = codes.map(assemble_inst);
    var imem = [];
    instrs.map(function(e) {
        if (undefined != e.err) return;
        var inst = e.inst.split(/\s+/).join('');
        var addr = e.addr;
        while (inst.length >= 2) {
            imem[addr] = inst.slice(0,2);
            addr += 1;
            inst = inst.slice(2);
        }
    });
    for (var i=0; i<imem.length; ++i) {
        if (undefined == imem[i]) {
            imem[i] = '00';
        }
    }
    imem = imem.join('');
    var ret = {
        imem: imem,
        instrs: instrs.map(function(e) {
            if (undefined != e.err) return '';
            return '0x' + e.addr.toString(16) + ':\t' + e.inst;
        }).join('\n')
    };
    return ret;
};
<|endoftext|>


<commit_before>//deps includes.js

function BarStyle(attrs) {
  EventEmitter.call(this);

  this._colorScheme = attrs.colorScheme;
  this._leftMargin = attrs.leftMargin;
  this._rightMargin = attrs.rightMargin;
  this._barSpacing = attrs.barSpacing;
  this._barWidth = attrs.barWidth;
  this._stretchMode = attrs.stretchMode || BarStyle.STRETCH_MODE_JUSTIFY_RIGHT;
  this._xLabelAlignment = attrs.xLabelAlignment || BarStyle.X_LABELS_LEFT;

  this._colorScheme.on('change', this.emit.bind('superficialChange'));
}

BarStyle.STRETCH_MODE_JUSTIFY_RIGHT = 0;
BarStyle.STRETCH_MODE_JUSTIFY_LEFT = 1;

BarStyle.X_LABELS_LEFT = 0;
BarStyle.X_LABELS_CENTER = 1;
BarStyle.X_LABELS_RIGHT = 2;

BarStyle.prototype = Object.create(EventEmitter.prototype);

BarStyle.prototype.computeRange = function(region, pointCount) {
  var startIndex = Math.floor((region.left - this.getLeftMargin()) /
    (this.getBarSpacing() + this.getBarWidth()));
  var endIndex = Math.ceil((region.left + region.width - this.getLeftMargin()) /
    (this.getBarSpacing() + this.getBarWidth()));

  return {
    startIndex: Math.max(0, Math.min(pointCount-1, startIndex)),
    length: Math.max(0, Math.min(length, endIndex - startIndex))
  };
};

BarStyle.prototype.computeRegion = function(range, pointCount) {
  var maxLeft = this.getLeftMargin() + this.getRightMargin() + pointCount*this.getBarWidth() +
    Math.max(0, (pointCount-1)*this.getBarSpacing());

  var startLeft = 0;
  if (range.startIndex >= pointCount - 1) {
    startLeft = maxLeft;
  } else if (range.startIndex > 0) {
    startLeft = (this.getBarSpacing()+this.getBarWidth())*range.startIndex + this.getLeftMargin();
  }

  var endLeft = 0;
  var endIndex = range.startIndex + range.length - 1;
  if (endIndex >= pointCount-1) {
    endLeft = maxLeft;
  } else if (endIndex > 0) {
    endLeft = (this.getBarSpacing()+this.getBarWidth())*range.startIndex + this.getLeftMargin();
  }

  assert(startLeft <= endLeft);

  return {left: startLeft, width: endLeft-startLeft};
};

BarStyle.prototype.xLabelPosition = function(pointIndex, pointCount) {
  var barLeft = this.getLeftSpacing() + (this.getBarWidth()+this.getBarSpacing())*pointIndex;
  switch (this.getXLabelAlignment()) {
  case BarStyle.X_LABELS_LEFT:
    if (pointIndex === 0) {
      return this.getLeftMargin() / 2;
    } else {
      return barLeft - this.getBarSpacing()/2;
    }
    break;
  case BarStyle.X_LABELS_RIGHT:
    if (pointIndex === pointCount-1) {
      var fullWidth = this.computeRegion({startIndex: 0, length: pointCount}, pointCount).width;
      return fullWidth - (this.getRightMargin() / 2);
    } else {
      return barLeft + this.getBarWidth() + this.getBarSpacing()/2;
    }
    break;
  case BarStyle.X_LABELS_CENTER:
    return barLeft + (this.getBarWidth() / 2);
    break;
  default:
    throw new Error('unknown xLabelAlignment: ' + this.getXLabelAlignment());
  }
};

BarStyle.prototype.getColorScheme = function() {
  return this._colorScheme;
};

BarStyle.prototype.getLeftMargin = function() {
  return this._leftMargin;
};

BarStyle.prototype.getRightMargin = function() {
  return this._rightMargin;
};

BarStyle.prototype.getBarSpacing = function() {
  return this._barSpacing;
};

BarStyle.prototype.getBarWidth = function() {
  return this._barWidth;
};

BarStyle.prototype.getStretchMode = function() {
  return this._stretchMode;
};

BarStyle.prototype.getXLabelAlignment = function() {
  return this._xLabelAlignment;
};

BarStyle.prototype.setAttributes = function(attrs) {
  var allKeys = ['leftMargin', 'rightMargin', 'barSpacing', 'barWidth', 'stretchMode',
    'xLabelAlignment'];
  for (var i = 0, len = allKeys.length; i < len; ++i) {
    var key = allKeys[i];
    if (attrs.hasOwnProperty(key)) {
      this['_' + key] = attrs[key];
    }
  }
  this.emit('metricChange');
};

exports.BarStyle = BarStyle;
<commit_msg>BarStyle: moved attribute management to BarStyleAttrs<commit_after>//deps includes.js

function BarStyleAttrs(attrs) {
  this._colorScheme = attrs.colorScheme;
  this._leftMargin = attrs.leftMargin;
  this._rightMargin = attrs.rightMargin;
  this._barSpacing = attrs.barSpacing;
  this._barWidth = attrs.barWidth;
  this._stretchMode = attrs.stretchMode || BarStyleAttrs.STRETCH_MODE_JUSTIFY_RIGHT;
  this._xLabelAlignment = attrs.xLabelAlignment || BarStyleAttrs.X_LABELS_LEFT;
}

BarStyleAttrs.STRETCH_MODE_JUSTIFY_RIGHT = 0;
BarStyleAttrs.STRETCH_MODE_JUSTIFY_LEFT = 1;

BarStyleAttrs.X_LABELS_LEFT = 0;
BarStyleAttrs.X_LABELS_CENTER = 1;
BarStyleAttrs.X_LABELS_RIGHT = 2;

BarStyleAttrs.prototype.copyAttributes = function() {
  return new BarStyleAttrs({
    colorScheme: this.getColorScheme(),
    leftMargin: this.getLeftMargin(),
    rightMargin: this.getRightMargin(),
    barSpacing: this.getBarSpacing(),
    barWidth: this.getBarWidth(),
    stretchMode: this.getStretchMode(),
    xLabelAlignment: this.getXLabelAlignment()
  });
};

BarStyleAttrs.prototype.getColorScheme = function() {
  return this._colorScheme;
};

BarStyleAttrs.prototype.getLeftMargin = function() {
  return this._leftMargin;
};

BarStyleAttrs.prototype.getRightMargin = function() {
  return this._rightMargin;
};

BarStyleAttrs.prototype.getBarSpacing = function() {
  return this._barSpacing;
};

BarStyleAttrs.prototype.getBarWidth = function() {
  return this._barWidth;
};

BarStyleAttrs.prototype.getStretchMode = function() {
  return this._stretchMode;
};

BarStyleAttrs.prototype.getXLabelAlignment = function() {
  return this._xLabelAlignment;
};

BarStyleAttrs.prototype.computeRange = function(region, pointCount) {
  var startIndex = Math.floor((region.left - this.getLeftMargin()) /
    (this.getBarSpacing() + this.getBarWidth()));
  var endIndex = Math.ceil((region.left + region.width - this.getLeftMargin()) /
    (this.getBarSpacing() + this.getBarWidth()));

  return {
    startIndex: Math.max(0, Math.min(pointCount-1, startIndex)),
    length: Math.max(0, Math.min(length, endIndex - startIndex))
  };
};

BarStyleAttrs.prototype.computeRegion = function(range, pointCount) {
  var maxLeft = this.getLeftMargin() + this.getRightMargin() + pointCount*this.getBarWidth() +
    Math.max(0, (pointCount-1)*this.getBarSpacing());

  var startLeft = 0;
  if (range.startIndex >= pointCount - 1) {
    startLeft = maxLeft;
  } else if (range.startIndex > 0) {
    startLeft = (this.getBarSpacing()+this.getBarWidth())*range.startIndex + this.getLeftMargin();
  }

  var endLeft = 0;
  var endIndex = range.startIndex + range.length - 1;
  if (endIndex >= pointCount-1) {
    endLeft = maxLeft;
  } else if (endIndex > 0) {
    endLeft = (this.getBarSpacing()+this.getBarWidth())*range.startIndex + this.getLeftMargin();
  }

  assert(startLeft <= endLeft);

  return {left: startLeft, width: endLeft-startLeft};
};

BarStyleAttrs.prototype.xLabelPosition = function(pointIndex, pointCount) {
  var barLeft = this.getLeftSpacing() + (this.getBarWidth()+this.getBarSpacing())*pointIndex;
  switch (this.getXLabelAlignment()) {
  case BarStyleAttrs.X_LABELS_LEFT:
    if (pointIndex === 0) {
      return this.getLeftMargin() / 2;
    } else {
      return barLeft - this.getBarSpacing()/2;
    }
    break;
  case BarStyleAttrs.X_LABELS_RIGHT:
    if (pointIndex === pointCount-1) {
      var fullWidth = this.computeRegion({startIndex: 0, length: pointCount}, pointCount).width;
      return fullWidth - (this.getRightMargin() / 2);
    } else {
      return barLeft + this.getBarWidth() + this.getBarSpacing()/2;
    }
    break;
  case BarStyleAttrs.X_LABELS_CENTER:
    return barLeft + (this.getBarWidth() / 2);
    break;
  default:
    throw new Error('unknown xLabelAlignment: ' + this.getXLabelAlignment());
  }
};

function BarStyle(attrs) {
  EventEmitter.call(this);
  BarStyleAttrs.call(this, attrs);

  this.getColorScheme().on('change', this.emit.bind('superficialChange'));
}

BarStyle.prototype = Object.create(EventEmitter.prototype);

// Inheret from BarStyleAttrs as well as EventEmitter.
for (var attr in BarStyleAttrs.prototype) {
  if (BarStyleAttrs.prototype.hasOwnProperty(attr)) {
    BarStyle.prototype[attr] = BarStyleAttrs.prototype[attr];
  }
}

BarStyle.prototype.setAttributes = function(attrs) {
  var allKeys = ['leftMargin', 'rightMargin', 'barSpacing', 'barWidth', 'stretchMode',
    'xLabelAlignment'];
  for (var i = 0, len = allKeys.length; i < len; ++i) {
    var key = allKeys[i];
    if (attrs.hasOwnProperty(key)) {
      this['_' + key] = attrs[key];
    }
  }
  this.emit('metricChange');
};

exports.BarStyle = BarStyle;
<|endoftext|>


<commit_before>
var ReportModule = (function () {

    function ReportConfig(report_id, display, availableReportIds, language) {
        var self = this;
        this.lang = language;
        this.fullDisplay = display || {};
        this.availableReportIds = availableReportIds;
        this.display = ko.observable(this.fullDisplay[this.lang]);
        this.reportId = ko.observable(report_id);
        this.toJSON = function () {
            self.fullDisplay[self.lang] = self.display();
            return {
                report_id: self.reportId(),
                header: self.fullDisplay
            };
        };
    }
    function ReportModule(options) {
        var self = this;
        var currentReports = options.currentReports || [];
        var availableReports = options.availableReports || [];
        var saveURL = options.saveURL;
        self.lang = options.lang;
        self.moduleName = options.moduleName;
        self.currentModuleName = ko.observable(options.moduleName[self.lang]);
        self.reportTitles = {};
        self.reports = ko.observableArray([]);
        for (var i = 0; i < availableReports.length; i++) {
            self.reportTitles[availableReports[i].report_id] = availableReports[i].title;
        }
        self.availableReportIds = _.map(options.availableReports, function (r) { return r.report_id; });

        self.defaultReportTitle = function (reportId) {
            return self.reportTitles[reportId];
        };

        self.saveButton = COMMCAREHQ.SaveButton.init({
            unsavedMessage: "You have unsaved changes in your report list module",
            save: function () {
                // validate that all reports have valid data
                var reports = self.reports();
                for (var i = 0; i < reports.length; i++) {
                    if (!reports[i].reportId() || !reports[i].display()) {
                        alert('Reports must have all properties set!');
                    }
                }
                self.moduleName[self.lang] = self.currentModuleName();
                self.saveButton.ajax({
                    url: saveURL,
                    type: 'post',
                    dataType: 'json',
                    data: {
                        name: JSON.stringify(self.moduleName),
                        reports: JSON.stringify(_.map(self.reports(), function (r) { return r.toJSON(); }))
                    }
                });
            }
        });

        var changeSaveButton = function () {
            self.saveButton.fire('change');
        };

        self.currentModuleName.subscribe(changeSaveButton);

        function newReport(options) {
            options = options || {};
            var report = new ReportConfig(options.report_id, options.header, self.availableReportIds, self.lang);
            report.display.subscribe(changeSaveButton);
            report.reportId.subscribe(changeSaveButton);
            report.reportId.subscribe(function (reportId) {
                report.display(self.defaultReportTitle(reportId));
            });

            return report;
        }
        this.addReport = function () {
            self.reports.push(newReport());
        };
        this.removeReport = function (report) {
            self.reports.remove(report);
            changeSaveButton();
        };

        // add exiting reports to UI
        for (i = 0; i < currentReports.length; i += 1) {
            var report = newReport(currentReports[i]);
            self.reports.push(report);
        }
    }

    return ReportModule;
}());
<commit_msg>store chart structure in ReportConfig in js<commit_after>
var ReportModule = (function () {

    function ReportConfig(report_id, display, availableReportIds, reportCharts, language) {
        var self = this;
        this.lang = language;
        this.fullDisplay = display || {};
        this.availableReportIds = availableReportIds;
        this.reportCharts = JSON.parse(JSON.stringify(reportCharts || {}));
        this.display = ko.observable(this.fullDisplay[this.lang]);
        this.reportId = ko.observable(report_id);
        this.toJSON = function () {
            self.fullDisplay[self.lang] = self.display();
            return {
                report_id: self.reportId(),
                header: self.fullDisplay
            };
        };
        this.charts = ko.computed(function() {
            return self.reportCharts[self.reportId()];
        });
    }
    function ReportModule(options) {
        var self = this;
        var currentReports = options.currentReports || [];
        var availableReports = options.availableReports || [];
        var saveURL = options.saveURL;
        self.lang = options.lang;
        self.moduleName = options.moduleName;
        self.currentModuleName = ko.observable(options.moduleName[self.lang]);
        self.reportTitles = {};
        self.reportCharts = {};
        self.reports = ko.observableArray([]);
        for (var i = 0; i < availableReports.length; i++) {
            var report = availableReports[i];
            var report_id = report.report_id;
            self.reportTitles[report_id] = report.title;
            self.reportCharts[report_id] = report.charts;
        }

        self.availableReportIds = _.map(options.availableReports, function (r) { return r.report_id; });

        self.defaultReportTitle = function (reportId) {
            return self.reportTitles[reportId];
        };

        self.saveButton = COMMCAREHQ.SaveButton.init({
            unsavedMessage: "You have unsaved changes in your report list module",
            save: function () {
                // validate that all reports have valid data
                var reports = self.reports();
                for (var i = 0; i < reports.length; i++) {
                    if (!reports[i].reportId() || !reports[i].display()) {
                        alert('Reports must have all properties set!');
                    }
                }
                self.moduleName[self.lang] = self.currentModuleName();
                self.saveButton.ajax({
                    url: saveURL,
                    type: 'post',
                    dataType: 'json',
                    data: {
                        name: JSON.stringify(self.moduleName),
                        reports: JSON.stringify(_.map(self.reports(), function (r) { return r.toJSON(); }))
                    }
                });
            }
        });

        var changeSaveButton = function () {
            self.saveButton.fire('change');
        };

        self.currentModuleName.subscribe(changeSaveButton);

        function newReport(options) {
            options = options || {};
            var report = new ReportConfig(
                options.report_id,
                options.header,
                self.availableReportIds,
                self.reportCharts,
                self.lang
            );
            report.display.subscribe(changeSaveButton);
            report.reportId.subscribe(changeSaveButton);
            report.reportId.subscribe(function (reportId) {
                report.display(self.defaultReportTitle(reportId));
            });

            return report;
        }
        this.addReport = function () {
            self.reports.push(newReport());
        };
        this.removeReport = function (report) {
            self.reports.remove(report);
            changeSaveButton();
        };

        // add exiting reports to UI
        for (i = 0; i < currentReports.length; i += 1) {
            var report = newReport(currentReports[i]);
            self.reports.push(report);
        }
    }

    return ReportModule;
}());
<|endoftext|>


<commit_before>/**
 * A table view row that can add an arbitrary number of data entry rows
 *
 * @package   Swat
 * @copyright 2004-2007 silverorange
 * @license   http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
 */

/**
 * A table view row that can add an arbitrary number of data entry rows
 *
 * @param String id the identifier of this row.
 * @param String row_string the XML string to use when inserting a new row. The
 *                           XML string can contain '%s' placeholders. Before
 *                           a new row is added, the placeholders are replaced
 *                           with the new row index.
 */
function SwatTableViewInputRow(id, row_string)
{
	this.id = id;

	// decode string
	row_string = row_string.replace(/</g, '<').replace(/>/g, '>');
	row_string = row_string.replace(/"/g, '"').replace(/&/g, '&');

	/*
	 * Pack row string in an XHTML document
	 *
	 * We purposly do not specify a DTD here as Internet Explorer is too slow
	 * when given a DTD. The XML string is encoded in UTF-8 with no special
	 * entities at this point.
	 */
	this.row_string = "<?xml version='1.0' encoding='UTF-8'?>\n" +
		'' +
		'<title>row</title>
' +
		row_string +
		'
';

	this.enter_row = document.getElementById(this.id + '_enter_row');

	// get table node belonging to the enter row
	this.table = this.enter_row;
	while (this.table.nodeName.toLowerCase() != 'table')
		this.table = this.table.parentNode;

	this.replicators = null;
	this.replicators_input = null;
}

/**
 * Check if the browser is Safari
 *
 * Safari's DOM importNode() method is broken so we use the IE table object
 * model hack for it as well.
 *
 * @var boolean
 */
SwatTableViewInputRow.is_webkit =
	(/AppleWebKit|Konqueror|KHTML/gi).test(navigator.userAgent);

/**
 * Gets an XML parser with a loadXML() method
 */
function SwatTableViewInputRow_getXMLParser()
{
	var parser = null;
	var is_ie = true;

	try {
		var dom = new ActiveXObject('Msxml2.XMLDOM');
	} catch (err1) {
		try {
			var dom = new ActiveXObject('Microsoft.XMLDOM');
		} catch (err2) {
			is_ie = false;
		}
	}

	if (is_ie) {
		/*
		 * Internet Explorer's XMLDOM object has a proprietary loadXML()
		 * method. Our method returns the document.
		 */
		parser = function() {}
		parser.loadXML = function(document_string)
		{
			if (!dom.loadXML(document_string))
				alert(dom.parseError.reason);

			return dom;
		}
	}

	if (parser === null && typeof DOMParser != 'undefined') {
		/*
		 * Mozilla, Safari and Opera have a proprietary DOMParser()
		 * class.
		 */
		dom_parser = new DOMParser();

		// Cannot add loadXML method to a newly created DOMParser because it
		// crashes Safari
		parser = function() {}
		parser.loadXML = function(document_string)
		{
			return dom_parser.parseFromString(document_string, 'text/xml');
		}
	}

	return parser;
}

/**
 * The XML parser used by this widget
 *
 * @var Object
 */
SwatTableViewInputRow.parser = SwatTableViewInputRow_getXMLParser();

/*
 * If the browser does not support the importNode() method then we need to
 * manually copy nodes from one document to the current document. These methods
 * parse a HTMLTableRowNode in one document into a table row in this document.
 */
if (!document.importNode || SwatTableViewInputRow.is_webkit) {

	/**
	 * Parses a table row from one document into another
	 *
	 * Internet Explorer does not allow writing to the innerHTML property for
	 * table row nodes so the table cells are individually inserted and cloned.
	 *
	 * @param HTMLTableRowNode source_tr the table row from the source document.
	 * @param HTMLTableRowNode dest_tr the table row in the destination
	 *                                  document.
	 */
	function SwatTableViewInputRow_parseTableRow(source_tr, dest_tr)
	{
		var child_node;
		var dest_td;
		for (var i = 0; i < source_tr.childNodes.length; i++) {
			child_node = source_tr.childNodes[i];
			if (child_node.nodeType == 1 && child_node.nodeName == 'td') {
				dest_td = dest_tr.insertCell(-1);
				source_attributes = child_node.attributes;
				for (var j = 0; j < source_attributes.length; j++) {
					if (source_attributes[j].name == 'class') {
						dest_td.className = source_attributes[j].value;
					} else {
						dest_td.setAttribute(source_attributes[j].name,
							source_attributes[j].value);
					}
				}
				SwatTableViewInputRow_parseTableCell(child_node, dest_td);
			}
		}
	}

	/**
	 * Parses a table cell from one document into another
	 *
	 * @param HTMLTableRowNode source_td the table cell from the source
	 *                                    document.
	 * @param HTMLTableRowNode dest_td the table cell in the destination
	 *                                  document.
	 */
	function SwatTableViewInputRow_parseTableCell(source_td, dest_td)
	{
		// Internet Explorer does not have an innerHTML property set on
		// imported DOM nodes even if the imported document is XHTML.
		if (source_td.innerHTML)
			dest_td.innerHTML = source_td.innerHTML;
		else
			dest_td.innerHTML = source_td.xml;
	}
}

/**
 * Initializes the replicator array
 *
 * @return boolean true if the replicators were successfully initialized and
 *          false if they were not.
 */
SwatTableViewInputRow.prototype.initReplicators = function()
{
	if (this.replicators === null) {
		this.replicators_input = document.getElementsByName(this.id +
			'_replicators')[0];

		if (this.replicators_input === null)
			return false;

		if (this.replicators_input.value == "")
			this.replicators = [];
		else
			this.replicators = this.replicators_input.value.split(',');
	}
	return true;
}

/**
 * Adds a new data row to the table
 */
SwatTableViewInputRow.prototype.addRow = function()
{
	if (!this.initReplicators())
		return;

	var replicator_id;
	if (this.replicators.length > 0)
		replicator_id = (parseInt(
			this.replicators[this.replicators.length - 1]) + 1).toString();
	else
		replicator_id = '0';

	this.replicators.push(replicator_id);
	this.replicators_input.value = this.replicators.join(',');

	var document_string = this.row_string.replace(/%s/g, replicator_id);
	var dom = SwatTableViewInputRow.parser.loadXML(document_string);
	var source_tr = dom.documentElement.getElementsByTagName('tr')[0];

	if (document.importNode && !SwatTableViewInputRow.is_webkit) {
		var dest_tr = document.importNode(source_tr, true);
		this.enter_row.parentNode.insertBefore(dest_tr, this.enter_row);
	} else {
		/*
		 * Internet Explorer and Safari specific code
		 *
		 * Uses the table object model instead of the DOM. IE does not
		 * implement importNode() and Safari's importNode() implementation is
		 * broken.
		 */
		var dest_tr = this.table.insertRow(this.enter_row.rowIndex);
		SwatTableViewInputRow_parseTableRow(source_tr, dest_tr);
	}

	dest_tr.className = 'swat-table-view-input-row';
	dest_tr.id = this.id + '_row_' + replicator_id;

	var animation = new YAHOO.util.ColorAnim(dest_tr,
		{ backgroundColor: { from: '#fffbc9', to: '#ffffff' } }, 1,
		YAHOO.util.Easing.easeOut);

	animation.animate();

	/*
	 * Run scripts
	 *
	 * A better way to do this might be to remove the script nodes from the
	 * document and then run the scripts. This way we can ensure the scripts
	 * are only run once.
	 */
	var scripts = dom.documentElement.getElementsByTagName('script');
	for (var i = 0; i < scripts.length; i++)
		if (scripts[0].getAttribute('type') == 'text/javascript' &&
			scripts[0].childNodes.length > 0)
				eval(scripts[i].firstChild.nodeValue);
}

/**
 * Removes a data row from the table
 */
SwatTableViewInputRow.prototype.removeRow = function(replicator_id)
{
	if (!this.initReplicators())
		return;

	// remove replicator_id from replicators array
	var replicator_index = -1;
	for (var i = 0; i < this.replicators.length; i++) {
		if (this.replicators[i] == replicator_id) {
			replicator_index = i;
			break;
		}
	}
	if (replicator_index != -1) {
		this.replicators.splice(replicator_index, 1);
		this.replicators_input.value = this.replicators.join(',');
	}

	// remove row from document
	var row_id = this.id + '_row_' + replicator_id;
	var row = document.getElementById(row_id);
	if (row && row.parentNode !== null) {
		var removed_row = row.parentNode.removeChild(row);
		delete removed_row;
	}
}
<commit_msg>single instead of double quotes<commit_after>/**
 * A table view row that can add an arbitrary number of data entry rows
 *
 * @package   Swat
 * @copyright 2004-2007 silverorange
 * @license   http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
 */

/**
 * A table view row that can add an arbitrary number of data entry rows
 *
 * @param String id the identifier of this row.
 * @param String row_string the XML string to use when inserting a new row. The
 *                           XML string can contain '%s' placeholders. Before
 *                           a new row is added, the placeholders are replaced
 *                           with the new row index.
 */
function SwatTableViewInputRow(id, row_string)
{
	this.id = id;

	// decode string
	row_string = row_string.replace(/</g, '<').replace(/>/g, '>');
	row_string = row_string.replace(/"/g, '"').replace(/&/g, '&');

	/*
	 * Pack row string in an XHTML document
	 *
	 * We purposly do not specify a DTD here as Internet Explorer is too slow
	 * when given a DTD. The XML string is encoded in UTF-8 with no special
	 * entities at this point.
	 */
	this.row_string = "<?xml version='1.0' encoding='UTF-8'?>\n" +
		'' +
		'<title>row</title>
' +
		row_string +
		'
';

	this.enter_row = document.getElementById(this.id + '_enter_row');

	// get table node belonging to the enter row
	this.table = this.enter_row;
	while (this.table.nodeName.toLowerCase() != 'table')
		this.table = this.table.parentNode;

	this.replicators = null;
	this.replicators_input = null;
}

/**
 * Check if the browser is Safari
 *
 * Safari's DOM importNode() method is broken so we use the IE table object
 * model hack for it as well.
 *
 * @var boolean
 */
SwatTableViewInputRow.is_webkit =
	(/AppleWebKit|Konqueror|KHTML/gi).test(navigator.userAgent);

/**
 * Gets an XML parser with a loadXML() method
 */
function SwatTableViewInputRow_getXMLParser()
{
	var parser = null;
	var is_ie = true;

	try {
		var dom = new ActiveXObject('Msxml2.XMLDOM');
	} catch (err1) {
		try {
			var dom = new ActiveXObject('Microsoft.XMLDOM');
		} catch (err2) {
			is_ie = false;
		}
	}

	if (is_ie) {
		/*
		 * Internet Explorer's XMLDOM object has a proprietary loadXML()
		 * method. Our method returns the document.
		 */
		parser = function() {}
		parser.loadXML = function(document_string)
		{
			if (!dom.loadXML(document_string))
				alert(dom.parseError.reason);

			return dom;
		}
	}

	if (parser === null && typeof DOMParser != 'undefined') {
		/*
		 * Mozilla, Safari and Opera have a proprietary DOMParser()
		 * class.
		 */
		dom_parser = new DOMParser();

		// Cannot add loadXML method to a newly created DOMParser because it
		// crashes Safari
		parser = function() {}
		parser.loadXML = function(document_string)
		{
			return dom_parser.parseFromString(document_string, 'text/xml');
		}
	}

	return parser;
}

/**
 * The XML parser used by this widget
 *
 * @var Object
 */
SwatTableViewInputRow.parser = SwatTableViewInputRow_getXMLParser();

/*
 * If the browser does not support the importNode() method then we need to
 * manually copy nodes from one document to the current document. These methods
 * parse a HTMLTableRowNode in one document into a table row in this document.
 */
if (!document.importNode || SwatTableViewInputRow.is_webkit) {

	/**
	 * Parses a table row from one document into another
	 *
	 * Internet Explorer does not allow writing to the innerHTML property for
	 * table row nodes so the table cells are individually inserted and cloned.
	 *
	 * @param HTMLTableRowNode source_tr the table row from the source document.
	 * @param HTMLTableRowNode dest_tr the table row in the destination
	 *                                  document.
	 */
	function SwatTableViewInputRow_parseTableRow(source_tr, dest_tr)
	{
		var child_node;
		var dest_td;
		for (var i = 0; i < source_tr.childNodes.length; i++) {
			child_node = source_tr.childNodes[i];
			if (child_node.nodeType == 1 && child_node.nodeName == 'td') {
				dest_td = dest_tr.insertCell(-1);
				source_attributes = child_node.attributes;
				for (var j = 0; j < source_attributes.length; j++) {
					if (source_attributes[j].name == 'class') {
						dest_td.className = source_attributes[j].value;
					} else {
						dest_td.setAttribute(source_attributes[j].name,
							source_attributes[j].value);
					}
				}
				SwatTableViewInputRow_parseTableCell(child_node, dest_td);
			}
		}
	}

	/**
	 * Parses a table cell from one document into another
	 *
	 * @param HTMLTableRowNode source_td the table cell from the source
	 *                                    document.
	 * @param HTMLTableRowNode dest_td the table cell in the destination
	 *                                  document.
	 */
	function SwatTableViewInputRow_parseTableCell(source_td, dest_td)
	{
		// Internet Explorer does not have an innerHTML property set on
		// imported DOM nodes even if the imported document is XHTML.
		if (source_td.innerHTML)
			dest_td.innerHTML = source_td.innerHTML;
		else
			dest_td.innerHTML = source_td.xml;
	}
}

/**
 * Initializes the replicator array
 *
 * @return boolean true if the replicators were successfully initialized and
 *          false if they were not.
 */
SwatTableViewInputRow.prototype.initReplicators = function()
{
	if (this.replicators === null) {
		this.replicators_input = document.getElementsByName(this.id +
			'_replicators')[0];

		if (this.replicators_input === null)
			return false;

		if (this.replicators_input.value == '')
			this.replicators = [];
		else
			this.replicators = this.replicators_input.value.split(',');
	}
	return true;
}

/**
 * Adds a new data row to the table
 */
SwatTableViewInputRow.prototype.addRow = function()
{
	if (!this.initReplicators())
		return;

	var replicator_id;
	if (this.replicators.length > 0)
		replicator_id = (parseInt(
			this.replicators[this.replicators.length - 1]) + 1).toString();
	else
		replicator_id = '0';

	this.replicators.push(replicator_id);
	this.replicators_input.value = this.replicators.join(',');

	var document_string = this.row_string.replace(/%s/g, replicator_id);
	var dom = SwatTableViewInputRow.parser.loadXML(document_string);
	var source_tr = dom.documentElement.getElementsByTagName('tr')[0];

	if (document.importNode && !SwatTableViewInputRow.is_webkit) {
		var dest_tr = document.importNode(source_tr, true);
		this.enter_row.parentNode.insertBefore(dest_tr, this.enter_row);
	} else {
		/*
		 * Internet Explorer and Safari specific code
		 *
		 * Uses the table object model instead of the DOM. IE does not
		 * implement importNode() and Safari's importNode() implementation is
		 * broken.
		 */
		var dest_tr = this.table.insertRow(this.enter_row.rowIndex);
		SwatTableViewInputRow_parseTableRow(source_tr, dest_tr);
	}

	dest_tr.className = 'swat-table-view-input-row';
	dest_tr.id = this.id + '_row_' + replicator_id;

	var animation = new YAHOO.util.ColorAnim(dest_tr,
		{ backgroundColor: { from: '#fffbc9', to: '#ffffff' } }, 1,
		YAHOO.util.Easing.easeOut);

	animation.animate();

	/*
	 * Run scripts
	 *
	 * A better way to do this might be to remove the script nodes from the
	 * document and then run the scripts. This way we can ensure the scripts
	 * are only run once.
	 */
	var scripts = dom.documentElement.getElementsByTagName('script');
	for (var i = 0; i < scripts.length; i++)
		if (scripts[0].getAttribute('type') == 'text/javascript' &&
			scripts[0].childNodes.length > 0)
				eval(scripts[i].firstChild.nodeValue);
}

/**
 * Removes a data row from the table
 */
SwatTableViewInputRow.prototype.removeRow = function(replicator_id)
{
	if (!this.initReplicators())
		return;

	// remove replicator_id from replicators array
	var replicator_index = -1;
	for (var i = 0; i < this.replicators.length; i++) {
		if (this.replicators[i] == replicator_id) {
			replicator_index = i;
			break;
		}
	}
	if (replicator_index != -1) {
		this.replicators.splice(replicator_index, 1);
		this.replicators_input.value = this.replicators.join(',');
	}

	// remove row from document
	var row_id = this.id + '_row_' + replicator_id;
	var row = document.getElementById(row_id);
	if (row && row.parentNode !== null) {
		var removed_row = row.parentNode.removeChild(row);
		delete removed_row;
	}
}
<|endoftext|>