text: (function(global) {
  
    'use strict';
  
    var fabric = global.fabric || (global.fabric = { });
  
    if (fabric.Color) {
      fabric.warn('fabric.Color is already defined.');
      return;
    }
  
    /**
     * Color class
     * The purpose of {@link fabric.Color} is to abstract and encapsulate common color operations;
     * {@link fabric.Color} is a constructor and creates instances of {@link fabric.Color} objects.
     *
     * @class fabric.Color
     * @param {String} color optional in hex or rgb(a) or hsl format or from known color list
     * @return {fabric.Color} thisArg
     * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#colors}
     */
    function Color(color) {
      if (!color) {
        this.setSource([0, 0, 0, 1]);
      }
      else {
        this._tryParsingColor(color);
      }
    }
  
    fabric.Color = Color;
  
    fabric.Color.prototype = /** @lends fabric.Color.prototype */ {
  
      /**
       * @private
       * @param {String|Array} color Color value to parse
       */
      _tryParsingColor: function(color) {
        var source;
  
        if (color in Color.colorNameMap) {
          color = Color.colorNameMap[color];
        }
  
        if (color === 'transparent') {
          source = [255, 255, 255, 0];
        }
  
        if (!source) {
          source = Color.sourceFromHex(color);
        }
        if (!source) {
          source = Color.sourceFromRgb(color);
        }
        if (!source) {
          source = Color.sourceFromHsl(color);
        }
        if (!source) {
          //if color is not recognize let's make black as canvas does
          source = [0, 0, 0, 1];
        }
        if (source) {
          this.setSource(source);
        }
      },
  
      /**
       * Adapted from <a href="https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html">https://github.com/mjijackson</a>
       * @private
       * @param {Number} r Red color value
       * @param {Number} g Green color value
       * @param {Number} b Blue color value
       * @return {Array} Hsl color
       */
      _rgbToHsl: function(r, g, b) {
        r /= 255; g /= 255; b /= 255;
  
        var h, s, l,
            max = fabric.util.array.max([r, g, b]),
            min = fabric.util.array.min([r, g, b]);
  
        l = (max + min) / 2;
  
        if (max === min) {
          h = s = 0; // achromatic
        }
        else {
          var d = max - min;
          s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
          switch (max) {
            case r:
              h = (g - b) / d + (g < b ? 6 : 0);
              break;
            case g:
              h = (b - r) / d + 2;
              break;
            case b:
              h = (r - g) / d + 4;
              break;
          }
          h /= 6;
        }
  
        return [
          Math.round(h * 360),
          Math.round(s * 100),
          Math.round(l * 100)
        ];
      },
  
      /**
       * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1])
       * @return {Array}
       */
      getSource: function() {
        return this._source;
      },
  
      /**
       * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1])
       * @param {Array} source
       */
      setSource: function(source) {
        this._source = source;
      },
  
      /**
       * Returns color representation in RGB format
       * @return {String} ex: rgb(0-255,0-255,0-255)
       */
      toRgb: function() {
        var source = this.getSource();
        return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')';
      },
  
      /**
       * Returns color representation in RGBA format
       * @return {String} ex: rgba(0-255,0-255,0-255,0-1)
       */
      toRgba: function() {
        var source = this.getSource();
        return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')';
      },
  
      /**
       * Returns color representation in HSL format
       * @return {String} ex: hsl(0-360,0%-100%,0%-100%)
       */
      toHsl: function() {
        var source = this.getSource(),
            hsl = this._rgbToHsl(source[0], source[1], source[2]);
  
        return 'hsl(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%)';
      },
  
      /**
       * Returns color representation in HSLA format
       * @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1)
       */
      toHsla: function() {
        var source = this.getSource(),
            hsl = this._rgbToHsl(source[0], source[1], source[2]);
  
        return 'hsla(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%,' + source[3] + ')';
      },
  
      /**
       * Returns color representation in HEX format
       * @return {String} ex: FF5555
       */
      toHex: function() {
        var source = this.getSource(), r, g, b;
  
        r = source[0].toString(16);
        r = (r.length === 1) ? ('0' + r) : r;
  
        g = source[1].toString(16);
        g = (g.length === 1) ? ('0' + g) : g;
  
        b = source[2].toString(16);
        b = (b.length === 1) ? ('0' + b) : b;
  
        return r.toUpperCase() + g.toUpperCase() + b.toUpperCase();
      },
  
      /**
       * Returns color representation in HEXA format
       * @return {String} ex: FF5555CC
       */
      toHexa: function() {
        var source = this.getSource(), a;
  
        a = source[3] * 255;
        a = a.toString(16);
        a = (a.length === 1) ? ('0' + a) : a;
  
        return this.toHex() + a.toUpperCase();
      },
  
      /**
       * Gets value of alpha channel for this color
       * @return {Number} 0-1
       */
      getAlpha: function() {
        return this.getSource()[3];
      },
  
      /**
       * Sets value of alpha channel for this color
       * @param {Number} alpha Alpha value 0-1
       * @return {fabric.Color} thisArg
       */
      setAlpha: function(alpha) {
        var source = this.getSource();
        source[3] = alpha;
        this.setSource(source);
        return this;
      },
  
      /**
       * Transforms color to its grayscale representation
       * @return {fabric.Color} thisArg
       */
      toGrayscale: function() {
        var source = this.getSource(),
            average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10),
            currentAlpha = source[3];
        this.setSource([average, average, average, currentAlpha]);
        return this;
      },
  
      /**
       * Transforms color to its black and white representation
       * @param {Number} threshold
       * @return {fabric.Color} thisArg
       */
      toBlackWhite: function(threshold) {
        var source = this.getSource(),
            average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0),
            currentAlpha = source[3];
  
        threshold = threshold || 127;
  
        average = (Number(average) < Number(threshold)) ? 0 : 255;
        this.setSource([average, average, average, currentAlpha]);
        return this;
      },
  
      /**
       * Overlays color with another color
       * @param {String|fabric.Color} otherColor
       * @return {fabric.Color} thisArg
       */
      overlayWith: function(otherColor) {
        if (!(otherColor instanceof Color)) {
          otherColor = new Color(otherColor);
        }
  
        var result = [],
            alpha = this.getAlpha(),
            otherAlpha = 0.5,
            source = this.getSource(),
            otherSource = otherColor.getSource();
  
        for (var i = 0; i < 3; i++) {
          result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha)));
        }
  
        result[3] = alpha;
        this.setSource(result);
        return this;
      }
    };
  
    /**
     * Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgba(255, 100, 10, 0.5), rgba( 255 , 100 , 10 , 0.5 ), rgb(1,1,1), rgba(100%, 60%, 10%, 0.5))
     * @static
     * @field
     * @memberOf fabric.Color
     */
     // eslint-disable-next-line max-len
    fabric.Color.reRGBa = /^rgba?\(\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/;
  
    /**
     * Regex matching color in HSL or HSLA formats (ex: hsl(200, 80%, 10%), hsla(300, 50%, 80%, 0.5), hsla( 300 , 50% , 80% , 0.5 ))
     * @static
     * @field
     * @memberOf fabric.Color
     */
    fabric.Color.reHSLa = /^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3}\%)\s*,\s*(\d{1,3}\%)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/;
  
    /**
     * Regex matching color in HEX format (ex: #FF5544CC, #FF5555, 010155, aff)
     * @static
     * @field
     * @memberOf fabric.Color
     */
    fabric.Color.reHex = /^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i;
  
    // TODO extend to the svg 1.0 color aka css3 colors.
  
    /**
     * Map of the 17 basic color names with HEX code
     * @static
     * @field
     * @memberOf fabric.Color
     * @see: http://www.w3.org/TR/CSS2/syndata.html#color-units
     */
    fabric.Color.colorNameMap = {
      aqua:      '#00FFFF',
      black:     '#000000',
      blue:      '#0000FF',
      fuchsia:   '#FF00FF',
      gray:      '#808080',
      grey:      '#808080',
      green:     '#008000',
      lime:      '#00FF00',
      maroon:    '#800000',
      navy:      '#000080',
      olive:     '#808000',
      orange:    '#FFA500',
      purple:    '#800080',
      red:       '#FF0000',
      silver:    '#C0C0C0',
      teal:      '#008080',
      white:     '#FFFFFF',
      yellow:    '#FFFF00'
    };
  
    /**
     * @private
     * @param {Number} p
     * @param {Number} q
     * @param {Number} t
     * @return {Number}
     */
    function hue2rgb(p, q, t) {
      if (t < 0) {
        t += 1;
      }
      if (t > 1) {
        t -= 1;
      }
      if (t < 1 / 6) {
        return p + (q - p) * 6 * t;
      }
      if (t < 1 / 2) {
        return q;
      }
      if (t < 2 / 3) {
        return p + (q - p) * (2 / 3 - t) * 6;
      }
      return p;
    }
  
    /**
     * Returns new color object, when given a color in RGB format
     * @memberOf fabric.Color
     * @param {String} color Color value ex: rgb(0-255,0-255,0-255)
     * @return {fabric.Color}
     */
    fabric.Color.fromRgb = function(color) {
      return Color.fromSource(Color.sourceFromRgb(color));
    };
  
    /**
     * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format
     * @memberOf fabric.Color
     * @param {String} color Color value ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%)
     * @return {Array} source
     */
    fabric.Color.sourceFromRgb = function(color) {
      var match = color.match(Color.reRGBa);
      if (match) {
        var r = parseInt(match[1], 10) / (/%$/.test(match[1]) ? 100 : 1) * (/%$/.test(match[1]) ? 255 : 1),
            g = parseInt(match[2], 10) / (/%$/.test(match[2]) ? 100 : 1) * (/%$/.test(match[2]) ? 255 : 1),
            b = parseInt(match[3], 10) / (/%$/.test(match[3]) ? 100 : 1) * (/%$/.test(match[3]) ? 255 : 1);
  
        return [
          parseInt(r, 10),
          parseInt(g, 10),
          parseInt(b, 10),
          match[4] ? parseFloat(match[4]) : 1
        ];
      }
    };
  
    /**
     * Returns new color object, when given a color in RGBA format
     * @static
     * @function
     * @memberOf fabric.Color
     * @param {String} color
     * @return {fabric.Color}
     */
    fabric.Color.fromRgba = Color.fromRgb;
  
    /**
     * Returns new color object, when given a color in HSL format
     * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%)
     * @memberOf fabric.Color
     * @return {fabric.Color}
     */
    fabric.Color.fromHsl = function(color) {
      return Color.fromSource(Color.sourceFromHsl(color));
    };
  
    /**
     * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format.
     * Adapted from <a href="https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html">https://github.com/mjijackson</a>
     * @memberOf fabric.Color
     * @param {String} color Color value ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1)
     * @return {Array} source
     * @see http://http://www.w3.org/TR/css3-color/#hsl-color
     */
    fabric.Color.sourceFromHsl = function(color) {
      var match = color.match(Color.reHSLa);
      if (!match) {
        return;
      }
  
      var h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360,
          s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1),
          l = parseFloat(match[3]) / (/%$/.test(match[3]) ? 100 : 1),
          r, g, b;
  
      if (s === 0) {
        r = g = b = l;
      }
      else {
        var q = l <= 0.5 ? l * (s + 1) : l + s - l * s,
            p = l * 2 - q;
  
        r = hue2rgb(p, q, h + 1 / 3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1 / 3);
      }
  
      return [
        Math.round(r * 255),
        Math.round(g * 255),
        Math.round(b * 255),
        match[4] ? parseFloat(match[4]) : 1
      ];
    };
  
    /**
     * Returns new color object, when given a color in HSLA format
     * @static
     * @function
     * @memberOf fabric.Color
     * @param {String} color
     * @return {fabric.Color}
     */
    fabric.Color.fromHsla = Color.fromHsl;
  
    /**
     * Returns new color object, when given a color in HEX format
     * @static
     * @memberOf fabric.Color
     * @param {String} color Color value ex: FF5555
     * @return {fabric.Color}
     */
    fabric.Color.fromHex = function(color) {
      return Color.fromSource(Color.sourceFromHex(color));
    };
  
    /**
     * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HEX format
     * @static
     * @memberOf fabric.Color
     * @param {String} color ex: FF5555 or FF5544CC (RGBa)
     * @return {Array} source
     */
    fabric.Color.sourceFromHex = function(color) {
      if (color.match(Color.reHex)) {
        var value = color.slice(color.indexOf('#') + 1),
            isShortNotation = (value.length === 3 || value.length === 4),
            isRGBa = (value.length === 8 || value.length === 4),
            r = isShortNotation ? (value.charAt(0) + value.charAt(0)) : value.substring(0, 2),
            g = isShortNotation ? (value.charAt(1) + value.charAt(1)) : value.substring(2, 4),
            b = isShortNotation ? (value.charAt(2) + value.charAt(2)) : value.substring(4, 6),
            a = isRGBa ? (isShortNotation ? (value.charAt(3) + value.charAt(3)) : value.substring(6, 8)) : 'FF';
  
        return [
          parseInt(r, 16),
          parseInt(g, 16),
          parseInt(b, 16),
          parseFloat((parseInt(a, 16) / 255).toFixed(2))
        ];
      }
    };
  
    /**
     * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5])
     * @static
     * @memberOf fabric.Color
     * @param {Array} source
     * @return {fabric.Color}
     */
    fabric.Color.fromSource = function(source) {
      var oColor = new Color();
      oColor.setSource(source);
      return oColor;
    };
  
  })(typeof exports !== 'undefined' ? exports : this);
  