text: // Copyright (c) 2008-2013, Andrew Brehaut, Tim Baumann, Matt Wilson, 
  //                          Simon Heimler, Michel Vielmetter 
  //
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are met:
  //
  // * Redistributions of source code must retain the above copyright notice,
  //   this list of conditions and the following disclaimer.
  // * Redistributions in binary form must reproduce the above copyright notice,
  //   this list of conditions and the following disclaimer in the documentation
  //   and/or other materials provided with the distribution.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  // POSSIBILITY OF SUCH DAMAGE.
  
  // color.js - version 1.0.1
  //
  // HSV <-> RGB code based on code from http://www.cs.rit.edu/~ncs/color/t_convert.html
  // object function created by Douglas Crockford.
  // Color scheme degrees taken from the colorjack.com colorpicker
  //
  // HSL support kindly provided by Tim Baumann - http://github.com/timjb
  
  // create namespaces
  /*global net */
  if ("undefined" == typeof net) {
      var net = {};
  }
  if (!net.brehaut) {
      net.brehaut = {};
  }
  
  // this module function is called with net.brehaut as 'this'
  (function () {
      "use strict";
      // Constants
  
      // css_colors maps color names onto their hex values
      // these names are defined by W3C
  
      var css_colors = { aliceblue: '#F0F8FF', antiquewhite: '#FAEBD7', aqua: '#00FFFF', aquamarine: '#7FFFD4', azure: '#F0FFFF', beige: '#F5F5DC', bisque: '#FFE4C4', black: '#000000', blanchedalmond: '#FFEBCD', blue: '#0000FF', blueviolet: '#8A2BE2', brown: '#A52A2A', burlywood: '#DEB887', cadetblue: '#5F9EA0', chartreuse: '#7FFF00', chocolate: '#D2691E', coral: '#FF7F50', cornflowerblue: '#6495ED', cornsilk: '#FFF8DC', crimson: '#DC143C', cyan: '#00FFFF', darkblue: '#00008B', darkcyan: '#008B8B', darkgoldenrod: '#B8860B', darkgray: '#A9A9A9', darkgrey: '#A9A9A9', darkgreen: '#006400', darkkhaki: '#BDB76B', darkmagenta: '#8B008B', darkolivegreen: '#556B2F', darkorange: '#FF8C00', darkorchid: '#9932CC', darkred: '#8B0000', darksalmon: '#E9967A', darkseagreen: '#8FBC8F', darkslateblue: '#483D8B', darkslategray: '#2F4F4F', darkslategrey: '#2F4F4F', darkturquoise: '#00CED1', darkviolet: '#9400D3', deeppink: '#FF1493', deepskyblue: '#00BFFF', dimgray: '#696969', dimgrey: '#696969', dodgerblue: '#1E90FF', firebrick: '#B22222', floralwhite: '#FFFAF0', forestgreen: '#228B22', fuchsia: '#FF00FF', gainsboro: '#DCDCDC', ghostwhite: '#F8F8FF', gold: '#FFD700', goldenrod: '#DAA520', gray: '#808080', grey: '#808080', green: '#008000', greenyellow: '#ADFF2F', honeydew: '#F0FFF0', hotpink: '#FF69B4', indianred: '#CD5C5C', indigo: '#4B0082', ivory: '#FFFFF0', khaki: '#F0E68C', lavender: '#E6E6FA', lavenderblush: '#FFF0F5', lawngreen: '#7CFC00', lemonchiffon: '#FFFACD', lightblue: '#ADD8E6', lightcoral: '#F08080', lightcyan: '#E0FFFF', lightgoldenrodyellow: '#FAFAD2', lightgray: '#D3D3D3', lightgrey: '#D3D3D3', lightgreen: '#90EE90', lightpink: '#FFB6C1', lightsalmon: '#FFA07A', lightseagreen: '#20B2AA', lightskyblue: '#87CEFA', lightslategray: '#778899', lightslategrey: '#778899', lightsteelblue: '#B0C4DE', lightyellow: '#FFFFE0', lime: '#00FF00', limegreen: '#32CD32', linen: '#FAF0E6', magenta: '#FF00FF', maroon: '#800000', mediumaquamarine: '#66CDAA', mediumblue: '#0000CD', mediumorchid: '#BA55D3', mediumpurple: '#9370D8', mediumseagreen: '#3CB371', mediumslateblue: '#7B68EE', mediumspringgreen: '#00FA9A', mediumturquoise: '#48D1CC', mediumvioletred: '#C71585', midnightblue: '#191970', mintcream: '#F5FFFA', mistyrose: '#FFE4E1', moccasin: '#FFE4B5', navajowhite: '#FFDEAD', navy: '#000080', oldlace: '#FDF5E6', olive: '#808000', olivedrab: '#6B8E23', orange: '#FFA500', orangered: '#FF4500', orchid: '#DA70D6', palegoldenrod: '#EEE8AA', palegreen: '#98FB98', paleturquoise: '#AFEEEE', palevioletred: '#D87093', papayawhip: '#FFEFD5', peachpuff: '#FFDAB9', peru: '#CD853F', pink: '#FFC0CB', plum: '#DDA0DD', powderblue: '#B0E0E6', purple: '#800080', rebeccapurple: '#663399', red: '#FF0000', rosybrown: '#BC8F8F', royalblue: '#4169E1', saddlebrown: '#8B4513', salmon: '#FA8072', sandybrown: '#F4A460', seagreen: '#2E8B57', seashell: '#FFF5EE', sienna: '#A0522D', silver: '#C0C0C0', skyblue: '#87CEEB', slateblue: '#6A5ACD', slategray: '#708090', slategrey: '#708090', snow: '#FFFAFA', springgreen: '#00FF7F', steelblue: '#4682B4', tan: '#D2B48C', teal: '#008080', thistle: '#D8BFD8', tomato: '#FF6347', turquoise: '#40E0D0', violet: '#EE82EE', wheat: '#F5DEB3', white: '#FFFFFF', whitesmoke: '#F5F5F5', yellow: '#FFFF00', yellowgreen: '#9ACD32' };
  
  
      // CSS value regexes, according to http://www.w3.org/TR/css3-values/
      var css_integer = '(?:\\+|-)?\\d+';
      var css_float = '(?:\\+|-)?\\d*\\.\\d+';
      var css_number = '(?:' + css_integer + ')|(?:' + css_float + ')';
      css_integer = '(' + css_integer + ')';
      css_float = '(' + css_float + ')';
      css_number = '(' + css_number + ')';
      var css_percentage = css_number + '%';
      var css_whitespace = '\\s*?';
  
      // http://www.w3.org/TR/2003/CR-css3-color-20030514/
      var hsl_hsla_regex = new RegExp([
          '^hsl(a?)\\(', css_number, ',', css_percentage, ',', css_percentage, '(,(', css_number, '))?\\)$'
      ].join(css_whitespace));
      var rgb_rgba_integer_regex = new RegExp([
          '^rgb(a?)\\(', css_integer, ',', css_integer, ',', css_integer, '(,(', css_number, '))?\\)$'
      ].join(css_whitespace));
      var rgb_rgba_percentage_regex = new RegExp([
          '^rgb(a?)\\(', css_percentage, ',', css_percentage, ',', css_percentage, '(,(', css_number, '))?\\)$'
      ].join(css_whitespace));
  
      // Package wide variables
  
      // becomes the top level prototype object
      var color;
  
      /* registered_models contains the template objects for all the
       * models that have been registered for the color class.
       */
      var registered_models = [];
  
  
      /* factories contains methods to create new instance of
       * different color models that have been registered.
       */
      var factories = {};
  
      // Utility functions
  
      /* object is Douglas Crockfords object function for prototypal
       * inheritance.
       */
      if (!this.object) {
          this.object = function (o) {
              function F() { }
              F.prototype = o;
              return new F();
          };
      }
      var object = this.object;
  
      /* takes a value, converts to string if need be, then pads it
       * to a minimum length.
       */
      function pad(val, len) {
          val = val.toString();
          var padded = [];
  
          for (var i = 0, j = Math.max(len - val.length, 0); i < j; i++) {
              padded.push('0');
          }
  
          padded.push(val);
          return padded.join('');
      }
  
  
      /* takes a string and returns a new string with the first letter
       * capitalised
       */
      function capitalise(s) {
          return s.slice(0, 1).toUpperCase() + s.slice(1);
      }
  
      /* removes leading and trailing whitespace
       */
      function trim(str) {
          return str.replace(/^\s+|\s+$/g, '');
      }
  
      /* used to apply a method to object non-destructively by
       * cloning the object and then apply the method to that
       * new object
       */
      function cloneOnApply(meth) {
          return function () {
              var cloned = this.clone();
              meth.apply(cloned, arguments);
              return cloned;
          };
      }
  
  
      /* registerModel is used to add additional representations
       * to the color code, and extend the color API with the new
       * operation that model provides. see before for examples
       */
      function registerModel(name, model) {
          var proto = object(color);
          var fields = []; // used for cloning and generating accessors
  
          var to_meth = 'to' + capitalise(name);
  
          function convertAndApply(meth) {
              return function () {
                  return meth.apply(this[to_meth](), arguments);
              };
          }
  
          for (var key in model)
              if (model.hasOwnProperty(key)) {
                  proto[key] = model[key];
                  var prop = proto[key];
  
                  if (key.slice(0, 1) == '_') {
                      continue;
                  }
                  if (!(key in color) && "function" == typeof prop) {
                      // the method found on this object is a) public and b) not
                      // currently supported by the color object. Create an impl that
                      // calls the toModel function and passes that new object
                      // onto the correct method with the args.
                      color[key] = convertAndApply(prop);
                  } else if ("function" != typeof prop) {
                      // we have found a public property. create accessor methods
                      // and bind them up correctly
                      fields.push(key);
                      var getter = 'get' + capitalise(key);
                      var setter = 'set' + capitalise(key);
  
                      color[getter] = convertAndApply(
                          proto[getter] = (function (key) {
                              return function () {
                                  return this[key];
                              };
                          })(key)
                      );
  
                      color[setter] = convertAndApply(
                          proto[setter] = (function (key) {
                              return function (val) {
                                  var cloned = this.clone();
                                  cloned[key] = val;
                                  return cloned;
                              };
                          })(key)
                      );
                  }
              } // end of for over model
  
          // a method to create a new object - largely so prototype chains dont
          // get insane. This uses an unrolled 'object' so that F is cached
          // for later use. this is approx a 25% speed improvement
  
          function F() { }
          F.prototype = proto;
  
          function factory() {
              return new F();
          }
          factories[name] = factory;
  
          proto.clone = function () {
              var cloned = factory();
              for (var i = 0, j = fields.length; i < j; i++) {
                  var key = fields[i];
                  cloned[key] = this[key];
              }
              return cloned;
          };
  
          color[to_meth] = function () {
              return factory();
          };
  
          registered_models.push(proto);
  
          return proto;
      } // end of registerModel
  
      // Template Objects
  
      /* color is the root object in the color hierarchy. It starts
       * life as a very simple object, but as color models are
       * registered it has methods programmatically added to manage
       * conversions as needed.
       */
      color = {
          /* fromObject takes an argument and delegates to the internal
           * color models to try to create a new instance.
           */
          fromObject: function (o) {
              if (!o) {
                  return object(color);
              }
  
              for (var i = 0, j = registered_models.length; i < j; i++) {
                  var nu = registered_models[i].fromObject(o);
                  if (nu) {
                      return nu;
                  }
              }
  
              return object(color);
          },
  
          toString: function () {
              return this.toCSS();
          }
      };
  
      var transparent = null; // defined with an RGB later.
  
      /* RGB is the red green blue model. This definition is converted
       * to a template object by registerModel.
       */
      registerModel('RGB', {
          red: 0,
          green: 0,
          blue: 0,
          alpha: 0,
  
          /* getLuminance returns a value between 0 and 1, this is the
           * luminance calcuated according to
           * http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC9
           */
          getLuminance: function () {
              return (this.red * 0.2126) + (this.green * 0.7152) + (this.blue * 0.0722);
          },
  
          /* does an alpha based blend of color onto this. alpha is the
           * amount of 'color' to use. (0 to 1)
           */
          blend: function (color, alpha) {
              color = color.toRGB();
              alpha = Math.min(Math.max(alpha, 0), 1);
              var rgb = this.clone();
  
              rgb.red = (rgb.red * (1 - alpha)) + (color.red * alpha);
              rgb.green = (rgb.green * (1 - alpha)) + (color.green * alpha);
              rgb.blue = (rgb.blue * (1 - alpha)) + (color.blue * alpha);
              rgb.alpha = (rgb.alpha * (1 - alpha)) + (color.alpha * alpha);
  
              return rgb;
          },
  
          /* fromObject attempts to convert an object o to and RGB
           * instance. This accepts an object with red, green and blue
           * members or a string. If the string is a known CSS color name
           * or a hexdecimal string it will accept it.
           */
          fromObject: function (o) {
              if (o instanceof Array) {
                  return this._fromRGBArray(o);
              }
              if ("string" == typeof o) {
                  return this._fromCSS(trim(o));
              }
              if (o.hasOwnProperty('red') &&
                  o.hasOwnProperty('green') &&
                  o.hasOwnProperty('blue')) {
                  return this._fromRGB(o);
              }
              // nothing matchs, not an RGB object
          },
  
          _stringParsers: [
              // CSS RGB(A) literal:
              function (css) {
                  css = trim(css);
  
                  var withInteger = match(rgb_rgba_integer_regex, 255);
                  if (withInteger) {
                      return withInteger;
                  }
                  return match(rgb_rgba_percentage_regex, 100);
  
                  function match(regex, max_value) {
                      var colorGroups = css.match(regex);
  
                      // If there is an "a" after "rgb", there must be a fourth parameter and the other way round
                      if (!colorGroups || (!!colorGroups[1] + !!colorGroups[5] === 1)) {
                          return null;
                      }
  
                      var rgb = factories.RGB();
                      rgb.red = Math.min(1, Math.max(0, colorGroups[2] / max_value));
                      rgb.green = Math.min(1, Math.max(0, colorGroups[3] / max_value));
                      rgb.blue = Math.min(1, Math.max(0, colorGroups[4] / max_value));
                      rgb.alpha = !!colorGroups[5] ? Math.min(Math.max(parseFloat(colorGroups[6]), 0), 1) : 1;
  
                      return rgb;
                  }
              },
  
              function (css) {
                  var lower = css.toLowerCase();
                  if (lower in css_colors) {
                      css = css_colors[lower];
                  }
  
                  if (!css.match(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/)) {
                      return;
                  }
  
                  css = css.replace(/^#/, '');
  
                  var bytes = css.length / 3;
  
                  var max = Math.pow(16, bytes) - 1;
  
                  var rgb = factories.RGB();
                  rgb.red = parseInt(css.slice(0, bytes), 16) / max;
                  rgb.green = parseInt(css.slice(bytes * 1, bytes * 2), 16) / max;
                  rgb.blue = parseInt(css.slice(bytes * 2), 16) / max;
                  rgb.alpha = 1;
                  return rgb;
              },
  
              function (css) {
                  if (css.toLowerCase() !== 'transparent') return;
  
                  return transparent;
              }
          ],
  
          _fromCSS: function (css) {
              var color = null;
              for (var i = 0, j = this._stringParsers.length; i < j; i++) {
                  color = this._stringParsers[i](css);
                  if (color) return color;
              }
          },
  
          _fromRGB: function (RGB) {
              var newRGB = factories.RGB();
  
              newRGB.red = RGB.red;
              newRGB.green = RGB.green;
              newRGB.blue = RGB.blue;
              newRGB.alpha = RGB.hasOwnProperty('alpha') ? RGB.alpha : 1;
  
              return newRGB;
          },
  
          _fromRGBArray: function (RGB) {
              var newRGB = factories.RGB();
  
              newRGB.red = Math.max(0, Math.min(1, RGB[0] / 255));
              newRGB.green = Math.max(0, Math.min(1, RGB[1] / 255));
              newRGB.blue = Math.max(0, Math.min(1, RGB[2] / 255));
              newRGB.alpha = RGB[3] !== undefined ? Math.max(0, Math.min(1, RGB[3])) : 1;
  
              return newRGB;
          },
  
          // convert to a CSS string. defaults to two bytes a value
          toCSSHex: function (bytes) {
              bytes = bytes || 2;
  
              var max = Math.pow(16, bytes) - 1;
              var css = [
                  "#",
                  pad(Math.round(this.red * max).toString(16).toUpperCase(), bytes),
                  pad(Math.round(this.green * max).toString(16).toUpperCase(), bytes),
                  pad(Math.round(this.blue * max).toString(16).toUpperCase(), bytes)
              ];
  
              return css.join('');
          },
  
          toCSS: function (bytes) {
              if (this.alpha === 1) return this.toCSSHex(bytes);
  
              var max = 255;
  
              var components = [
                  'rgba(',
                  Math.max(0, Math.min(max, Math.round(this.red * max))), ',',
                  Math.max(0, Math.min(max, Math.round(this.green * max))), ',',
                  Math.max(0, Math.min(max, Math.round(this.blue * max))), ',',
                  Math.max(0, Math.min(1, this.alpha)),
                  ')'
              ];
  
              return components.join('');
          },
  
          toHSV: function () {
              var hsv = factories.HSV();
              var min, max, delta;
  
              min = Math.min(this.red, this.green, this.blue);
              max = Math.max(this.red, this.green, this.blue);
              hsv.value = max; // v
  
              delta = max - min;
  
              if (delta == 0) { // white, grey, black
                  hsv.hue = hsv.saturation = 0;
              } else { // chroma
                  hsv.saturation = delta / max;
  
                  if (this.red == max) {
                      hsv.hue = (this.green - this.blue) / delta; // between yellow & magenta
                  } else if (this.green == max) {
                      hsv.hue = 2 + (this.blue - this.red) / delta; // between cyan & yellow
                  } else {
                      hsv.hue = 4 + (this.red - this.green) / delta; // between magenta & cyan
                  }
  
                  hsv.hue = ((hsv.hue * 60) + 360) % 360; // degrees
              }
  
              hsv.alpha = this.alpha;
  
              return hsv;
          },
          toHSL: function () {
              return this.toHSV().toHSL();
          },
  
          toRGB: function () {
              return this.clone();
          }
      });
  
      transparent = color.fromObject({
          red: 0,
          blue: 0,
          green: 0,
          alpha: 0
      });
  
  
      /* Like RGB above, this object describes what will become the HSV
       * template object. This model handles hue, saturation and value.
       * hue is the number of degrees around the color wheel, saturation
       * describes how much color their is and value is the brightness.
       */
      registerModel('HSV', {
          hue: 0,
          saturation: 0,
          value: 1,
          alpha: 1,
  
          shiftHue: cloneOnApply(function (degrees) {
              var hue = (this.hue + degrees) % 360;
              if (hue < 0) {
                  hue = (360 + hue) % 360;
              }
  
              this.hue = hue;
          }),
  
          devalueByAmount: cloneOnApply(function (val) {
              this.value = Math.min(1, Math.max(this.value - val, 0));
          }),
  
          devalueByRatio: cloneOnApply(function (val) {
              this.value = Math.min(1, Math.max(this.value * (1 - val), 0));
          }),
  
          valueByAmount: cloneOnApply(function (val) {
              this.value = Math.min(1, Math.max(this.value + val, 0));
          }),
  
          valueByRatio: cloneOnApply(function (val) {
              this.value = Math.min(1, Math.max(this.value * (1 + val), 0));
          }),
  
          desaturateByAmount: cloneOnApply(function (val) {
              this.saturation = Math.min(1, Math.max(this.saturation - val, 0));
          }),
  
          desaturateByRatio: cloneOnApply(function (val) {
              this.saturation = Math.min(1, Math.max(this.saturation * (1 - val), 0));
          }),
  
          saturateByAmount: cloneOnApply(function (val) {
              this.saturation = Math.min(1, Math.max(this.saturation + val, 0));
          }),
  
          saturateByRatio: cloneOnApply(function (val) {
              this.saturation = Math.min(1, Math.max(this.saturation * (1 + val), 0));
          }),
  
          schemeFromDegrees: function (degrees) {
              var newColors = [];
              for (var i = 0, j = degrees.length; i < j; i++) {
                  var col = this.clone();
                  col.hue = (this.hue + degrees[i]) % 360;
                  newColors.push(col);
              }
              return newColors;
          },
  
          complementaryScheme: function () {
              return this.schemeFromDegrees([0, 180]);
          },
  
          splitComplementaryScheme: function () {
              return this.schemeFromDegrees([0, 150, 320]);
          },
  
          splitComplementaryCWScheme: function () {
              return this.schemeFromDegrees([0, 150, 300]);
          },
  
          splitComplementaryCCWScheme: function () {
              return this.schemeFromDegrees([0, 60, 210]);
          },
  
          triadicScheme: function () {
              return this.schemeFromDegrees([0, 120, 240]);
          },
  
          clashScheme: function () {
              return this.schemeFromDegrees([0, 90, 270]);
          },
  
          tetradicScheme: function () {
              return this.schemeFromDegrees([0, 90, 180, 270]);
          },
  
          fourToneCWScheme: function () {
              return this.schemeFromDegrees([0, 60, 180, 240]);
          },
  
          fourToneCCWScheme: function () {
              return this.schemeFromDegrees([0, 120, 180, 300]);
          },
  
          fiveToneAScheme: function () {
              return this.schemeFromDegrees([0, 115, 155, 205, 245]);
          },
  
          fiveToneBScheme: function () {
              return this.schemeFromDegrees([0, 40, 90, 130, 245]);
          },
  
          fiveToneCScheme: function () {
              return this.schemeFromDegrees([0, 50, 90, 205, 320]);
          },
  
          fiveToneDScheme: function () {
              return this.schemeFromDegrees([0, 40, 155, 270, 310]);
          },
  
          fiveToneEScheme: function () {
              return this.schemeFromDegrees([0, 115, 230, 270, 320]);
          },
  
          sixToneCWScheme: function () {
              return this.schemeFromDegrees([0, 30, 120, 150, 240, 270]);
          },
  
          sixToneCCWScheme: function () {
              return this.schemeFromDegrees([0, 90, 120, 210, 240, 330]);
          },
  
          neutralScheme: function () {
              return this.schemeFromDegrees([0, 15, 30, 45, 60, 75]);
          },
  
          analogousScheme: function () {
              return this.schemeFromDegrees([0, 30, 60, 90, 120, 150]);
          },
  
          fromObject: function (o) {
              if (o.hasOwnProperty('hue') &&
                  o.hasOwnProperty('saturation') &&
                  o.hasOwnProperty('value')) {
                  var hsv = factories.HSV();
  
                  hsv.hue = o.hue;
                  hsv.saturation = o.saturation;
                  hsv.value = o.value;
                  hsv.alpha = o.hasOwnProperty('alpha') ? o.alpha : 1;
  
                  return hsv;
              }
              // nothing matches, not an HSV object
              return null;
          },
  
          _normalise: function () {
              this.hue %= 360;
              this.saturation = Math.min(Math.max(0, this.saturation), 1);
              this.value = Math.min(Math.max(0, this.value));
              this.alpha = Math.min(1, Math.max(0, this.alpha));
          },
  
          toRGB: function () {
              this._normalise();
  
              var rgb = factories.RGB();
              var i;
              var f, p, q, t;
  
              if (this.saturation === 0) {
                  // achromatic (grey)
                  rgb.red = this.value;
                  rgb.green = this.value;
                  rgb.blue = this.value;
                  rgb.alpha = this.alpha;
                  return rgb;
              }
  
              var h = this.hue / 60; // sector 0 to 5
              i = Math.floor(h);
              f = h - i; // factorial part of h
              p = this.value * (1 - this.saturation);
              q = this.value * (1 - this.saturation * f);
              t = this.value * (1 - this.saturation * (1 - f));
  
              switch (i) {
                  case 0:
                      rgb.red = this.value;
                      rgb.green = t;
                      rgb.blue = p;
                      break;
                  case 1:
                      rgb.red = q;
                      rgb.green = this.value;
                      rgb.blue = p;
                      break;
                  case 2:
                      rgb.red = p;
                      rgb.green = this.value;
                      rgb.blue = t;
                      break;
                  case 3:
                      rgb.red = p;
                      rgb.green = q;
                      rgb.blue = this.value;
                      break;
                  case 4:
                      rgb.red = t;
                      rgb.green = p;
                      rgb.blue = this.value;
                      break;
                  default: // case 5:
                      rgb.red = this.value;
                      rgb.green = p;
                      rgb.blue = q;
                      break;
              }
  
              rgb.alpha = this.alpha;
  
              return rgb;
          },
          toHSL: function () {
              this._normalise();
  
              var hsl = factories.HSL();
  
              hsl.hue = this.hue;
              var l = (2 - this.saturation) * this.value,
                  s = this.saturation * this.value;
              if (l && 2 - l) {
                  s /= (l <= 1) ? l : 2 - l;
              }
              l /= 2;
              hsl.saturation = s;
              hsl.lightness = l;
              hsl.alpha = this.alpha;
  
              return hsl;
          },
  
          toHSV: function () {
              return this.clone();
          }
      });
  
      registerModel('HSL', {
          hue: 0,
          saturation: 0,
          lightness: 0,
          alpha: 1,
  
          darkenByAmount: cloneOnApply(function (val) {
              this.lightness = Math.min(1, Math.max(this.lightness - val, 0));
          }),
  
          darkenByRatio: cloneOnApply(function (val) {
              this.lightness = Math.min(1, Math.max(this.lightness * (1 - val), 0));
          }),
  
          lightenByAmount: cloneOnApply(function (val) {
              this.lightness = Math.min(1, Math.max(this.lightness + val, 0));
          }),
  
          lightenByRatio: cloneOnApply(function (val) {
              this.lightness = Math.min(1, Math.max(this.lightness * (1 + val), 0));
          }),
  
          fromObject: function (o) {
              if ("string" == typeof o) {
                  return this._fromCSS(o);
              }
              if (o.hasOwnProperty('hue') &&
                  o.hasOwnProperty('saturation') &&
                  o.hasOwnProperty('lightness')) {
                  return this._fromHSL(o);
              }
              // nothing matchs, not an RGB object
          },
  
          _fromCSS: function (css) {
              var colorGroups = trim(css).match(hsl_hsla_regex);
  
              // if there is an "a" after "hsl", there must be a fourth parameter and the other way round
              if (!colorGroups || (!!colorGroups[1] + !!colorGroups[5] === 1)) {
                  return null;
              }
  
              var hsl = factories.HSL();
              hsl.hue = (colorGroups[2] % 360 + 360) % 360;
              hsl.saturation = Math.max(0, Math.min(parseInt(colorGroups[3], 10) / 100, 1));
              hsl.lightness = Math.max(0, Math.min(parseInt(colorGroups[4], 10) / 100, 1));
              hsl.alpha = !!colorGroups[5] ? Math.max(0, Math.min(1, parseFloat(colorGroups[6]))) : 1;
  
              return hsl;
          },
  
          _fromHSL: function (HSL) {
              var newHSL = factories.HSL();
  
              newHSL.hue = HSL.hue;
              newHSL.saturation = HSL.saturation;
              newHSL.lightness = HSL.lightness;
  
              newHSL.alpha = HSL.hasOwnProperty('alpha') ? HSL.alpha : 1;
  
              return newHSL;
          },
  
          _normalise: function () {
              this.hue = (this.hue % 360 + 360) % 360;
              this.saturation = Math.min(Math.max(0, this.saturation), 1);
              this.lightness = Math.min(Math.max(0, this.lightness));
              this.alpha = Math.min(1, Math.max(0, this.alpha));
          },
  
          toHSL: function () {
              return this.clone();
          },
          toHSV: function () {
              this._normalise();
  
              var hsv = factories.HSV();
  
              // http://ariya.blogspot.com/2008/07/converting-between-hsl-and-hsv.html
              hsv.hue = this.hue; // H
              var l = 2 * this.lightness,
                  s = this.saturation * ((l <= 1) ? l : 2 - l);
              hsv.value = (l + s) / 2; // V
              hsv.saturation = ((2 * s) / (l + s)) || 0; // S
              hsv.alpha = this.alpha;
  
              return hsv;
          },
          toRGB: function () {
              return this.toHSV().toRGB();
          }
      });
  
      // Package specific exports
  
      /* the Color function is a factory for new color objects.
       */
      function Color(o) {
          return color.fromObject(o);
      }
      Color.isValid = function (str) {
          var key, c = Color(str);
  
          var length = 0;
          for (key in c) {
              if (c.hasOwnProperty(key)) {
                  length++;
              }
          }
  
          return length > 0;
      };
      net.brehaut.Color = Color;
  }).call(net.brehaut);
  
  /* Export to CommonJS
   */
  if (typeof module !== 'undefined') {
      module.exports = net.brehaut.Color;    
  }
  
  //
  //
  // Integration by coboye 
  // ES6 export
  // Colors gradient wrappers
  //
  //
  //
  //
  
  export const Color = net.brehaut.Color;
  
  export class ColorStep{
      /**
       * @type {String}
       */
      length=null;
      /**
       * @type {net.brehaut.Color}
       */
      color=null;
  
      /**
       * 
       * @param {string} color
       * @param {String} length 
       */
      constructor(color, length){
          this.color = new net.brehaut.Color(color);
          this.length = length;
      }
  
      toString(){
          return `${this.color} ${this.length}`;
      }
  
      shiftHue(value){
          this.color = this.color.shiftHue(value);
          return this;
      }
      lightenByRatio(value){
          this.color = this.color.lightenByRatio(value);
          return this;
      }
      valueByRatio(value){
          this.color = this.color.valueByRatio(value);
          return this;
      }
      saturateByRatio(value){
          this.color = this.color.saturateByRatio(value);
          return this;
      }
  
  }
  
  
  export class LinearGradient{
      //linear-gradient(25deg, #1d4e8c 0%, #45afeb 40 %, #2b6abb 60 %, #1d4e8c 100 %);
      tilt = null;
      /**
       * @type {Array<ColorStep>}
      */
      steps=[];
  
      /**
       * 
       * @param {String} tilt 
       * @param {Array<ColorStep>} steps
       */
      constructor(tilt, steps){
          this.tilt = tilt;
          this.steps = steps;
      }
  
      toString(){
          const steps = this.steps.map(s => s.toString()).join(" ,");
          return `linear-gradient(${this.tilt==null ? "" : this.tilt+", "}${steps})`;
      }
  
      shiftHue(value) {
          this.steps = this.steps.map(step =>{
              return step.shiftHue(value);
          })
          return this;
      }
      lightenByRatio(value) {
          this.steps = this.steps.map(step =>{
              return step.lightenByRatio(value);
          })
          return this;
      }
      valueByRatio(value) {
          this.steps = this.steps.map(step =>{
              return step.valueByRatio(value);
          })
          return this;
      }
      saturateByRatio(value) {
          this.steps = this.steps.map(step =>{
              return step.saturateByRatio(value);
          })
          return this;
      }
      
  }