{"version":3,"sources":["jsdelivr-header.js","/npm/fabric@1.7.22/dist/fabric.js"],"names":[],"mappings":"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","file":"/npm/fabric@1.7.22/dist/fabric.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.37.0.\n * Original file: /npm/fabric@1.7.22/dist/fabric.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/* build: `node build.js modules=ALL exclude=json,gestures minifier=uglifyjs` */\n /*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */\n\nvar fabric = fabric || { version: \"1.7.22\" };\nif (typeof exports !== 'undefined') {\n  exports.fabric = fabric;\n}\n\nif (typeof document !== 'undefined' && typeof window !== 'undefined') {\n  fabric.document = document;\n  fabric.window = window;\n  // ensure globality even if entire library were function wrapped (as in Meteor.js packaging system)\n  window.fabric = fabric;\n}\nelse {\n  // assume we're running under node.js when document/window are not present\n  fabric.document = require(\"jsdom\")\n    .jsdom(\n      decodeURIComponent(\"%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E\")\n    );\n\n  if (fabric.document.createWindow) {\n    fabric.window = fabric.document.createWindow();\n  } else {\n    fabric.window = fabric.document.parentWindow;\n  }\n}\n\n/**\n * True when in environment that supports touch events\n * @type boolean\n */\n\nfabric.isTouchSupported = 'ontouchstart' in fabric.window;\n\n/**\n * True when in environment that's probably Node.js\n * @type boolean\n */\nfabric.isLikelyNode = typeof Buffer !== 'undefined' &&\n                      typeof window === 'undefined';\n\n/* _FROM_SVG_START_ */\n/**\n * Attributes parsed from all SVG elements\n * @type array\n */\nfabric.SHARED_ATTRIBUTES = [\n  \"display\",\n  \"transform\",\n  \"fill\", \"fill-opacity\", \"fill-rule\",\n  \"opacity\",\n  \"stroke\", \"stroke-dasharray\", \"stroke-linecap\",\n  \"stroke-linejoin\", \"stroke-miterlimit\",\n  \"stroke-opacity\", \"stroke-width\",\n  \"id\"\n];\n/* _FROM_SVG_END_ */\n\n/**\n * Pixel per Inch as a default value set to 96. Can be changed for more realistic conversion.\n */\nfabric.DPI = 96;\nfabric.reNum = '(?:[-+]?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:e[-+]?\\\\d+)?)';\nfabric.fontPaths = { };\nfabric.iMatrix = [1, 0, 0, 1, 0, 0];\nfabric.canvasModule = 'canvas';\n\n/**\n * Pixel limit for cache canvases. 1Mpx , 4Mpx should be fine.\n * @since 1.7.14\n * @type Number\n * @default\n */\nfabric.perfLimitSizeTotal = 2097152;\n\n/**\n * Pixel limit for cache canvases width or height. IE fixes the maximum at 5000\n * @since 1.7.14\n * @type Number\n * @default\n */\nfabric.maxCacheSideLimit = 4096;\n\n/**\n * Lowest pixel limit for cache canvases, set at 256PX\n * @since 1.7.14\n * @type Number\n * @default\n */\nfabric.minCacheSideLimit = 256;\n\n/**\n * Cache Object for widths of chars in text rendering.\n */\nfabric.charWidthsCache = { };\n\n/**\n * Device Pixel Ratio\n * @see https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/SettingUptheCanvas/SettingUptheCanvas.html\n */\nfabric.devicePixelRatio = fabric.window.devicePixelRatio ||\n                          fabric.window.webkitDevicePixelRatio ||\n                          fabric.window.mozDevicePixelRatio ||\n                          1;\n\n\n(function() {\n\n  /**\n   * @private\n   * @param {String} eventName\n   * @param {Function} handler\n   */\n  function _removeEventListener(eventName, handler) {\n    if (!this.__eventListeners[eventName]) {\n      return;\n    }\n    var eventListener = this.__eventListeners[eventName];\n    if (handler) {\n      eventListener[eventListener.indexOf(handler)] = false;\n    }\n    else {\n      fabric.util.array.fill(eventListener, false);\n    }\n  }\n\n  /**\n   * Observes specified event\n   * @deprecated `observe` deprecated since 0.8.34 (use `on` instead)\n   * @memberOf fabric.Observable\n   * @alias on\n   * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n   * @param {Function} handler Function that receives a notification when an event of the specified type occurs\n   * @return {Self} thisArg\n   * @chainable\n   */\n  function observe(eventName, handler) {\n    if (!this.__eventListeners) {\n      this.__eventListeners = { };\n    }\n    // one object with key/value pairs was passed\n    if (arguments.length === 1) {\n      for (var prop in eventName) {\n        this.on(prop, eventName[prop]);\n      }\n    }\n    else {\n      if (!this.__eventListeners[eventName]) {\n        this.__eventListeners[eventName] = [];\n      }\n      this.__eventListeners[eventName].push(handler);\n    }\n    return this;\n  }\n\n  /**\n   * Stops event observing for a particular event handler. Calling this method\n   * without arguments removes all handlers for all events\n   * @deprecated `stopObserving` deprecated since 0.8.34 (use `off` instead)\n   * @memberOf fabric.Observable\n   * @alias off\n   * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n   * @param {Function} handler Function to be deleted from EventListeners\n   * @return {Self} thisArg\n   * @chainable\n   */\n  function stopObserving(eventName, handler) {\n    if (!this.__eventListeners) {\n      return;\n    }\n\n    // remove all key/value pairs (event name -> event handler)\n    if (arguments.length === 0) {\n      for (eventName in this.__eventListeners) {\n        _removeEventListener.call(this, eventName);\n      }\n    }\n    // one object with key/value pairs was passed\n    else if (arguments.length === 1 && typeof arguments[0] === 'object') {\n      for (var prop in eventName) {\n        _removeEventListener.call(this, prop, eventName[prop]);\n      }\n    }\n    else {\n      _removeEventListener.call(this, eventName, handler);\n    }\n    return this;\n  }\n\n  /**\n   * Fires event with an optional options object\n   * @deprecated `fire` deprecated since 1.0.7 (use `trigger` instead)\n   * @memberOf fabric.Observable\n   * @alias trigger\n   * @param {String} eventName Event name to fire\n   * @param {Object} [options] Options object\n   * @return {Self} thisArg\n   * @chainable\n   */\n  function fire(eventName, options) {\n    if (!this.__eventListeners) {\n      return;\n    }\n\n    var listenersForEvent = this.__eventListeners[eventName];\n    if (!listenersForEvent) {\n      return;\n    }\n\n    for (var i = 0, len = listenersForEvent.length; i < len; i++) {\n      listenersForEvent[i] && listenersForEvent[i].call(this, options || { });\n    }\n    this.__eventListeners[eventName] = listenersForEvent.filter(function(value) {\n      return value !== false;\n    });\n    return this;\n  }\n\n  /**\n   * @namespace fabric.Observable\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#events}\n   * @see {@link http://fabricjs.com/events|Events demo}\n   */\n  fabric.Observable = {\n    observe: observe,\n    stopObserving: stopObserving,\n    fire: fire,\n\n    on: observe,\n    off: stopObserving,\n    trigger: fire\n  };\n})();\n\n\n/**\n * @namespace fabric.Collection\n */\nfabric.Collection = {\n\n  _objects: [],\n\n  /**\n   * Adds objects to collection, Canvas or Group, then renders canvas\n   * (if `renderOnAddRemove` is not `false`).\n   * in case of Group no changes to bounding box are made.\n   * Objects should be instances of (or inherit from) fabric.Object\n   * Use of this function is highly discouraged for groups.\n   * you can add a bunch of objects with the add method but then you NEED\n   * to run a addWithUpdate call for the Group class or position/bbox will be wrong.\n   * @param {...fabric.Object} object Zero or more fabric instances\n   * @return {Self} thisArg\n   * @chainable\n   */\n  add: function () {\n    this._objects.push.apply(this._objects, arguments);\n    if (this._onObjectAdded) {\n      for (var i = 0, length = arguments.length; i < length; i++) {\n        this._onObjectAdded(arguments[i]);\n      }\n    }\n    this.renderOnAddRemove && this.renderAll();\n    return this;\n  },\n\n  /**\n   * Inserts an object into collection at specified index, then renders canvas (if `renderOnAddRemove` is not `false`)\n   * An object should be an instance of (or inherit from) fabric.Object\n   * Use of this function is highly discouraged for groups.\n   * you can add a bunch of objects with the insertAt method but then you NEED\n   * to run a addWithUpdate call for the Group class or position/bbox will be wrong.\n   * @param {Object} object Object to insert\n   * @param {Number} index Index to insert object at\n   * @param {Boolean} nonSplicing When `true`, no splicing (shifting) of objects occurs\n   * @return {Self} thisArg\n   * @chainable\n   */\n  insertAt: function (object, index, nonSplicing) {\n    var objects = this.getObjects();\n    if (nonSplicing) {\n      objects[index] = object;\n    }\n    else {\n      objects.splice(index, 0, object);\n    }\n    this._onObjectAdded && this._onObjectAdded(object);\n    this.renderOnAddRemove && this.renderAll();\n    return this;\n  },\n\n  /**\n   * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`)\n   * @param {...fabric.Object} object Zero or more fabric instances\n   * @return {Self} thisArg\n   * @chainable\n   */\n  remove: function() {\n    var objects = this.getObjects(),\n        index, somethingRemoved = false;\n\n    for (var i = 0, length = arguments.length; i < length; i++) {\n      index = objects.indexOf(arguments[i]);\n\n      // only call onObjectRemoved if an object was actually removed\n      if (index !== -1) {\n        somethingRemoved = true;\n        objects.splice(index, 1);\n        this._onObjectRemoved && this._onObjectRemoved(arguments[i]);\n      }\n    }\n\n    this.renderOnAddRemove && somethingRemoved && this.renderAll();\n    return this;\n  },\n\n  /**\n   * Executes given function for each object in this group\n   * @param {Function} callback\n   *                   Callback invoked with current object as first argument,\n   *                   index - as second and an array of all objects - as third.\n   *                   Callback is invoked in a context of Global Object (e.g. `window`)\n   *                   when no `context` argument is given\n   *\n   * @param {Object} context Context (aka thisObject)\n   * @return {Self} thisArg\n   * @chainable\n   */\n  forEachObject: function(callback, context) {\n    var objects = this.getObjects();\n    for (var i = 0, len = objects.length; i < len; i++) {\n      callback.call(context, objects[i], i, objects);\n    }\n    return this;\n  },\n\n  /**\n   * Returns an array of children objects of this instance\n   * Type parameter introduced in 1.3.10\n   * @param {String} [type] When specified, only objects of this type are returned\n   * @return {Array}\n   */\n  getObjects: function(type) {\n    if (typeof type === 'undefined') {\n      return this._objects;\n    }\n    return this._objects.filter(function(o) {\n      return o.type === type;\n    });\n  },\n\n  /**\n   * Returns object at specified index\n   * @param {Number} index\n   * @return {Self} thisArg\n   */\n  item: function (index) {\n    return this.getObjects()[index];\n  },\n\n  /**\n   * Returns true if collection contains no objects\n   * @return {Boolean} true if collection is empty\n   */\n  isEmpty: function () {\n    return this.getObjects().length === 0;\n  },\n\n  /**\n   * Returns a size of a collection (i.e: length of an array containing its objects)\n   * @return {Number} Collection size\n   */\n  size: function() {\n    return this.getObjects().length;\n  },\n\n  /**\n   * Returns true if collection contains an object\n   * @param {Object} object Object to check against\n   * @return {Boolean} `true` if collection contains an object\n   */\n  contains: function(object) {\n    return this.getObjects().indexOf(object) > -1;\n  },\n\n  /**\n   * Returns number representation of a collection complexity\n   * @return {Number} complexity\n   */\n  complexity: function () {\n    return this.getObjects().reduce(function (memo, current) {\n      memo += current.complexity ? current.complexity() : 0;\n      return memo;\n    }, 0);\n  }\n};\n\n\n/**\n * @namespace fabric.CommonMethods\n */\nfabric.CommonMethods = {\n\n  /**\n   * Sets object's properties from options\n   * @param {Object} [options] Options object\n   */\n  _setOptions: function(options) {\n    for (var prop in options) {\n      this.set(prop, options[prop]);\n    }\n  },\n\n  /**\n   * @private\n   * @param {Object} [filler] Options object\n   * @param {String} [property] property to set the Gradient to\n   */\n  _initGradient: function(filler, property) {\n    if (filler && filler.colorStops && !(filler instanceof fabric.Gradient)) {\n      this.set(property, new fabric.Gradient(filler));\n    }\n  },\n\n  /**\n   * @private\n   * @param {Object} [filler] Options object\n   * @param {String} [property] property to set the Pattern to\n   * @param {Function} [callback] callback to invoke after pattern load\n   */\n  _initPattern: function(filler, property, callback) {\n    if (filler && filler.source && !(filler instanceof fabric.Pattern)) {\n      this.set(property, new fabric.Pattern(filler, callback));\n    }\n    else {\n      callback && callback();\n    }\n  },\n\n  /**\n   * @private\n   * @param {Object} [options] Options object\n   */\n  _initClipping: function(options) {\n    if (!options.clipTo || typeof options.clipTo !== 'string') {\n      return;\n    }\n\n    var functionBody = fabric.util.getFunctionBody(options.clipTo);\n    if (typeof functionBody !== 'undefined') {\n      this.clipTo = new Function('ctx', functionBody);\n    }\n  },\n\n  /**\n   * @private\n   */\n  _setObject: function(obj) {\n    for (var prop in obj) {\n      this._set(prop, obj[prop]);\n    }\n  },\n\n  /**\n   * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`.\n   * @param {String|Object} key Property name or object (if object, iterate over the object properties)\n   * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one)\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  set: function(key, value) {\n    if (typeof key === 'object') {\n      this._setObject(key);\n    }\n    else {\n      if (typeof value === 'function' && key !== 'clipTo') {\n        this._set(key, value(this.get(key)));\n      }\n      else {\n        this._set(key, value);\n      }\n    }\n    return this;\n  },\n\n  _set: function(key, value) {\n    this[key] = value;\n  },\n\n  /**\n   * Toggles specified property from `true` to `false` or from `false` to `true`\n   * @param {String} property Property to toggle\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  toggle: function(property) {\n    var value = this.get(property);\n    if (typeof value === 'boolean') {\n      this.set(property, !value);\n    }\n    return this;\n  },\n\n  /**\n   * Basic getter\n   * @param {String} property Property name\n   * @return {*} value of a property\n   */\n  get: function(property) {\n    return this[property];\n  }\n};\n\n\n(function(global) {\n\n  var sqrt = Math.sqrt,\n      atan2 = Math.atan2,\n      pow = Math.pow,\n      abs = Math.abs,\n      PiBy180 = Math.PI / 180;\n\n  /**\n   * @namespace fabric.util\n   */\n  fabric.util = {\n\n    /**\n     * Removes value from an array.\n     * Presence of value (and its position in an array) is determined via `Array.prototype.indexOf`\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} array\n     * @param {*} value\n     * @return {Array} original array\n     */\n    removeFromArray: function(array, value) {\n      var idx = array.indexOf(value);\n      if (idx !== -1) {\n        array.splice(idx, 1);\n      }\n      return array;\n    },\n\n    /**\n     * Returns random number between 2 specified ones.\n     * @static\n     * @memberOf fabric.util\n     * @param {Number} min lower limit\n     * @param {Number} max upper limit\n     * @return {Number} random value (between min and max)\n     */\n    getRandomInt: function(min, max) {\n      return Math.floor(Math.random() * (max - min + 1)) + min;\n    },\n\n    /**\n     * Transforms degrees to radians.\n     * @static\n     * @memberOf fabric.util\n     * @param {Number} degrees value in degrees\n     * @return {Number} value in radians\n     */\n    degreesToRadians: function(degrees) {\n      return degrees * PiBy180;\n    },\n\n    /**\n     * Transforms radians to degrees.\n     * @static\n     * @memberOf fabric.util\n     * @param {Number} radians value in radians\n     * @return {Number} value in degrees\n     */\n    radiansToDegrees: function(radians) {\n      return radians / PiBy180;\n    },\n\n    /**\n     * Rotates `point` around `origin` with `radians`\n     * @static\n     * @memberOf fabric.util\n     * @param {fabric.Point} point The point to rotate\n     * @param {fabric.Point} origin The origin of the rotation\n     * @param {Number} radians The radians of the angle for the rotation\n     * @return {fabric.Point} The new rotated point\n     */\n    rotatePoint: function(point, origin, radians) {\n      point.subtractEquals(origin);\n      var v = fabric.util.rotateVector(point, radians);\n      return new fabric.Point(v.x, v.y).addEquals(origin);\n    },\n\n    /**\n     * Rotates `vector` with `radians`\n     * @static\n     * @memberOf fabric.util\n     * @param {Object} vector The vector to rotate (x and y)\n     * @param {Number} radians The radians of the angle for the rotation\n     * @return {Object} The new rotated point\n     */\n    rotateVector: function(vector, radians) {\n      var sin = Math.sin(radians),\n          cos = Math.cos(radians),\n          rx = vector.x * cos - vector.y * sin,\n          ry = vector.x * sin + vector.y * cos;\n      return {\n        x: rx,\n        y: ry\n      };\n    },\n\n    /**\n     * Apply transform t to point p\n     * @static\n     * @memberOf fabric.util\n     * @param  {fabric.Point} p The point to transform\n     * @param  {Array} t The transform\n     * @param  {Boolean} [ignoreOffset] Indicates that the offset should not be applied\n     * @return {fabric.Point} The transformed point\n     */\n    transformPoint: function(p, t, ignoreOffset) {\n      if (ignoreOffset) {\n        return new fabric.Point(\n          t[0] * p.x + t[2] * p.y,\n          t[1] * p.x + t[3] * p.y\n        );\n      }\n      return new fabric.Point(\n        t[0] * p.x + t[2] * p.y + t[4],\n        t[1] * p.x + t[3] * p.y + t[5]\n      );\n    },\n\n    /**\n     * Returns coordinates of points's bounding rectangle (left, top, width, height)\n     * @param {Array} points 4 points array\n     * @return {Object} Object with left, top, width, height properties\n     */\n    makeBoundingBoxFromPoints: function(points) {\n      var xPoints = [points[0].x, points[1].x, points[2].x, points[3].x],\n          minX = fabric.util.array.min(xPoints),\n          maxX = fabric.util.array.max(xPoints),\n          width = Math.abs(minX - maxX),\n          yPoints = [points[0].y, points[1].y, points[2].y, points[3].y],\n          minY = fabric.util.array.min(yPoints),\n          maxY = fabric.util.array.max(yPoints),\n          height = Math.abs(minY - maxY);\n\n      return {\n        left: minX,\n        top: minY,\n        width: width,\n        height: height\n      };\n    },\n\n    /**\n     * Invert transformation t\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} t The transform\n     * @return {Array} The inverted transform\n     */\n    invertTransform: function(t) {\n      var a = 1 / (t[0] * t[3] - t[1] * t[2]),\n          r = [a * t[3], -a * t[1], -a * t[2], a * t[0]],\n          o = fabric.util.transformPoint({ x: t[4], y: t[5] }, r, true);\n      r[4] = -o.x;\n      r[5] = -o.y;\n      return r;\n    },\n\n    /**\n     * A wrapper around Number#toFixed, which contrary to native method returns number, not string.\n     * @static\n     * @memberOf fabric.util\n     * @param {Number|String} number number to operate on\n     * @param {Number} fractionDigits number of fraction digits to \"leave\"\n     * @return {Number}\n     */\n    toFixed: function(number, fractionDigits) {\n      return parseFloat(Number(number).toFixed(fractionDigits));\n    },\n\n    /**\n     * Converts from attribute value to pixel value if applicable.\n     * Returns converted pixels or original value not converted.\n     * @param {Number|String} value number to operate on\n     * @param {Number} fontSize\n     * @return {Number|String}\n     */\n    parseUnit: function(value, fontSize) {\n      var unit = /\\D{0,2}$/.exec(value),\n          number = parseFloat(value);\n      if (!fontSize) {\n        fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;\n      }\n      switch (unit[0]) {\n        case 'mm':\n          return number * fabric.DPI / 25.4;\n\n        case 'cm':\n          return number * fabric.DPI / 2.54;\n\n        case 'in':\n          return number * fabric.DPI;\n\n        case 'pt':\n          return number * fabric.DPI / 72; // or * 4 / 3\n\n        case 'pc':\n          return number * fabric.DPI / 72 * 12; // or * 16\n\n        case 'em':\n          return number * fontSize;\n\n        default:\n          return number;\n      }\n    },\n\n    /**\n     * Function which always returns `false`.\n     * @static\n     * @memberOf fabric.util\n     * @return {Boolean}\n     */\n    falseFunction: function() {\n      return false;\n    },\n\n    /**\n     * Returns klass \"Class\" object of given namespace\n     * @memberOf fabric.util\n     * @param {String} type Type of object (eg. 'circle')\n     * @param {String} namespace Namespace to get klass \"Class\" object from\n     * @return {Object} klass \"Class\"\n     */\n    getKlass: function(type, namespace) {\n      // capitalize first letter only\n      type = fabric.util.string.camelize(type.charAt(0).toUpperCase() + type.slice(1));\n      return fabric.util.resolveNamespace(namespace)[type];\n    },\n\n    /**\n     * Returns object of given namespace\n     * @memberOf fabric.util\n     * @param {String} namespace Namespace string e.g. 'fabric.Image.filter' or 'fabric'\n     * @return {Object} Object for given namespace (default fabric)\n     */\n    resolveNamespace: function(namespace) {\n      if (!namespace) {\n        return fabric;\n      }\n\n      var parts = namespace.split('.'),\n          len = parts.length, i,\n          obj = global || fabric.window;\n\n      for (i = 0; i < len; ++i) {\n        obj = obj[parts[i]];\n      }\n\n      return obj;\n    },\n\n    /**\n     * Loads image element from given url and passes it to a callback\n     * @memberOf fabric.util\n     * @param {String} url URL representing an image\n     * @param {Function} callback Callback; invoked with loaded image\n     * @param {*} [context] Context to invoke callback in\n     * @param {Object} [crossOrigin] crossOrigin value to set image element to\n     */\n    loadImage: function(url, callback, context, crossOrigin) {\n      if (!url) {\n        callback && callback.call(context, url);\n        return;\n      }\n\n      var img = fabric.util.createImage();\n\n      /** @ignore */\n      img.onload = function () {\n        callback && callback.call(context, img);\n        img = img.onload = img.onerror = null;\n      };\n\n      /** @ignore */\n      img.onerror = function() {\n        fabric.log('Error loading ' + img.src);\n        callback && callback.call(context, null, true);\n        img = img.onload = img.onerror = null;\n      };\n\n      // data-urls appear to be buggy with crossOrigin\n      // https://github.com/kangax/fabric.js/commit/d0abb90f1cd5c5ef9d2a94d3fb21a22330da3e0a#commitcomment-4513767\n      // see https://code.google.com/p/chromium/issues/detail?id=315152\n      //     https://bugzilla.mozilla.org/show_bug.cgi?id=935069\n      if (url.indexOf('data') !== 0 && crossOrigin) {\n        img.crossOrigin = crossOrigin;\n      }\n\n      img.src = url;\n    },\n\n    /**\n     * Creates corresponding fabric instances from their object representations\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} objects Objects to enliven\n     * @param {Function} callback Callback to invoke when all objects are created\n     * @param {String} namespace Namespace to get klass \"Class\" object from\n     * @param {Function} reviver Method for further parsing of object elements,\n     * called after each fabric object created.\n     */\n    enlivenObjects: function(objects, callback, namespace, reviver) {\n      objects = objects || [];\n\n      function onLoaded() {\n        if (++numLoadedObjects === numTotalObjects) {\n          callback && callback(enlivenedObjects);\n        }\n      }\n\n      var enlivenedObjects = [],\n          numLoadedObjects = 0,\n          numTotalObjects = objects.length,\n          forceAsync = true;\n\n      if (!numTotalObjects) {\n        callback && callback(enlivenedObjects);\n        return;\n      }\n\n      objects.forEach(function (o, index) {\n        // if sparse array\n        if (!o || !o.type) {\n          onLoaded();\n          return;\n        }\n        var klass = fabric.util.getKlass(o.type, namespace);\n        klass.fromObject(o, function (obj, error) {\n          error || (enlivenedObjects[index] = obj);\n          reviver && reviver(o, obj, error);\n          onLoaded();\n        }, forceAsync);\n      });\n    },\n\n    /**\n     * Create and wait for loading of patterns\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} objects Objects to enliven\n     * @param {Function} callback Callback to invoke when all objects are created\n     * @param {String} namespace Namespace to get klass \"Class\" object from\n     * @param {Function} reviver Method for further parsing of object elements,\n     * called after each fabric object created.\n     */\n    enlivenPatterns: function(patterns, callback) {\n      patterns = patterns || [];\n\n      function onLoaded() {\n        if (++numLoadedPatterns === numPatterns) {\n          callback && callback(enlivenedPatterns);\n        }\n      }\n\n      var enlivenedPatterns = [],\n          numLoadedPatterns = 0,\n          numPatterns = patterns.length;\n\n      if (!numPatterns) {\n        callback && callback(enlivenedPatterns);\n        return;\n      }\n\n      patterns.forEach(function (p, index) {\n        if (p && p.source) {\n          new fabric.Pattern(p, function(pattern) {\n            enlivenedPatterns[index] = pattern;\n            onLoaded();\n          });\n        }\n        else {\n          enlivenedPatterns[index] = p;\n          onLoaded();\n        }\n      });\n    },\n\n    /**\n     * Groups SVG elements (usually those retrieved from SVG document)\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} elements SVG elements to group\n     * @param {Object} [options] Options object\n     * @param {String} path Value to set sourcePath to\n     * @return {fabric.Object|fabric.PathGroup}\n     */\n    groupSVGElements: function(elements, options, path) {\n      var object;\n\n      object = new fabric.PathGroup(elements, options);\n\n      if (typeof path !== 'undefined') {\n        object.sourcePath = path;\n      }\n      return object;\n    },\n\n    /**\n     * Populates an object with properties of another object\n     * @static\n     * @memberOf fabric.util\n     * @param {Object} source Source object\n     * @param {Object} destination Destination object\n     * @return {Array} properties Propertie names to include\n     */\n    populateWithProperties: function(source, destination, properties) {\n      if (properties && Object.prototype.toString.call(properties) === '[object Array]') {\n        for (var i = 0, len = properties.length; i < len; i++) {\n          if (properties[i] in source) {\n            destination[properties[i]] = source[properties[i]];\n          }\n        }\n      }\n    },\n\n    /**\n     * Draws a dashed line between two points\n     *\n     * This method is used to draw dashed line around selection area.\n     * See <a href=\"http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas\">dotted stroke in canvas</a>\n     *\n     * @param {CanvasRenderingContext2D} ctx context\n     * @param {Number} x  start x coordinate\n     * @param {Number} y start y coordinate\n     * @param {Number} x2 end x coordinate\n     * @param {Number} y2 end y coordinate\n     * @param {Array} da dash array pattern\n     */\n    drawDashedLine: function(ctx, x, y, x2, y2, da) {\n      var dx = x2 - x,\n          dy = y2 - y,\n          len = sqrt(dx * dx + dy * dy),\n          rot = atan2(dy, dx),\n          dc = da.length,\n          di = 0,\n          draw = true;\n\n      ctx.save();\n      ctx.translate(x, y);\n      ctx.moveTo(0, 0);\n      ctx.rotate(rot);\n\n      x = 0;\n      while (len > x) {\n        x += da[di++ % dc];\n        if (x > len) {\n          x = len;\n        }\n        ctx[draw ? 'lineTo' : 'moveTo'](x, 0);\n        draw = !draw;\n      }\n\n      ctx.restore();\n    },\n\n    /**\n     * Creates canvas element and initializes it via excanvas if necessary\n     * @static\n     * @memberOf fabric.util\n     * @param {CanvasElement} [canvasEl] optional canvas element to initialize;\n     * when not given, element is created implicitly\n     * @return {CanvasElement} initialized canvas element\n     */\n    createCanvasElement: function(canvasEl) {\n      canvasEl || (canvasEl = fabric.document.createElement('canvas'));\n      /* eslint-disable camelcase */\n      if (!canvasEl.getContext && typeof G_vmlCanvasManager !== 'undefined') {\n        G_vmlCanvasManager.initElement(canvasEl);\n      }\n      /* eslint-enable camelcase */\n      return canvasEl;\n    },\n\n    /**\n     * Creates image element (works on client and node)\n     * @static\n     * @memberOf fabric.util\n     * @return {HTMLImageElement} HTML image element\n     */\n    createImage: function() {\n      return fabric.isLikelyNode\n        ? new (require('canvas').Image)()\n        : fabric.document.createElement('img');\n    },\n\n    /**\n     * Creates accessors (getXXX, setXXX) for a \"class\", based on \"stateProperties\" array\n     * @static\n     * @memberOf fabric.util\n     * @param {Object} klass \"Class\" to create accessors for\n     */\n    createAccessors: function(klass) {\n      var proto = klass.prototype, i, propName,\n          capitalizedPropName, setterName, getterName;\n\n      for (i = proto.stateProperties.length; i--; ) {\n\n        propName = proto.stateProperties[i];\n        capitalizedPropName = propName.charAt(0).toUpperCase() + propName.slice(1);\n        setterName = 'set' + capitalizedPropName;\n        getterName = 'get' + capitalizedPropName;\n\n        // using `new Function` for better introspection\n        if (!proto[getterName]) {\n          proto[getterName] = (function(property) {\n            return new Function('return this.get(\"' + property + '\")');\n          })(propName);\n        }\n        if (!proto[setterName]) {\n          proto[setterName] = (function(property) {\n            return new Function('value', 'return this.set(\"' + property + '\", value)');\n          })(propName);\n        }\n      }\n    },\n\n    /**\n     * @static\n     * @memberOf fabric.util\n     * @param {fabric.Object} receiver Object implementing `clipTo` method\n     * @param {CanvasRenderingContext2D} ctx Context to clip\n     */\n    clipContext: function(receiver, ctx) {\n      ctx.save();\n      ctx.beginPath();\n      receiver.clipTo(ctx);\n      ctx.clip();\n    },\n\n    /**\n     * Multiply matrix A by matrix B to nest transformations\n     * @static\n     * @memberOf fabric.util\n     * @param  {Array} a First transformMatrix\n     * @param  {Array} b Second transformMatrix\n     * @param  {Boolean} is2x2 flag to multiply matrices as 2x2 matrices\n     * @return {Array} The product of the two transform matrices\n     */\n    multiplyTransformMatrices: function(a, b, is2x2) {\n      // Matrix multiply a * b\n      return [\n        a[0] * b[0] + a[2] * b[1],\n        a[1] * b[0] + a[3] * b[1],\n        a[0] * b[2] + a[2] * b[3],\n        a[1] * b[2] + a[3] * b[3],\n        is2x2 ? 0 : a[0] * b[4] + a[2] * b[5] + a[4],\n        is2x2 ? 0 : a[1] * b[4] + a[3] * b[5] + a[5]\n      ];\n    },\n\n    /**\n     * Decomposes standard 2x2 matrix into transform componentes\n     * @static\n     * @memberOf fabric.util\n     * @param  {Array} a transformMatrix\n     * @return {Object} Components of transform\n     */\n    qrDecompose: function(a) {\n      var angle = atan2(a[1], a[0]),\n          denom = pow(a[0], 2) + pow(a[1], 2),\n          scaleX = sqrt(denom),\n          scaleY = (a[0] * a[3] - a[2] * a [1]) / scaleX,\n          skewX = atan2(a[0] * a[2] + a[1] * a [3], denom);\n      return {\n        angle: angle  / PiBy180,\n        scaleX: scaleX,\n        scaleY: scaleY,\n        skewX: skewX / PiBy180,\n        skewY: 0,\n        translateX: a[4],\n        translateY: a[5]\n      };\n    },\n\n    customTransformMatrix: function(scaleX, scaleY, skewX) {\n      var skewMatrixX = [1, 0, abs(Math.tan(skewX * PiBy180)), 1],\n          scaleMatrix = [abs(scaleX), 0, 0, abs(scaleY)];\n      return fabric.util.multiplyTransformMatrices(scaleMatrix, skewMatrixX, true);\n    },\n\n    resetObjectTransform: function (target) {\n      target.scaleX = 1;\n      target.scaleY = 1;\n      target.skewX = 0;\n      target.skewY = 0;\n      target.flipX = false;\n      target.flipY = false;\n      target.setAngle(0);\n    },\n\n    /**\n     * Returns string representation of function body\n     * @param {Function} fn Function to get body of\n     * @return {String} Function body\n     */\n    getFunctionBody: function(fn) {\n      return (String(fn).match(/function[^{]*\\{([\\s\\S]*)\\}/) || {})[1];\n    },\n\n    /**\n     * Returns true if context has transparent pixel\n     * at specified location (taking tolerance into account)\n     * @param {CanvasRenderingContext2D} ctx context\n     * @param {Number} x x coordinate\n     * @param {Number} y y coordinate\n     * @param {Number} tolerance Tolerance\n     */\n    isTransparent: function(ctx, x, y, tolerance) {\n\n      // If tolerance is > 0 adjust start coords to take into account.\n      // If moves off Canvas fix to 0\n      if (tolerance > 0) {\n        if (x > tolerance) {\n          x -= tolerance;\n        }\n        else {\n          x = 0;\n        }\n        if (y > tolerance) {\n          y -= tolerance;\n        }\n        else {\n          y = 0;\n        }\n      }\n\n      var _isTransparent = true, i, temp,\n          imageData = ctx.getImageData(x, y, (tolerance * 2) || 1, (tolerance * 2) || 1),\n          l = imageData.data.length;\n\n      // Split image data - for tolerance > 1, pixelDataSize = 4;\n      for (i = 3; i < l; i += 4) {\n        temp = imageData.data[i];\n        _isTransparent = temp <= 0;\n        if (_isTransparent === false) {\n          break; // Stop if colour found\n        }\n      }\n\n      imageData = null;\n\n      return _isTransparent;\n    },\n\n    /**\n     * Parse preserveAspectRatio attribute from element\n     * @param {string} attribute to be parsed\n     * @return {Object} an object containing align and meetOrSlice attribute\n     */\n    parsePreserveAspectRatioAttribute: function(attribute) {\n      var meetOrSlice = 'meet', alignX = 'Mid', alignY = 'Mid',\n          aspectRatioAttrs = attribute.split(' '), align;\n\n      if (aspectRatioAttrs && aspectRatioAttrs.length) {\n        meetOrSlice = aspectRatioAttrs.pop();\n        if (meetOrSlice !== 'meet' && meetOrSlice !== 'slice') {\n          align = meetOrSlice;\n          meetOrSlice = 'meet';\n        }\n        else if (aspectRatioAttrs.length) {\n          align = aspectRatioAttrs.pop();\n        }\n      }\n      //divide align in alignX and alignY\n      alignX = align !== 'none' ? align.slice(1, 4) : 'none';\n      alignY = align !== 'none' ? align.slice(5, 8) : 'none';\n      return {\n        meetOrSlice: meetOrSlice,\n        alignX: alignX,\n        alignY: alignY\n      };\n    },\n\n    /**\n     * Clear char widths cache for a font family.\n     * @memberOf fabric.util\n     * @param {String} [fontFamily] font family to clear\n     */\n    clearFabricFontCache: function(fontFamily) {\n      if (!fontFamily) {\n        fabric.charWidthsCache = { };\n      }\n      else if (fabric.charWidthsCache[fontFamily]) {\n        delete fabric.charWidthsCache[fontFamily];\n      }\n    },\n\n    /**\n     * Clear char widths cache for a font family.\n     * @memberOf fabric.util\n     * @param {Number} ar aspect ratio\n     * @param {Number} maximumArea Maximum area you want to achieve\n     * @param {Number} maximumSide biggest side allowed\n     * @return {Object.x} Limited dimensions by X\n     * @return {Object.y} Limited dimensions by Y\n     */\n    limitDimsByArea: function(ar, maximumArea) {\n      var roughWidth = Math.sqrt(maximumArea * ar),\n          perfLimitSizeY = Math.floor(maximumArea / roughWidth);\n      return { x: Math.floor(roughWidth), y: perfLimitSizeY };\n    },\n\n    capValue: function(min, value, max) {\n      return Math.max(min, Math.min(value, max));\n    }\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n  var arcToSegmentsCache = { },\n      segmentToBezierCache = { },\n      boundsOfCurveCache = { },\n      _join = Array.prototype.join;\n\n  /* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp\n   * by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here\n   * http://mozilla.org/MPL/2.0/\n   */\n  function arcToSegments(toX, toY, rx, ry, large, sweep, rotateX) {\n    var argsString = _join.call(arguments);\n    if (arcToSegmentsCache[argsString]) {\n      return arcToSegmentsCache[argsString];\n    }\n\n    var PI = Math.PI, th = rotateX * PI / 180,\n        sinTh = Math.sin(th),\n        cosTh = Math.cos(th),\n        fromX = 0, fromY = 0;\n\n    rx = Math.abs(rx);\n    ry = Math.abs(ry);\n\n    var px = -cosTh * toX * 0.5 - sinTh * toY * 0.5,\n        py = -cosTh * toY * 0.5 + sinTh * toX * 0.5,\n        rx2 = rx * rx, ry2 = ry * ry, py2 = py * py, px2 = px * px,\n        pl = rx2 * ry2 - rx2 * py2 - ry2 * px2,\n        root = 0;\n\n    if (pl < 0) {\n      var s = Math.sqrt(1 - pl / (rx2 * ry2));\n      rx *= s;\n      ry *= s;\n    }\n    else {\n      root = (large === sweep ? -1.0 : 1.0) *\n              Math.sqrt( pl / (rx2 * py2 + ry2 * px2));\n    }\n\n    var cx = root * rx * py / ry,\n        cy = -root * ry * px / rx,\n        cx1 = cosTh * cx - sinTh * cy + toX * 0.5,\n        cy1 = sinTh * cx + cosTh * cy + toY * 0.5,\n        mTheta = calcVectorAngle(1, 0, (px - cx) / rx, (py - cy) / ry),\n        dtheta = calcVectorAngle((px - cx) / rx, (py - cy) / ry, (-px - cx) / rx, (-py - cy) / ry);\n\n    if (sweep === 0 && dtheta > 0) {\n      dtheta -= 2 * PI;\n    }\n    else if (sweep === 1 && dtheta < 0) {\n      dtheta += 2 * PI;\n    }\n\n    // Convert into cubic bezier segments <= 90deg\n    var segments = Math.ceil(Math.abs(dtheta / PI * 2)),\n        result = [], mDelta = dtheta / segments,\n        mT = 8 / 3 * Math.sin(mDelta / 4) * Math.sin(mDelta / 4) / Math.sin(mDelta / 2),\n        th3 = mTheta + mDelta;\n\n    for (var i = 0; i < segments; i++) {\n      result[i] = segmentToBezier(mTheta, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY);\n      fromX = result[i][4];\n      fromY = result[i][5];\n      mTheta = th3;\n      th3 += mDelta;\n    }\n    arcToSegmentsCache[argsString] = result;\n    return result;\n  }\n\n  function segmentToBezier(th2, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY) {\n    var argsString2 = _join.call(arguments);\n    if (segmentToBezierCache[argsString2]) {\n      return segmentToBezierCache[argsString2];\n    }\n\n    var costh2 = Math.cos(th2),\n        sinth2 = Math.sin(th2),\n        costh3 = Math.cos(th3),\n        sinth3 = Math.sin(th3),\n        toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1,\n        toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1,\n        cp1X = fromX + mT * ( -cosTh * rx * sinth2 - sinTh * ry * costh2),\n        cp1Y = fromY + mT * ( -sinTh * rx * sinth2 + cosTh * ry * costh2),\n        cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3),\n        cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3);\n\n    segmentToBezierCache[argsString2] = [\n      cp1X, cp1Y,\n      cp2X, cp2Y,\n      toX, toY\n    ];\n    return segmentToBezierCache[argsString2];\n  }\n\n  /*\n   * Private\n   */\n  function calcVectorAngle(ux, uy, vx, vy) {\n    var ta = Math.atan2(uy, ux),\n        tb = Math.atan2(vy, vx);\n    if (tb >= ta) {\n      return tb - ta;\n    }\n    else {\n      return 2 * Math.PI - (ta - tb);\n    }\n  }\n\n  /**\n   * Draws arc\n   * @param {CanvasRenderingContext2D} ctx\n   * @param {Number} fx\n   * @param {Number} fy\n   * @param {Array} coords\n   */\n  fabric.util.drawArc = function(ctx, fx, fy, coords) {\n    var rx = coords[0],\n        ry = coords[1],\n        rot = coords[2],\n        large = coords[3],\n        sweep = coords[4],\n        tx = coords[5],\n        ty = coords[6],\n        segs = [[], [], [], []],\n        segsNorm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);\n\n    for (var i = 0, len = segsNorm.length; i < len; i++) {\n      segs[i][0] = segsNorm[i][0] + fx;\n      segs[i][1] = segsNorm[i][1] + fy;\n      segs[i][2] = segsNorm[i][2] + fx;\n      segs[i][3] = segsNorm[i][3] + fy;\n      segs[i][4] = segsNorm[i][4] + fx;\n      segs[i][5] = segsNorm[i][5] + fy;\n      ctx.bezierCurveTo.apply(ctx, segs[i]);\n    }\n  };\n\n  /**\n   * Calculate bounding box of a elliptic-arc\n   * @param {Number} fx start point of arc\n   * @param {Number} fy\n   * @param {Number} rx horizontal radius\n   * @param {Number} ry vertical radius\n   * @param {Number} rot angle of horizontal axe\n   * @param {Number} large 1 or 0, whatever the arc is the big or the small on the 2 points\n   * @param {Number} sweep 1 or 0, 1 clockwise or counterclockwise direction\n   * @param {Number} tx end point of arc\n   * @param {Number} ty\n   */\n  fabric.util.getBoundsOfArc = function(fx, fy, rx, ry, rot, large, sweep, tx, ty) {\n\n    var fromX = 0, fromY = 0, bound, bounds = [],\n        segs = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);\n\n    for (var i = 0, len = segs.length; i < len; i++) {\n      bound = getBoundsOfCurve(fromX, fromY, segs[i][0], segs[i][1], segs[i][2], segs[i][3], segs[i][4], segs[i][5]);\n      bounds.push({ x: bound[0].x + fx, y: bound[0].y + fy });\n      bounds.push({ x: bound[1].x + fx, y: bound[1].y + fy });\n      fromX = segs[i][4];\n      fromY = segs[i][5];\n    }\n    return bounds;\n  };\n\n  /**\n   * Calculate bounding box of a beziercurve\n   * @param {Number} x0 starting point\n   * @param {Number} y0\n   * @param {Number} x1 first control point\n   * @param {Number} y1\n   * @param {Number} x2 secondo control point\n   * @param {Number} y2\n   * @param {Number} x3 end of beizer\n   * @param {Number} y3\n   */\n  // taken from http://jsbin.com/ivomiq/56/edit  no credits available for that.\n  function getBoundsOfCurve(x0, y0, x1, y1, x2, y2, x3, y3) {\n    var argsString = _join.call(arguments);\n    if (boundsOfCurveCache[argsString]) {\n      return boundsOfCurveCache[argsString];\n    }\n\n    var sqrt = Math.sqrt,\n        min = Math.min, max = Math.max,\n        abs = Math.abs, tvalues = [],\n        bounds = [[], []],\n        a, b, c, t, t1, t2, b2ac, sqrtb2ac;\n\n    b = 6 * x0 - 12 * x1 + 6 * x2;\n    a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;\n    c = 3 * x1 - 3 * x0;\n\n    for (var i = 0; i < 2; ++i) {\n      if (i > 0) {\n        b = 6 * y0 - 12 * y1 + 6 * y2;\n        a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;\n        c = 3 * y1 - 3 * y0;\n      }\n\n      if (abs(a) < 1e-12) {\n        if (abs(b) < 1e-12) {\n          continue;\n        }\n        t = -c / b;\n        if (0 < t && t < 1) {\n          tvalues.push(t);\n        }\n        continue;\n      }\n      b2ac = b * b - 4 * c * a;\n      if (b2ac < 0) {\n        continue;\n      }\n      sqrtb2ac = sqrt(b2ac);\n      t1 = (-b + sqrtb2ac) / (2 * a);\n      if (0 < t1 && t1 < 1) {\n        tvalues.push(t1);\n      }\n      t2 = (-b - sqrtb2ac) / (2 * a);\n      if (0 < t2 && t2 < 1) {\n        tvalues.push(t2);\n      }\n    }\n\n    var x, y, j = tvalues.length, jlen = j, mt;\n    while (j--) {\n      t = tvalues[j];\n      mt = 1 - t;\n      x = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);\n      bounds[0][j] = x;\n\n      y = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);\n      bounds[1][j] = y;\n    }\n\n    bounds[0][jlen] = x0;\n    bounds[1][jlen] = y0;\n    bounds[0][jlen + 1] = x3;\n    bounds[1][jlen + 1] = y3;\n    var result = [\n      {\n        x: min.apply(null, bounds[0]),\n        y: min.apply(null, bounds[1])\n      },\n      {\n        x: max.apply(null, bounds[0]),\n        y: max.apply(null, bounds[1])\n      }\n    ];\n    boundsOfCurveCache[argsString] = result;\n    return result;\n  }\n\n  fabric.util.getBoundsOfCurve = getBoundsOfCurve;\n\n})();\n\n\n(function() {\n\n  var slice = Array.prototype.slice;\n\n  /* _ES5_COMPAT_START_ */\n\n  if (!Array.prototype.indexOf) {\n    /**\n     * Finds index of an element in an array\n     * @param {*} searchElement\n     * @return {Number}\n     */\n    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {\n      if (this === void 0 || this === null) {\n        throw new TypeError();\n      }\n      var t = Object(this), len = t.length >>> 0;\n      if (len === 0) {\n        return -1;\n      }\n      var n = 0;\n      if (arguments.length > 0) {\n        n = Number(arguments[1]);\n        if (n !== n) { // shortcut for verifying if it's NaN\n          n = 0;\n        }\n        else if (n !== 0 && n !== Number.POSITIVE_INFINITY && n !== Number.NEGATIVE_INFINITY) {\n          n = (n > 0 || -1) * Math.floor(Math.abs(n));\n        }\n      }\n      if (n >= len) {\n        return -1;\n      }\n      var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);\n      for (; k < len; k++) {\n        if (k in t && t[k] === searchElement) {\n          return k;\n        }\n      }\n      return -1;\n    };\n  }\n\n  if (!Array.prototype.forEach) {\n    /**\n     * Iterates an array, invoking callback for each element\n     * @param {Function} fn Callback to invoke for each element\n     * @param {Object} [context] Context to invoke callback in\n     * @return {Array}\n     */\n    Array.prototype.forEach = function(fn, context) {\n      for (var i = 0, len = this.length >>> 0; i < len; i++) {\n        if (i in this) {\n          fn.call(context, this[i], i, this);\n        }\n      }\n    };\n  }\n\n  if (!Array.prototype.map) {\n    /**\n     * Returns a result of iterating over an array, invoking callback for each element\n     * @param {Function} fn Callback to invoke for each element\n     * @param {Object} [context] Context to invoke callback in\n     * @return {Array}\n     */\n    Array.prototype.map = function(fn, context) {\n      var result = [];\n      for (var i = 0, len = this.length >>> 0; i < len; i++) {\n        if (i in this) {\n          result[i] = fn.call(context, this[i], i, this);\n        }\n      }\n      return result;\n    };\n  }\n\n  if (!Array.prototype.every) {\n    /**\n     * Returns true if a callback returns truthy value for all elements in an array\n     * @param {Function} fn Callback to invoke for each element\n     * @param {Object} [context] Context to invoke callback in\n     * @return {Boolean}\n     */\n    Array.prototype.every = function(fn, context) {\n      for (var i = 0, len = this.length >>> 0; i < len; i++) {\n        if (i in this && !fn.call(context, this[i], i, this)) {\n          return false;\n        }\n      }\n      return true;\n    };\n  }\n\n  if (!Array.prototype.some) {\n    /**\n     * Returns true if a callback returns truthy value for at least one element in an array\n     * @param {Function} fn Callback to invoke for each element\n     * @param {Object} [context] Context to invoke callback in\n     * @return {Boolean}\n     */\n    Array.prototype.some = function(fn, context) {\n      for (var i = 0, len = this.length >>> 0; i < len; i++) {\n        if (i in this && fn.call(context, this[i], i, this)) {\n          return true;\n        }\n      }\n      return false;\n    };\n  }\n\n  if (!Array.prototype.filter) {\n    /**\n     * Returns the result of iterating over elements in an array\n     * @param {Function} fn Callback to invoke for each element\n     * @param {Object} [context] Context to invoke callback in\n     * @return {Array}\n     */\n    Array.prototype.filter = function(fn, context) {\n      var result = [], val;\n      for (var i = 0, len = this.length >>> 0; i < len; i++) {\n        if (i in this) {\n          val = this[i]; // in case fn mutates this\n          if (fn.call(context, val, i, this)) {\n            result.push(val);\n          }\n        }\n      }\n      return result;\n    };\n  }\n\n  if (!Array.prototype.reduce) {\n    /**\n     * Returns \"folded\" (reduced) result of iterating over elements in an array\n     * @param {Function} fn Callback to invoke for each element\n     * @return {*}\n     */\n    Array.prototype.reduce = function(fn /*, initial*/) {\n      var len = this.length >>> 0,\n          i = 0,\n          rv;\n\n      if (arguments.length > 1) {\n        rv = arguments[1];\n      }\n      else {\n        do {\n          if (i in this) {\n            rv = this[i++];\n            break;\n          }\n          // if array contains no values, no initial value to return\n          if (++i >= len) {\n            throw new TypeError();\n          }\n        }\n        while (true);\n      }\n      for (; i < len; i++) {\n        if (i in this) {\n          rv = fn.call(null, rv, this[i], i, this);\n        }\n      }\n      return rv;\n    };\n  }\n\n  /* _ES5_COMPAT_END_ */\n\n  /**\n   * Invokes method on all items in a given array\n   * @memberOf fabric.util.array\n   * @param {Array} array Array to iterate over\n   * @param {String} method Name of a method to invoke\n   * @return {Array}\n   */\n  function invoke(array, method) {\n    var args = slice.call(arguments, 2), result = [];\n    for (var i = 0, len = array.length; i < len; i++) {\n      result[i] = args.length ? array[i][method].apply(array[i], args) : array[i][method].call(array[i]);\n    }\n    return result;\n  }\n\n  /**\n   * Finds maximum value in array (not necessarily \"first\" one)\n   * @memberOf fabric.util.array\n   * @param {Array} array Array to iterate over\n   * @param {String} byProperty\n   * @return {*}\n   */\n  function max(array, byProperty) {\n    return find(array, byProperty, function(value1, value2) {\n      return value1 >= value2;\n    });\n  }\n\n  /**\n   * Finds minimum value in array (not necessarily \"first\" one)\n   * @memberOf fabric.util.array\n   * @param {Array} array Array to iterate over\n   * @param {String} byProperty\n   * @return {*}\n   */\n  function min(array, byProperty) {\n    return find(array, byProperty, function(value1, value2) {\n      return value1 < value2;\n    });\n  }\n\n  /**\n   * @private\n   */\n  function fill(array, value) {\n    var k = array.length;\n    while (k--) {\n      array[k] = value;\n    }\n    return array;\n  }\n\n  /**\n   * @private\n   */\n  function find(array, byProperty, condition) {\n    if (!array || array.length === 0) {\n      return;\n    }\n\n    var i = array.length - 1,\n        result = byProperty ? array[i][byProperty] : array[i];\n    if (byProperty) {\n      while (i--) {\n        if (condition(array[i][byProperty], result)) {\n          result = array[i][byProperty];\n        }\n      }\n    }\n    else {\n      while (i--) {\n        if (condition(array[i], result)) {\n          result = array[i];\n        }\n      }\n    }\n    return result;\n  }\n\n  /**\n   * @namespace fabric.util.array\n   */\n  fabric.util.array = {\n    fill: fill,\n    invoke: invoke,\n    min: min,\n    max: max\n  };\n\n})();\n\n\n(function() {\n  /**\n   * Copies all enumerable properties of one js object to another\n   * Does not clone or extend fabric.Object subclasses.\n   * @memberOf fabric.util.object\n   * @param {Object} destination Where to copy to\n   * @param {Object} source Where to copy from\n   * @return {Object}\n   */\n\n  function extend(destination, source, deep) {\n    // JScript DontEnum bug is not taken care of\n    // the deep clone is for internal use, is not meant to avoid\n    // javascript traps or cloning html element or self referenced objects.\n    if (deep) {\n      if (!fabric.isLikelyNode && source instanceof Element) {\n        // avoid cloning deep images, canvases,\n        destination = source;\n      }\n      else if (source instanceof Array) {\n        destination = [];\n        for (var i = 0, len = source.length; i < len; i++) {\n          destination[i] = extend({ }, source[i], deep);\n        }\n      }\n      else if (source && typeof source === 'object') {\n        for (var property in source) {\n          if (source.hasOwnProperty(property)) {\n            destination[property] = extend({ }, source[property], deep);\n          }\n        }\n      }\n      else {\n        // this sounds odd for an extend but is ok for recursive use\n        destination = source;\n      }\n    }\n    else {\n      for (var property in source) {\n        destination[property] = source[property];\n      }\n    }\n    return destination;\n  }\n\n  /**\n   * Creates an empty object and copies all enumerable properties of another object to it\n   * @memberOf fabric.util.object\n   * @param {Object} object Object to clone\n   * @return {Object}\n   */\n  function clone(object, deep) {\n    return extend({ }, object, deep);\n  }\n\n  /** @namespace fabric.util.object */\n  fabric.util.object = {\n    extend: extend,\n    clone: clone\n  };\n\n})();\n\n\n(function() {\n\n  /* _ES5_COMPAT_START_ */\n  if (!String.prototype.trim) {\n    /**\n     * Trims a string (removing whitespace from the beginning and the end)\n     * @function external:String#trim\n     * @see <a href=\"https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/Trim\">String#trim on MDN</a>\n     */\n    String.prototype.trim = function () {\n      // this trim is not fully ES3 or ES5 compliant, but it should cover most cases for now\n      return this.replace(/^[\\s\\xA0]+/, '').replace(/[\\s\\xA0]+$/, '');\n    };\n  }\n  /* _ES5_COMPAT_END_ */\n\n  /**\n   * Camelizes a string\n   * @memberOf fabric.util.string\n   * @param {String} string String to camelize\n   * @return {String} Camelized version of a string\n   */\n  function camelize(string) {\n    return string.replace(/-+(.)?/g, function(match, character) {\n      return character ? character.toUpperCase() : '';\n    });\n  }\n\n  /**\n   * Capitalizes a string\n   * @memberOf fabric.util.string\n   * @param {String} string String to capitalize\n   * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized\n   * and other letters stay untouched, if false first letter is capitalized\n   * and other letters are converted to lowercase.\n   * @return {String} Capitalized version of a string\n   */\n  function capitalize(string, firstLetterOnly) {\n    return string.charAt(0).toUpperCase() +\n      (firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase());\n  }\n\n  /**\n   * Escapes XML in a string\n   * @memberOf fabric.util.string\n   * @param {String} string String to escape\n   * @return {String} Escaped version of a string\n   */\n  function escapeXml(string) {\n    return string.replace(/&/g, '&amp;')\n       .replace(/\"/g, '&quot;')\n       .replace(/'/g, '&apos;')\n       .replace(/</g, '&lt;')\n       .replace(/>/g, '&gt;');\n  }\n\n  /**\n   * String utilities\n   * @namespace fabric.util.string\n   */\n  fabric.util.string = {\n    camelize: camelize,\n    capitalize: capitalize,\n    escapeXml: escapeXml\n  };\n})();\n\n\n/* _ES5_COMPAT_START_ */\n(function() {\n\n  var slice = Array.prototype.slice,\n      apply = Function.prototype.apply,\n      Dummy = function() { };\n\n  if (!Function.prototype.bind) {\n    /**\n     * Cross-browser approximation of ES5 Function.prototype.bind (not fully spec conforming)\n     * @see <a href=\"https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind\">Function#bind on MDN</a>\n     * @param {Object} thisArg Object to bind function to\n     * @param {Any[]} Values to pass to a bound function\n     * @return {Function}\n     */\n    Function.prototype.bind = function(thisArg) {\n      var _this = this, args = slice.call(arguments, 1), bound;\n      if (args.length) {\n        bound = function() {\n          return apply.call(_this, this instanceof Dummy ? this : thisArg, args.concat(slice.call(arguments)));\n        };\n      }\n      else {\n        /** @ignore */\n        bound = function() {\n          return apply.call(_this, this instanceof Dummy ? this : thisArg, arguments);\n        };\n      }\n      Dummy.prototype = this.prototype;\n      bound.prototype = new Dummy();\n\n      return bound;\n    };\n  }\n\n})();\n/* _ES5_COMPAT_END_ */\n\n\n(function() {\n\n  var slice = Array.prototype.slice, emptyFunction = function() { },\n\n      IS_DONTENUM_BUGGY = (function() {\n        for (var p in { toString: 1 }) {\n          if (p === 'toString') {\n            return false;\n          }\n        }\n        return true;\n      })(),\n\n      /** @ignore */\n      addMethods = function(klass, source, parent) {\n        for (var property in source) {\n\n          if (property in klass.prototype &&\n              typeof klass.prototype[property] === 'function' &&\n              (source[property] + '').indexOf('callSuper') > -1) {\n\n            klass.prototype[property] = (function(property) {\n              return function() {\n\n                var superclass = this.constructor.superclass;\n                this.constructor.superclass = parent;\n                var returnValue = source[property].apply(this, arguments);\n                this.constructor.superclass = superclass;\n\n                if (property !== 'initialize') {\n                  return returnValue;\n                }\n              };\n            })(property);\n          }\n          else {\n            klass.prototype[property] = source[property];\n          }\n\n          if (IS_DONTENUM_BUGGY) {\n            if (source.toString !== Object.prototype.toString) {\n              klass.prototype.toString = source.toString;\n            }\n            if (source.valueOf !== Object.prototype.valueOf) {\n              klass.prototype.valueOf = source.valueOf;\n            }\n          }\n        }\n      };\n\n  function Subclass() { }\n\n  function callSuper(methodName) {\n    var parentMethod = null,\n        _this = this;\n\n    // climb prototype chain to find method not equal to callee's method\n    while (_this.constructor.superclass) {\n      var superClassMethod = _this.constructor.superclass.prototype[methodName];\n      if (_this[methodName] !== superClassMethod) {\n        parentMethod = superClassMethod;\n        break;\n      }\n      // eslint-disable-next-line\n      _this = _this.constructor.superclass.prototype;\n    }\n\n    if (!parentMethod) {\n      return console.log('tried to callSuper ' + methodName + ', method not found in prototype chain', this);\n    }\n\n    return (arguments.length > 1)\n      ? parentMethod.apply(this, slice.call(arguments, 1))\n      : parentMethod.call(this);\n  }\n\n  /**\n   * Helper for creation of \"classes\".\n   * @memberOf fabric.util\n   * @param {Function} [parent] optional \"Class\" to inherit from\n   * @param {Object} [properties] Properties shared by all instances of this class\n   *                  (be careful modifying objects defined here as this would affect all instances)\n   */\n  function createClass() {\n    var parent = null,\n        properties = slice.call(arguments, 0);\n\n    if (typeof properties[0] === 'function') {\n      parent = properties.shift();\n    }\n    function klass() {\n      this.initialize.apply(this, arguments);\n    }\n\n    klass.superclass = parent;\n    klass.subclasses = [];\n\n    if (parent) {\n      Subclass.prototype = parent.prototype;\n      klass.prototype = new Subclass();\n      parent.subclasses.push(klass);\n    }\n    for (var i = 0, length = properties.length; i < length; i++) {\n      addMethods(klass, properties[i], parent);\n    }\n    if (!klass.prototype.initialize) {\n      klass.prototype.initialize = emptyFunction;\n    }\n    klass.prototype.constructor = klass;\n    klass.prototype.callSuper = callSuper;\n    return klass;\n  }\n\n  fabric.util.createClass = createClass;\n})();\n\n\n(function () {\n\n  var unknown = 'unknown';\n\n  /* EVENT HANDLING */\n\n  function areHostMethods(object) {\n    var methodNames = Array.prototype.slice.call(arguments, 1),\n        t, i, len = methodNames.length;\n    for (i = 0; i < len; i++) {\n      t = typeof object[methodNames[i]];\n      if (!(/^(?:function|object|unknown)$/).test(t)) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  /** @ignore */\n  var getElement,\n      setElement,\n      getUniqueId = (function () {\n        var uid = 0;\n        return function (element) {\n          return element.__uniqueID || (element.__uniqueID = 'uniqueID__' + uid++);\n        };\n      })();\n\n  (function () {\n    var elements = { };\n    /** @ignore */\n    getElement = function (uid) {\n      return elements[uid];\n    };\n    /** @ignore */\n    setElement = function (uid, element) {\n      elements[uid] = element;\n    };\n  })();\n\n  function createListener(uid, handler) {\n    return {\n      handler: handler,\n      wrappedHandler: createWrappedHandler(uid, handler)\n    };\n  }\n\n  function createWrappedHandler(uid, handler) {\n    return function (e) {\n      handler.call(getElement(uid), e || fabric.window.event);\n    };\n  }\n\n  function createDispatcher(uid, eventName) {\n    return function (e) {\n      if (handlers[uid] && handlers[uid][eventName]) {\n        var handlersForEvent = handlers[uid][eventName];\n        for (var i = 0, len = handlersForEvent.length; i < len; i++) {\n          handlersForEvent[i].call(this, e || fabric.window.event);\n        }\n      }\n    };\n  }\n\n  var shouldUseAddListenerRemoveListener = (\n        areHostMethods(fabric.document.documentElement, 'addEventListener', 'removeEventListener') &&\n        areHostMethods(fabric.window, 'addEventListener', 'removeEventListener')),\n\n      shouldUseAttachEventDetachEvent = (\n        areHostMethods(fabric.document.documentElement, 'attachEvent', 'detachEvent') &&\n        areHostMethods(fabric.window, 'attachEvent', 'detachEvent')),\n\n      // IE branch\n      listeners = { },\n\n      // DOM L0 branch\n      handlers = { },\n\n      addListener, removeListener;\n\n  if (shouldUseAddListenerRemoveListener) {\n    /** @ignore */\n    addListener = function (element, eventName, handler, options) {\n      // since ie10 or ie9 can use addEventListener but they do not support options, i need to check\n      element && element.addEventListener(eventName, handler, shouldUseAttachEventDetachEvent ? false : options);\n    };\n    /** @ignore */\n    removeListener = function (element, eventName, handler, options) {\n      element && element.removeEventListener(eventName, handler, shouldUseAttachEventDetachEvent ? false : options);\n    };\n  }\n\n  else if (shouldUseAttachEventDetachEvent) {\n    /** @ignore */\n    addListener = function (element, eventName, handler) {\n      if (!element) {\n        return;\n      }\n      var uid = getUniqueId(element);\n      setElement(uid, element);\n      if (!listeners[uid]) {\n        listeners[uid] = { };\n      }\n      if (!listeners[uid][eventName]) {\n        listeners[uid][eventName] = [];\n\n      }\n      var listener = createListener(uid, handler);\n      listeners[uid][eventName].push(listener);\n      element.attachEvent('on' + eventName, listener.wrappedHandler);\n    };\n    /** @ignore */\n    removeListener = function (element, eventName, handler) {\n      if (!element) {\n        return;\n      }\n      var uid = getUniqueId(element), listener;\n      if (listeners[uid] && listeners[uid][eventName]) {\n        for (var i = 0, len = listeners[uid][eventName].length; i < len; i++) {\n          listener = listeners[uid][eventName][i];\n          if (listener && listener.handler === handler) {\n            element.detachEvent('on' + eventName, listener.wrappedHandler);\n            listeners[uid][eventName][i] = null;\n          }\n        }\n      }\n    };\n  }\n  else {\n    /** @ignore */\n    addListener = function (element, eventName, handler) {\n      if (!element) {\n        return;\n      }\n      var uid = getUniqueId(element);\n      if (!handlers[uid]) {\n        handlers[uid] = { };\n      }\n      if (!handlers[uid][eventName]) {\n        handlers[uid][eventName] = [];\n        var existingHandler = element['on' + eventName];\n        if (existingHandler) {\n          handlers[uid][eventName].push(existingHandler);\n        }\n        element['on' + eventName] = createDispatcher(uid, eventName);\n      }\n      handlers[uid][eventName].push(handler);\n    };\n    /** @ignore */\n    removeListener = function (element, eventName, handler) {\n      if (!element) {\n        return;\n      }\n      var uid = getUniqueId(element);\n      if (handlers[uid] && handlers[uid][eventName]) {\n        var handlersForEvent = handlers[uid][eventName];\n        for (var i = 0, len = handlersForEvent.length; i < len; i++) {\n          if (handlersForEvent[i] === handler) {\n            handlersForEvent.splice(i, 1);\n          }\n        }\n      }\n    };\n  }\n\n  /**\n   * Adds an event listener to an element\n   * @function\n   * @memberOf fabric.util\n   * @param {HTMLElement} element\n   * @param {String} eventName\n   * @param {Function} handler\n   */\n  fabric.util.addListener = addListener;\n\n  /**\n   * Removes an event listener from an element\n   * @function\n   * @memberOf fabric.util\n   * @param {HTMLElement} element\n   * @param {String} eventName\n   * @param {Function} handler\n   */\n  fabric.util.removeListener = removeListener;\n\n  /**\n   * Cross-browser wrapper for getting event's coordinates\n   * @memberOf fabric.util\n   * @param {Event} event Event object\n   */\n  function getPointer(event) {\n    event || (event = fabric.window.event);\n\n    var element = event.target ||\n                  (typeof event.srcElement !== unknown ? event.srcElement : null),\n\n        scroll = fabric.util.getScrollLeftTop(element);\n\n    return {\n      x: pointerX(event) + scroll.left,\n      y: pointerY(event) + scroll.top\n    };\n  }\n\n  var pointerX = function(event) {\n    // looks like in IE (<9) clientX at certain point (apparently when mouseup fires on VML element)\n    // is represented as COM object, with all the consequences, like \"unknown\" type and error on [[Get]]\n    // need to investigate later\n        return (typeof event.clientX !== unknown ? event.clientX : 0);\n      },\n\n      pointerY = function(event) {\n        return (typeof event.clientY !== unknown ? event.clientY : 0);\n      };\n\n  function _getPointer(event, pageProp, clientProp) {\n    var touchProp = event.type === 'touchend' ? 'changedTouches' : 'touches';\n\n    return (event[touchProp] && event[touchProp][0]\n      ? (event[touchProp][0][pageProp] - (event[touchProp][0][pageProp] - event[touchProp][0][clientProp]))\n        || event[clientProp]\n      : event[clientProp]);\n  }\n\n  if (fabric.isTouchSupported) {\n    pointerX = function(event) {\n      return _getPointer(event, 'pageX', 'clientX');\n    };\n    pointerY = function(event) {\n      return _getPointer(event, 'pageY', 'clientY');\n    };\n  }\n\n  fabric.util.getPointer = getPointer;\n\n  fabric.util.object.extend(fabric.util, fabric.Observable);\n\n})();\n\n\n(function () {\n\n  /**\n   * Cross-browser wrapper for setting element's style\n   * @memberOf fabric.util\n   * @param {HTMLElement} element\n   * @param {Object} styles\n   * @return {HTMLElement} Element that was passed as a first argument\n   */\n  function setStyle(element, styles) {\n    var elementStyle = element.style;\n    if (!elementStyle) {\n      return element;\n    }\n    if (typeof styles === 'string') {\n      element.style.cssText += ';' + styles;\n      return styles.indexOf('opacity') > -1\n        ? setOpacity(element, styles.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1])\n        : element;\n    }\n    for (var property in styles) {\n      if (property === 'opacity') {\n        setOpacity(element, styles[property]);\n      }\n      else {\n        var normalizedProperty = (property === 'float' || property === 'cssFloat')\n          ? (typeof elementStyle.styleFloat === 'undefined' ? 'cssFloat' : 'styleFloat')\n          : property;\n        elementStyle[normalizedProperty] = styles[property];\n      }\n    }\n    return element;\n  }\n\n  var parseEl = fabric.document.createElement('div'),\n      supportsOpacity = typeof parseEl.style.opacity === 'string',\n      supportsFilters = typeof parseEl.style.filter === 'string',\n      reOpacity = /alpha\\s*\\(\\s*opacity\\s*=\\s*([^\\)]+)\\)/,\n\n      /** @ignore */\n      setOpacity = function (element) { return element; };\n\n  if (supportsOpacity) {\n    /** @ignore */\n    setOpacity = function(element, value) {\n      element.style.opacity = value;\n      return element;\n    };\n  }\n  else if (supportsFilters) {\n    /** @ignore */\n    setOpacity = function(element, value) {\n      var es = element.style;\n      if (element.currentStyle && !element.currentStyle.hasLayout) {\n        es.zoom = 1;\n      }\n      if (reOpacity.test(es.filter)) {\n        value = value >= 0.9999 ? '' : ('alpha(opacity=' + (value * 100) + ')');\n        es.filter = es.filter.replace(reOpacity, value);\n      }\n      else {\n        es.filter += ' alpha(opacity=' + (value * 100) + ')';\n      }\n      return element;\n    };\n  }\n\n  fabric.util.setStyle = setStyle;\n\n})();\n\n\n(function() {\n\n  var _slice = Array.prototype.slice;\n\n  /**\n   * Takes id and returns an element with that id (if one exists in a document)\n   * @memberOf fabric.util\n   * @param {String|HTMLElement} id\n   * @return {HTMLElement|null}\n   */\n  function getById(id) {\n    return typeof id === 'string' ? fabric.document.getElementById(id) : id;\n  }\n\n  var sliceCanConvertNodelists,\n      /**\n       * Converts an array-like object (e.g. arguments or NodeList) to an array\n       * @memberOf fabric.util\n       * @param {Object} arrayLike\n       * @return {Array}\n       */\n      toArray = function(arrayLike) {\n        return _slice.call(arrayLike, 0);\n      };\n\n  try {\n    sliceCanConvertNodelists = toArray(fabric.document.childNodes) instanceof Array;\n  }\n  catch (err) { }\n\n  if (!sliceCanConvertNodelists) {\n    toArray = function(arrayLike) {\n      var arr = new Array(arrayLike.length), i = arrayLike.length;\n      while (i--) {\n        arr[i] = arrayLike[i];\n      }\n      return arr;\n    };\n  }\n\n  /**\n   * Creates specified element with specified attributes\n   * @memberOf fabric.util\n   * @param {String} tagName Type of an element to create\n   * @param {Object} [attributes] Attributes to set on an element\n   * @return {HTMLElement} Newly created element\n   */\n  function makeElement(tagName, attributes) {\n    var el = fabric.document.createElement(tagName);\n    for (var prop in attributes) {\n      if (prop === 'class') {\n        el.className = attributes[prop];\n      }\n      else if (prop === 'for') {\n        el.htmlFor = attributes[prop];\n      }\n      else {\n        el.setAttribute(prop, attributes[prop]);\n      }\n    }\n    return el;\n  }\n\n  /**\n   * Adds class to an element\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to add class to\n   * @param {String} className Class to add to an element\n   */\n  function addClass(element, className) {\n    if (element && (' ' + element.className + ' ').indexOf(' ' + className + ' ') === -1) {\n      element.className += (element.className ? ' ' : '') + className;\n    }\n  }\n\n  /**\n   * Wraps element with another element\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to wrap\n   * @param {HTMLElement|String} wrapper Element to wrap with\n   * @param {Object} [attributes] Attributes to set on a wrapper\n   * @return {HTMLElement} wrapper\n   */\n  function wrapElement(element, wrapper, attributes) {\n    if (typeof wrapper === 'string') {\n      wrapper = makeElement(wrapper, attributes);\n    }\n    if (element.parentNode) {\n      element.parentNode.replaceChild(wrapper, element);\n    }\n    wrapper.appendChild(element);\n    return wrapper;\n  }\n\n  /**\n   * Returns element scroll offsets\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to operate on\n   * @return {Object} Object with left/top values\n   */\n  function getScrollLeftTop(element) {\n\n    var left = 0,\n        top = 0,\n        docElement = fabric.document.documentElement,\n        body = fabric.document.body || {\n          scrollLeft: 0, scrollTop: 0\n        };\n\n    // While loop checks (and then sets element to) .parentNode OR .host\n    //  to account for ShadowDOM. We still want to traverse up out of ShadowDOM,\n    //  but the .parentNode of a root ShadowDOM node will always be null, instead\n    //  it should be accessed through .host. See http://stackoverflow.com/a/24765528/4383938\n    while (element && (element.parentNode || element.host)) {\n\n      // Set element to element parent, or 'host' in case of ShadowDOM\n      element = element.parentNode || element.host;\n\n      if (element === fabric.document) {\n        left = body.scrollLeft || docElement.scrollLeft || 0;\n        top = body.scrollTop ||  docElement.scrollTop || 0;\n      }\n      else {\n        left += element.scrollLeft || 0;\n        top += element.scrollTop || 0;\n      }\n\n      if (element.nodeType === 1 &&\n          fabric.util.getElementStyle(element, 'position') === 'fixed') {\n        break;\n      }\n    }\n\n    return { left: left, top: top };\n  }\n\n  /**\n   * Returns offset for a given element\n   * @function\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to get offset for\n   * @return {Object} Object with \"left\" and \"top\" properties\n   */\n  function getElementOffset(element) {\n    var docElem,\n        doc = element && element.ownerDocument,\n        box = { left: 0, top: 0 },\n        offset = { left: 0, top: 0 },\n        scrollLeftTop,\n        offsetAttributes = {\n          borderLeftWidth: 'left',\n          borderTopWidth:  'top',\n          paddingLeft:     'left',\n          paddingTop:      'top'\n        };\n\n    if (!doc) {\n      return offset;\n    }\n\n    for (var attr in offsetAttributes) {\n      offset[offsetAttributes[attr]] += parseInt(getElementStyle(element, attr), 10) || 0;\n    }\n\n    docElem = doc.documentElement;\n    if ( typeof element.getBoundingClientRect !== 'undefined' ) {\n      box = element.getBoundingClientRect();\n    }\n\n    scrollLeftTop = getScrollLeftTop(element);\n\n    return {\n      left: box.left + scrollLeftTop.left - (docElem.clientLeft || 0) + offset.left,\n      top: box.top + scrollLeftTop.top - (docElem.clientTop || 0)  + offset.top\n    };\n  }\n\n  /**\n   * Returns style attribute value of a given element\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to get style attribute for\n   * @param {String} attr Style attribute to get for element\n   * @return {String} Style attribute value of the given element.\n   */\n  var getElementStyle;\n  if (fabric.document.defaultView && fabric.document.defaultView.getComputedStyle) {\n    getElementStyle = function(element, attr) {\n      var style = fabric.document.defaultView.getComputedStyle(element, null);\n      return style ? style[attr] : undefined;\n    };\n  }\n  else {\n    getElementStyle = function(element, attr) {\n      var value = element.style[attr];\n      if (!value && element.currentStyle) {\n        value = element.currentStyle[attr];\n      }\n      return value;\n    };\n  }\n\n  (function () {\n    var style = fabric.document.documentElement.style,\n        selectProp = 'userSelect' in style\n          ? 'userSelect'\n          : 'MozUserSelect' in style\n            ? 'MozUserSelect'\n            : 'WebkitUserSelect' in style\n              ? 'WebkitUserSelect'\n              : 'KhtmlUserSelect' in style\n                ? 'KhtmlUserSelect'\n                : '';\n\n    /**\n     * Makes element unselectable\n     * @memberOf fabric.util\n     * @param {HTMLElement} element Element to make unselectable\n     * @return {HTMLElement} Element that was passed in\n     */\n    function makeElementUnselectable(element) {\n      if (typeof element.onselectstart !== 'undefined') {\n        element.onselectstart = fabric.util.falseFunction;\n      }\n      if (selectProp) {\n        element.style[selectProp] = 'none';\n      }\n      else if (typeof element.unselectable === 'string') {\n        element.unselectable = 'on';\n      }\n      return element;\n    }\n\n    /**\n     * Makes element selectable\n     * @memberOf fabric.util\n     * @param {HTMLElement} element Element to make selectable\n     * @return {HTMLElement} Element that was passed in\n     */\n    function makeElementSelectable(element) {\n      if (typeof element.onselectstart !== 'undefined') {\n        element.onselectstart = null;\n      }\n      if (selectProp) {\n        element.style[selectProp] = '';\n      }\n      else if (typeof element.unselectable === 'string') {\n        element.unselectable = '';\n      }\n      return element;\n    }\n\n    fabric.util.makeElementUnselectable = makeElementUnselectable;\n    fabric.util.makeElementSelectable = makeElementSelectable;\n  })();\n\n  (function() {\n\n    /**\n     * Inserts a script element with a given url into a document; invokes callback, when that script is finished loading\n     * @memberOf fabric.util\n     * @param {String} url URL of a script to load\n     * @param {Function} callback Callback to execute when script is finished loading\n     */\n    function getScript(url, callback) {\n      var headEl = fabric.document.getElementsByTagName('head')[0],\n          scriptEl = fabric.document.createElement('script'),\n          loading = true;\n\n      /** @ignore */\n      scriptEl.onload = /** @ignore */ scriptEl.onreadystatechange = function(e) {\n        if (loading) {\n          if (typeof this.readyState === 'string' &&\n              this.readyState !== 'loaded' &&\n              this.readyState !== 'complete') {\n            return;\n          }\n          loading = false;\n          callback(e || fabric.window.event);\n          scriptEl = scriptEl.onload = scriptEl.onreadystatechange = null;\n        }\n      };\n      scriptEl.src = url;\n      headEl.appendChild(scriptEl);\n      // causes issue in Opera\n      // headEl.removeChild(scriptEl);\n    }\n\n    fabric.util.getScript = getScript;\n  })();\n\n  fabric.util.getById = getById;\n  fabric.util.toArray = toArray;\n  fabric.util.makeElement = makeElement;\n  fabric.util.addClass = addClass;\n  fabric.util.wrapElement = wrapElement;\n  fabric.util.getScrollLeftTop = getScrollLeftTop;\n  fabric.util.getElementOffset = getElementOffset;\n  fabric.util.getElementStyle = getElementStyle;\n\n})();\n\n\n(function() {\n\n  function addParamToUrl(url, param) {\n    return url + (/\\?/.test(url) ? '&' : '?') + param;\n  }\n\n  var makeXHR = (function() {\n    var factories = [\n      function() { return new ActiveXObject('Microsoft.XMLHTTP'); },\n      function() { return new ActiveXObject('Msxml2.XMLHTTP'); },\n      function() { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); },\n      function() { return new XMLHttpRequest(); }\n    ];\n    for (var i = factories.length; i--; ) {\n      try {\n        var req = factories[i]();\n        if (req) {\n          return factories[i];\n        }\n      }\n      catch (err) { }\n    }\n  })();\n\n  function emptyFn() { }\n\n  /**\n   * Cross-browser abstraction for sending XMLHttpRequest\n   * @memberOf fabric.util\n   * @param {String} url URL to send XMLHttpRequest to\n   * @param {Object} [options] Options object\n   * @param {String} [options.method=\"GET\"]\n   * @param {String} [options.parameters] parameters to append to url in GET or in body\n   * @param {String} [options.body] body to send with POST or PUT request\n   * @param {Function} options.onComplete Callback to invoke when request is completed\n   * @return {XMLHttpRequest} request\n   */\n  function request(url, options) {\n\n    options || (options = { });\n\n    var method = options.method ? options.method.toUpperCase() : 'GET',\n        onComplete = options.onComplete || function() { },\n        xhr = makeXHR(),\n        body = options.body || options.parameters;\n\n    /** @ignore */\n    xhr.onreadystatechange = function() {\n      if (xhr.readyState === 4) {\n        onComplete(xhr);\n        xhr.onreadystatechange = emptyFn;\n      }\n    };\n\n    if (method === 'GET') {\n      body = null;\n      if (typeof options.parameters === 'string') {\n        url = addParamToUrl(url, options.parameters);\n      }\n    }\n\n    xhr.open(method, url, true);\n\n    if (method === 'POST' || method === 'PUT') {\n      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n    }\n\n    xhr.send(body);\n    return xhr;\n  }\n\n  fabric.util.request = request;\n})();\n\n\n/**\n * Wrapper around `console.log` (when available)\n * @param {*} [values] Values to log\n */\nfabric.log = function() { };\n\n/**\n * Wrapper around `console.warn` (when available)\n * @param {*} [values] Values to log as a warning\n */\nfabric.warn = function() { };\n\n/* eslint-disable */\nif (typeof console !== 'undefined') {\n\n  ['log', 'warn'].forEach(function(methodName) {\n\n    if (typeof console[methodName] !== 'undefined' &&\n        typeof console[methodName].apply === 'function') {\n\n      fabric[methodName] = function() {\n        return console[methodName].apply(console, arguments);\n      };\n    }\n  });\n}\n/* eslint-enable */\n\n\n(function() {\n\n  function noop() {\n    return false;\n  }\n\n  /**\n   * Changes value from one to another within certain period of time, invoking callbacks as value is being changed.\n   * @memberOf fabric.util\n   * @param {Object} [options] Animation options\n   * @param {Function} [options.onChange] Callback; invoked on every value change\n   * @param {Function} [options.onComplete] Callback; invoked when value change is completed\n   * @param {Number} [options.startValue=0] Starting value\n   * @param {Number} [options.endValue=100] Ending value\n   * @param {Number} [options.byValue=100] Value to modify the property by\n   * @param {Function} [options.easing] Easing function\n   * @param {Number} [options.duration=500] Duration of change (in ms)\n   */\n  function animate(options) {\n\n    requestAnimFrame(function(timestamp) {\n      options || (options = { });\n\n      var start = timestamp || +new Date(),\n          duration = options.duration || 500,\n          finish = start + duration, time,\n          onChange = options.onChange || noop,\n          abort = options.abort || noop,\n          onComplete = options.onComplete || noop,\n          easing = options.easing || function(t, b, c, d) {return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;},\n          startValue = 'startValue' in options ? options.startValue : 0,\n          endValue = 'endValue' in options ? options.endValue : 100,\n          byValue = options.byValue || endValue - startValue;\n\n      options.onStart && options.onStart();\n\n      (function tick(ticktime) {\n        if (abort()) {\n          onComplete(endValue, 1, 1);\n          return;\n        }\n        time = ticktime || +new Date();\n        var currentTime = time > finish ? duration : (time - start),\n            timePerc = currentTime / duration,\n            current = easing(currentTime, startValue, byValue, duration),\n            valuePerc = Math.abs((current - startValue) / byValue);\n        onChange(current, valuePerc, timePerc);\n        if (time > finish) {\n          options.onComplete && options.onComplete();\n          return;\n        }\n        requestAnimFrame(tick);\n      })(start);\n    });\n\n  }\n\n  var _requestAnimFrame = fabric.window.requestAnimationFrame       ||\n                          fabric.window.webkitRequestAnimationFrame ||\n                          fabric.window.mozRequestAnimationFrame    ||\n                          fabric.window.oRequestAnimationFrame      ||\n                          fabric.window.msRequestAnimationFrame     ||\n                          function(callback) {\n                            fabric.window.setTimeout(callback, 1000 / 60);\n                          };\n\n  /**\n   * requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/\n   * In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method\n   * @memberOf fabric.util\n   * @param {Function} callback Callback to invoke\n   * @param {DOMElement} element optional Element to associate with animation\n   */\n  function requestAnimFrame() {\n    return _requestAnimFrame.apply(fabric.window, arguments);\n  }\n\n  fabric.util.animate = animate;\n  fabric.util.requestAnimFrame = requestAnimFrame;\n\n})();\n\n\n(function() {\n  // Calculate an in-between color. Returns a \"rgba()\" string.\n  // Credit: Edwin Martin <edwin@bitstorm.org>\n  //         http://www.bitstorm.org/jquery/color-animation/jquery.animate-colors.js\n  function calculateColor(begin, end, pos) {\n    var color = 'rgba('\n        + parseInt((begin[0] + pos * (end[0] - begin[0])), 10) + ','\n        + parseInt((begin[1] + pos * (end[1] - begin[1])), 10) + ','\n        + parseInt((begin[2] + pos * (end[2] - begin[2])), 10);\n\n    color += ',' + (begin && end ? parseFloat(begin[3] + pos * (end[3] - begin[3])) : 1);\n    color += ')';\n    return color;\n  }\n\n  /**\n   * Changes the color from one to another within certain period of time, invoking callbacks as value is being changed.\n   * @memberOf fabric.util\n   * @param {String} fromColor The starting color in hex or rgb(a) format.\n   * @param {String} toColor The starting color in hex or rgb(a) format.\n   * @param {Number} [duration] Duration of change (in ms).\n   * @param {Object} [options] Animation options\n   * @param {Function} [options.onChange] Callback; invoked on every value change\n   * @param {Function} [options.onComplete] Callback; invoked when value change is completed\n   * @param {Function} [options.colorEasing] Easing function. Note that this function only take two arguments (currentTime, duration). Thus the regular animation easing functions cannot be used.\n   */\n  function animateColor(fromColor, toColor, duration, options) {\n    var startColor = new fabric.Color(fromColor).getSource(),\n        endColor = new fabric.Color(toColor).getSource();\n\n    options = options || {};\n\n    fabric.util.animate(fabric.util.object.extend(options, {\n      duration: duration || 500,\n      startValue: startColor,\n      endValue: endColor,\n      byValue: endColor,\n      easing: function (currentTime, startValue, byValue, duration) {\n        var posValue = options.colorEasing\n              ? options.colorEasing(currentTime, duration)\n              : 1 - Math.cos(currentTime / duration * (Math.PI / 2));\n        return calculateColor(startValue, byValue, posValue);\n      }\n    }));\n  }\n\n  fabric.util.animateColor = animateColor;\n\n})();\n\n\n(function() {\n\n  function normalize(a, c, p, s) {\n    if (a < Math.abs(c)) {\n      a = c;\n      s = p / 4;\n    }\n    else {\n      //handle the 0/0 case:\n      if (c === 0 && a === 0) {\n        s = p / (2 * Math.PI) * Math.asin(1);\n      }\n      else {\n        s = p / (2 * Math.PI) * Math.asin(c / a);\n      }\n    }\n    return { a: a, c: c, p: p, s: s };\n  }\n\n  function elastic(opts, t, d) {\n    return opts.a *\n      Math.pow(2, 10 * (t -= 1)) *\n      Math.sin( (t * d - opts.s) * (2 * Math.PI) / opts.p );\n  }\n\n  /**\n   * Cubic easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutCubic(t, b, c, d) {\n    return c * ((t = t / d - 1) * t * t + 1) + b;\n  }\n\n  /**\n   * Cubic easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutCubic(t, b, c, d) {\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * t * t * t + b;\n    }\n    return c / 2 * ((t -= 2) * t * t + 2) + b;\n  }\n\n  /**\n   * Quartic easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInQuart(t, b, c, d) {\n    return c * (t /= d) * t * t * t + b;\n  }\n\n  /**\n   * Quartic easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutQuart(t, b, c, d) {\n    return -c * ((t = t / d - 1) * t * t * t - 1) + b;\n  }\n\n  /**\n   * Quartic easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutQuart(t, b, c, d) {\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * t * t * t * t + b;\n    }\n    return -c / 2 * ((t -= 2) * t * t * t - 2) + b;\n  }\n\n  /**\n   * Quintic easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInQuint(t, b, c, d) {\n    return c * (t /= d) * t * t * t * t + b;\n  }\n\n  /**\n   * Quintic easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutQuint(t, b, c, d) {\n    return c * ((t = t / d - 1) * t * t * t * t + 1) + b;\n  }\n\n  /**\n   * Quintic easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutQuint(t, b, c, d) {\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * t * t * t * t * t + b;\n    }\n    return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;\n  }\n\n  /**\n   * Sinusoidal easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInSine(t, b, c, d) {\n    return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;\n  }\n\n  /**\n   * Sinusoidal easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutSine(t, b, c, d) {\n    return c * Math.sin(t / d * (Math.PI / 2)) + b;\n  }\n\n  /**\n   * Sinusoidal easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutSine(t, b, c, d) {\n    return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;\n  }\n\n  /**\n   * Exponential easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInExpo(t, b, c, d) {\n    return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;\n  }\n\n  /**\n   * Exponential easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutExpo(t, b, c, d) {\n    return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;\n  }\n\n  /**\n   * Exponential easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutExpo(t, b, c, d) {\n    if (t === 0) {\n      return b;\n    }\n    if (t === d) {\n      return b + c;\n    }\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * Math.pow(2, 10 * (t - 1)) + b;\n    }\n    return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;\n  }\n\n  /**\n   * Circular easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInCirc(t, b, c, d) {\n    return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;\n  }\n\n  /**\n   * Circular easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutCirc(t, b, c, d) {\n    return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;\n  }\n\n  /**\n   * Circular easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutCirc(t, b, c, d) {\n    t /= d / 2;\n    if (t < 1) {\n      return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;\n    }\n    return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;\n  }\n\n  /**\n   * Elastic easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInElastic(t, b, c, d) {\n    var s = 1.70158, p = 0, a = c;\n    if (t === 0) {\n      return b;\n    }\n    t /= d;\n    if (t === 1) {\n      return b + c;\n    }\n    if (!p) {\n      p = d * 0.3;\n    }\n    var opts = normalize(a, c, p, s);\n    return -elastic(opts, t, d) + b;\n  }\n\n  /**\n   * Elastic easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutElastic(t, b, c, d) {\n    var s = 1.70158, p = 0, a = c;\n    if (t === 0) {\n      return b;\n    }\n    t /= d;\n    if (t === 1) {\n      return b + c;\n    }\n    if (!p) {\n      p = d * 0.3;\n    }\n    var opts = normalize(a, c, p, s);\n    return opts.a * Math.pow(2, -10 * t) * Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) + opts.c + b;\n  }\n\n  /**\n   * Elastic easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutElastic(t, b, c, d) {\n    var s = 1.70158, p = 0, a = c;\n    if (t === 0) {\n      return b;\n    }\n    t /= d / 2;\n    if (t === 2) {\n      return b + c;\n    }\n    if (!p) {\n      p = d * (0.3 * 1.5);\n    }\n    var opts = normalize(a, c, p, s);\n    if (t < 1) {\n      return -0.5 * elastic(opts, t, d) + b;\n    }\n    return opts.a * Math.pow(2, -10 * (t -= 1)) *\n      Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) * 0.5 + opts.c + b;\n  }\n\n  /**\n   * Backwards easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInBack(t, b, c, d, s) {\n    if (s === undefined) {\n      s = 1.70158;\n    }\n    return c * (t /= d) * t * ((s + 1) * t - s) + b;\n  }\n\n  /**\n   * Backwards easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutBack(t, b, c, d, s) {\n    if (s === undefined) {\n      s = 1.70158;\n    }\n    return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;\n  }\n\n  /**\n   * Backwards easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutBack(t, b, c, d, s) {\n    if (s === undefined) {\n      s = 1.70158;\n    }\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;\n    }\n    return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;\n  }\n\n  /**\n   * Bouncing easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInBounce(t, b, c, d) {\n    return c - easeOutBounce (d - t, 0, c, d) + b;\n  }\n\n  /**\n   * Bouncing easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutBounce(t, b, c, d) {\n    if ((t /= d) < (1 / 2.75)) {\n      return c * (7.5625 * t * t) + b;\n    }\n    else if (t < (2 / 2.75)) {\n      return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;\n    }\n    else if (t < (2.5 / 2.75)) {\n      return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;\n    }\n    else {\n      return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;\n    }\n  }\n\n  /**\n   * Bouncing easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutBounce(t, b, c, d) {\n    if (t < d / 2) {\n      return easeInBounce (t * 2, 0, c, d) * 0.5 + b;\n    }\n    return easeOutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;\n  }\n\n  /**\n   * Easing functions\n   * See <a href=\"http://gizma.com/easing/\">Easing Equations by Robert Penner</a>\n   * @namespace fabric.util.ease\n   */\n  fabric.util.ease = {\n\n    /**\n     * Quadratic easing in\n     * @memberOf fabric.util.ease\n     */\n    easeInQuad: function(t, b, c, d) {\n      return c * (t /= d) * t + b;\n    },\n\n    /**\n     * Quadratic easing out\n     * @memberOf fabric.util.ease\n     */\n    easeOutQuad: function(t, b, c, d) {\n      return -c * (t /= d) * (t - 2) + b;\n    },\n\n    /**\n     * Quadratic easing in and out\n     * @memberOf fabric.util.ease\n     */\n    easeInOutQuad: function(t, b, c, d) {\n      t /= (d / 2);\n      if (t < 1) {\n        return c / 2 * t * t + b;\n      }\n      return -c / 2 * ((--t) * (t - 2) - 1) + b;\n    },\n\n    /**\n     * Cubic easing in\n     * @memberOf fabric.util.ease\n     */\n    easeInCubic: function(t, b, c, d) {\n      return c * (t /= d) * t * t + b;\n    },\n\n    easeOutCubic: easeOutCubic,\n    easeInOutCubic: easeInOutCubic,\n    easeInQuart: easeInQuart,\n    easeOutQuart: easeOutQuart,\n    easeInOutQuart: easeInOutQuart,\n    easeInQuint: easeInQuint,\n    easeOutQuint: easeOutQuint,\n    easeInOutQuint: easeInOutQuint,\n    easeInSine: easeInSine,\n    easeOutSine: easeOutSine,\n    easeInOutSine: easeInOutSine,\n    easeInExpo: easeInExpo,\n    easeOutExpo: easeOutExpo,\n    easeInOutExpo: easeInOutExpo,\n    easeInCirc: easeInCirc,\n    easeOutCirc: easeOutCirc,\n    easeInOutCirc: easeInOutCirc,\n    easeInElastic: easeInElastic,\n    easeOutElastic: easeOutElastic,\n    easeInOutElastic: easeInOutElastic,\n    easeInBack: easeInBack,\n    easeOutBack: easeOutBack,\n    easeInOutBack: easeInOutBack,\n    easeInBounce: easeInBounce,\n    easeOutBounce: easeOutBounce,\n    easeInOutBounce: easeInOutBounce\n  };\n\n})();\n\n\n(function(global) {\n\n  'use strict';\n\n  /**\n   * @name fabric\n   * @namespace\n   */\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      clone = fabric.util.object.clone,\n      toFixed = fabric.util.toFixed,\n      parseUnit = fabric.util.parseUnit,\n      multiplyTransformMatrices = fabric.util.multiplyTransformMatrices,\n\n      reAllowedSVGTagNames = /^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i,\n      reViewBoxTagNames = /^(symbol|image|marker|pattern|view|svg)$/i,\n      reNotAllowedAncestors = /^(?:pattern|defs|symbol|metadata|clipPath|mask)$/i,\n      reAllowedParents = /^(symbol|g|a|svg)$/i,\n\n      attributesMap = {\n        cx:                   'left',\n        x:                    'left',\n        r:                    'radius',\n        cy:                   'top',\n        y:                    'top',\n        display:              'visible',\n        visibility:           'visible',\n        transform:            'transformMatrix',\n        'fill-opacity':       'fillOpacity',\n        'fill-rule':          'fillRule',\n        'font-family':        'fontFamily',\n        'font-size':          'fontSize',\n        'font-style':         'fontStyle',\n        'font-weight':        'fontWeight',\n        'stroke-dasharray':   'strokeDashArray',\n        'stroke-linecap':     'strokeLineCap',\n        'stroke-linejoin':    'strokeLineJoin',\n        'stroke-miterlimit':  'strokeMiterLimit',\n        'stroke-opacity':     'strokeOpacity',\n        'stroke-width':       'strokeWidth',\n        'text-decoration':    'textDecoration',\n        'text-anchor':        'originX',\n        opacity:              'opacity'\n      },\n\n      colorAttributes = {\n        stroke: 'strokeOpacity',\n        fill:   'fillOpacity'\n      };\n\n  fabric.cssRules = { };\n  fabric.gradientDefs = { };\n\n  function normalizeAttr(attr) {\n    // transform attribute names\n    if (attr in attributesMap) {\n      return attributesMap[attr];\n    }\n    return attr;\n  }\n\n  function normalizeValue(attr, value, parentAttributes, fontSize) {\n    var isArray = Object.prototype.toString.call(value) === '[object Array]',\n        parsed;\n\n    if ((attr === 'fill' || attr === 'stroke') && value === 'none') {\n      value = '';\n    }\n    else if (attr === 'strokeDashArray') {\n      if (value === 'none') {\n        value = null;\n      }\n      else {\n        value = value.replace(/,/g, ' ').split(/\\s+/).map(function(n) {\n          return parseFloat(n);\n        });\n      }\n    }\n    else if (attr === 'transformMatrix') {\n      if (parentAttributes && parentAttributes.transformMatrix) {\n        value = multiplyTransformMatrices(\n          parentAttributes.transformMatrix, fabric.parseTransformAttribute(value));\n      }\n      else {\n        value = fabric.parseTransformAttribute(value);\n      }\n    }\n    else if (attr === 'visible') {\n      value = (value === 'none' || value === 'hidden') ? false : true;\n      // display=none on parent element always takes precedence over child element\n      if (parentAttributes && parentAttributes.visible === false) {\n        value = false;\n      }\n    }\n    else if (attr === 'opacity') {\n      value = parseFloat(value);\n      if (parentAttributes && typeof parentAttributes.opacity !== 'undefined') {\n        value *= parentAttributes.opacity;\n      }\n    }\n    else if (attr === 'originX' /* text-anchor */) {\n      value = value === 'start' ? 'left' : value === 'end' ? 'right' : 'center';\n    }\n    else {\n      parsed = isArray ? value.map(parseUnit) : parseUnit(value, fontSize);\n    }\n\n    return (!isArray && isNaN(parsed) ? value : parsed);\n  }\n\n  /**\n   * @private\n   * @param {Object} attributes Array of attributes to parse\n   */\n  function _setStrokeFillOpacity(attributes) {\n    for (var attr in colorAttributes) {\n\n      if (typeof attributes[colorAttributes[attr]] === 'undefined' || attributes[attr] === '') {\n        continue;\n      }\n\n      if (typeof attributes[attr] === 'undefined') {\n        if (!fabric.Object.prototype[attr]) {\n          continue;\n        }\n        attributes[attr] = fabric.Object.prototype[attr];\n      }\n\n      if (attributes[attr].indexOf('url(') === 0) {\n        continue;\n      }\n\n      var color = new fabric.Color(attributes[attr]);\n      attributes[attr] = color.setAlpha(toFixed(color.getAlpha() * attributes[colorAttributes[attr]], 2)).toRgba();\n    }\n    return attributes;\n  }\n\n  /**\n   * @private\n   */\n  function _getMultipleNodes(doc, nodeNames) {\n    var nodeName, nodeArray = [], nodeList;\n    for (var i = 0; i < nodeNames.length; i++) {\n      nodeName = nodeNames[i];\n      nodeList = doc.getElementsByTagName(nodeName);\n      nodeArray = nodeArray.concat(Array.prototype.slice.call(nodeList));\n    }\n    return nodeArray;\n  }\n\n  /**\n   * Parses \"transform\" attribute, returning an array of values\n   * @static\n   * @function\n   * @memberOf fabric\n   * @param {String} attributeValue String containing attribute value\n   * @return {Array} Array of 6 elements representing transformation matrix\n   */\n  fabric.parseTransformAttribute = (function() {\n    function rotateMatrix(matrix, args) {\n      var cos = Math.cos(args[0]), sin = Math.sin(args[0]),\n          x = 0, y = 0;\n      if (args.length === 3) {\n        x = args[1];\n        y = args[2];\n      }\n\n      matrix[0] = cos;\n      matrix[1] = sin;\n      matrix[2] = -sin;\n      matrix[3] = cos;\n      matrix[4] = x - (cos * x - sin * y);\n      matrix[5] = y - (sin * x + cos * y);\n    }\n\n    function scaleMatrix(matrix, args) {\n      var multiplierX = args[0],\n          multiplierY = (args.length === 2) ? args[1] : args[0];\n\n      matrix[0] = multiplierX;\n      matrix[3] = multiplierY;\n    }\n\n    function skewMatrix(matrix, args, pos) {\n      matrix[pos] = Math.tan(fabric.util.degreesToRadians(args[0]));\n    }\n\n    function translateMatrix(matrix, args) {\n      matrix[4] = args[0];\n      if (args.length === 2) {\n        matrix[5] = args[1];\n      }\n    }\n\n    // identity matrix\n    var iMatrix = [\n          1, // a\n          0, // b\n          0, // c\n          1, // d\n          0, // e\n          0  // f\n        ],\n\n        // == begin transform regexp\n        number = fabric.reNum,\n\n        commaWsp = '(?:\\\\s+,?\\\\s*|,\\\\s*)',\n\n        skewX = '(?:(skewX)\\\\s*\\\\(\\\\s*(' + number + ')\\\\s*\\\\))',\n\n        skewY = '(?:(skewY)\\\\s*\\\\(\\\\s*(' + number + ')\\\\s*\\\\))',\n\n        rotate = '(?:(rotate)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n                    commaWsp + '(' + number + ')' +\n                    commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n        scale = '(?:(scale)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n                    commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n        translate = '(?:(translate)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n                    commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n        matrix = '(?:(matrix)\\\\s*\\\\(\\\\s*' +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' +\n                  '\\\\s*\\\\))',\n\n        transform = '(?:' +\n                    matrix + '|' +\n                    translate + '|' +\n                    scale + '|' +\n                    rotate + '|' +\n                    skewX + '|' +\n                    skewY +\n                    ')',\n\n        transforms = '(?:' + transform + '(?:' + commaWsp + '*' + transform + ')*' + ')',\n\n        transformList = '^\\\\s*(?:' + transforms + '?)\\\\s*$',\n\n        // http://www.w3.org/TR/SVG/coords.html#TransformAttribute\n        reTransformList = new RegExp(transformList),\n        // == end transform regexp\n\n        reTransform = new RegExp(transform, 'g');\n\n    return function(attributeValue) {\n\n      // start with identity matrix\n      var matrix = iMatrix.concat(),\n          matrices = [];\n\n      // return if no argument was given or\n      // an argument does not match transform attribute regexp\n      if (!attributeValue || (attributeValue && !reTransformList.test(attributeValue))) {\n        return matrix;\n      }\n\n      attributeValue.replace(reTransform, function(match) {\n\n        var m = new RegExp(transform).exec(match).filter(function (match) {\n              // match !== '' && match != null\n              return (!!match);\n            }),\n            operation = m[1],\n            args = m.slice(2).map(parseFloat);\n\n        switch (operation) {\n          case 'translate':\n            translateMatrix(matrix, args);\n            break;\n          case 'rotate':\n            args[0] = fabric.util.degreesToRadians(args[0]);\n            rotateMatrix(matrix, args);\n            break;\n          case 'scale':\n            scaleMatrix(matrix, args);\n            break;\n          case 'skewX':\n            skewMatrix(matrix, args, 2);\n            break;\n          case 'skewY':\n            skewMatrix(matrix, args, 1);\n            break;\n          case 'matrix':\n            matrix = args;\n            break;\n        }\n\n        // snapshot current matrix into matrices array\n        matrices.push(matrix.concat());\n        // reset\n        matrix = iMatrix.concat();\n      });\n\n      var combinedMatrix = matrices[0];\n      while (matrices.length > 1) {\n        matrices.shift();\n        combinedMatrix = fabric.util.multiplyTransformMatrices(combinedMatrix, matrices[0]);\n      }\n      return combinedMatrix;\n    };\n  })();\n\n  /**\n   * @private\n   */\n  function parseStyleString(style, oStyle) {\n    var attr, value;\n    style.replace(/;\\s*$/, '').split(';').forEach(function (chunk) {\n      var pair = chunk.split(':');\n\n      attr = pair[0].trim().toLowerCase();\n      value =  pair[1].trim();\n\n      oStyle[attr] = value;\n    });\n  }\n\n  /**\n   * @private\n   */\n  function parseStyleObject(style, oStyle) {\n    var attr, value;\n    for (var prop in style) {\n      if (typeof style[prop] === 'undefined') {\n        continue;\n      }\n\n      attr = prop.toLowerCase();\n      value = style[prop];\n\n      oStyle[attr] = value;\n    }\n  }\n\n  /**\n   * @private\n   */\n  function getGlobalStylesForElement(element, svgUid) {\n    var styles = { };\n    for (var rule in fabric.cssRules[svgUid]) {\n      if (elementMatchesRule(element, rule.split(' '))) {\n        for (var property in fabric.cssRules[svgUid][rule]) {\n          styles[property] = fabric.cssRules[svgUid][rule][property];\n        }\n      }\n    }\n    return styles;\n  }\n\n  /**\n   * @private\n   */\n  function elementMatchesRule(element, selectors) {\n    var firstMatching, parentMatching = true;\n    //start from rightmost selector.\n    firstMatching = selectorMatches(element, selectors.pop());\n    if (firstMatching && selectors.length) {\n      parentMatching = doesSomeParentMatch(element, selectors);\n    }\n    return firstMatching && parentMatching && (selectors.length === 0);\n  }\n\n  function doesSomeParentMatch(element, selectors) {\n    var selector, parentMatching = true;\n    while (element.parentNode && element.parentNode.nodeType === 1 && selectors.length) {\n      if (parentMatching) {\n        selector = selectors.pop();\n      }\n      element = element.parentNode;\n      parentMatching = selectorMatches(element, selector);\n    }\n    return selectors.length === 0;\n  }\n\n  /**\n   * @private\n   */\n  function selectorMatches(element, selector) {\n    var nodeName = element.nodeName,\n        classNames = element.getAttribute('class'),\n        id = element.getAttribute('id'), matcher;\n    // i check if a selector matches slicing away part from it.\n    // if i get empty string i should match\n    matcher = new RegExp('^' + nodeName, 'i');\n    selector = selector.replace(matcher, '');\n    if (id && selector.length) {\n      matcher = new RegExp('#' + id + '(?![a-zA-Z\\\\-]+)', 'i');\n      selector = selector.replace(matcher, '');\n    }\n    if (classNames && selector.length) {\n      classNames = classNames.split(' ');\n      for (var i = classNames.length; i--;) {\n        matcher = new RegExp('\\\\.' + classNames[i] + '(?![a-zA-Z\\\\-]+)', 'i');\n        selector = selector.replace(matcher, '');\n      }\n    }\n    return selector.length === 0;\n  }\n\n  /**\n   * @private\n   * to support IE8 missing getElementById on SVGdocument\n   */\n  function elementById(doc, id) {\n    var el;\n    doc.getElementById && (el = doc.getElementById(id));\n    if (el) {\n      return el;\n    }\n    var node, i, nodelist = doc.getElementsByTagName('*');\n    for (i = 0; i < nodelist.length; i++) {\n      node = nodelist[i];\n      if (id === node.getAttribute('id')) {\n        return node;\n      }\n    }\n  }\n\n  /**\n   * @private\n   */\n  function parseUseDirectives(doc) {\n    var nodelist = _getMultipleNodes(doc, ['use', 'svg:use']), i = 0;\n\n    while (nodelist.length && i < nodelist.length) {\n      var el = nodelist[i],\n          xlink = el.getAttribute('xlink:href').substr(1),\n          x = el.getAttribute('x') || 0,\n          y = el.getAttribute('y') || 0,\n          el2 = elementById(doc, xlink).cloneNode(true),\n          currentTrans = (el2.getAttribute('transform') || '') + ' translate(' + x + ', ' + y + ')',\n          parentNode, oldLength = nodelist.length, attr, j, attrs, l;\n\n      applyViewboxTransform(el2);\n      if (/^svg$/i.test(el2.nodeName)) {\n        var el3 = el2.ownerDocument.createElement('g');\n        for (j = 0, attrs = el2.attributes, l = attrs.length; j < l; j++) {\n          attr = attrs.item(j);\n          el3.setAttribute(attr.nodeName, attr.nodeValue);\n        }\n        // el2.firstChild != null\n        while (el2.firstChild) {\n          el3.appendChild(el2.firstChild);\n        }\n        el2 = el3;\n      }\n\n      for (j = 0, attrs = el.attributes, l = attrs.length; j < l; j++) {\n        attr = attrs.item(j);\n        if (attr.nodeName === 'x' || attr.nodeName === 'y' || attr.nodeName === 'xlink:href') {\n          continue;\n        }\n\n        if (attr.nodeName === 'transform') {\n          currentTrans = attr.nodeValue + ' ' + currentTrans;\n        }\n        else {\n          el2.setAttribute(attr.nodeName, attr.nodeValue);\n        }\n      }\n\n      el2.setAttribute('transform', currentTrans);\n      el2.setAttribute('instantiated_by_use', '1');\n      el2.removeAttribute('id');\n      parentNode = el.parentNode;\n      parentNode.replaceChild(el2, el);\n      // some browsers do not shorten nodelist after replaceChild (IE8)\n      if (nodelist.length === oldLength) {\n        i++;\n      }\n    }\n  }\n\n  // http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute\n  // matches, e.g.: +14.56e-12, etc.\n  var reViewBoxAttrValue = new RegExp(\n    '^' +\n    '\\\\s*(' + fabric.reNum + '+)\\\\s*,?' +\n    '\\\\s*(' + fabric.reNum + '+)\\\\s*,?' +\n    '\\\\s*(' + fabric.reNum + '+)\\\\s*,?' +\n    '\\\\s*(' + fabric.reNum + '+)\\\\s*' +\n    '$'\n  );\n\n  /**\n   * Add a <g> element that envelop all child elements and makes the viewbox transformMatrix descend on all elements\n   */\n  function applyViewboxTransform(element) {\n\n    var viewBoxAttr = element.getAttribute('viewBox'),\n        scaleX = 1,\n        scaleY = 1,\n        minX = 0,\n        minY = 0,\n        viewBoxWidth, viewBoxHeight, matrix, el,\n        widthAttr = element.getAttribute('width'),\n        heightAttr = element.getAttribute('height'),\n        x = element.getAttribute('x') || 0,\n        y = element.getAttribute('y') || 0,\n        preserveAspectRatio = element.getAttribute('preserveAspectRatio') || '',\n        missingViewBox = (!viewBoxAttr || !reViewBoxTagNames.test(element.nodeName)\n                           || !(viewBoxAttr = viewBoxAttr.match(reViewBoxAttrValue))),\n        missingDimAttr = (!widthAttr || !heightAttr || widthAttr === '100%' || heightAttr === '100%'),\n        toBeParsed = missingViewBox && missingDimAttr,\n        parsedDim = { }, translateMatrix = '';\n\n    parsedDim.width = 0;\n    parsedDim.height = 0;\n    parsedDim.toBeParsed = toBeParsed;\n\n    if (toBeParsed) {\n      return parsedDim;\n    }\n\n    if (missingViewBox) {\n      parsedDim.width = parseUnit(widthAttr);\n      parsedDim.height = parseUnit(heightAttr);\n      return parsedDim;\n    }\n\n    minX = -parseFloat(viewBoxAttr[1]);\n    minY = -parseFloat(viewBoxAttr[2]);\n    viewBoxWidth = parseFloat(viewBoxAttr[3]);\n    viewBoxHeight = parseFloat(viewBoxAttr[4]);\n\n    if (!missingDimAttr) {\n      parsedDim.width = parseUnit(widthAttr);\n      parsedDim.height = parseUnit(heightAttr);\n      scaleX = parsedDim.width / viewBoxWidth;\n      scaleY = parsedDim.height / viewBoxHeight;\n    }\n    else {\n      parsedDim.width = viewBoxWidth;\n      parsedDim.height = viewBoxHeight;\n    }\n\n    // default is to preserve aspect ratio\n    preserveAspectRatio = fabric.util.parsePreserveAspectRatioAttribute(preserveAspectRatio);\n    if (preserveAspectRatio.alignX !== 'none') {\n      //translate all container for the effect of Mid, Min, Max\n      scaleY = scaleX = (scaleX > scaleY ? scaleY : scaleX);\n    }\n\n    if (scaleX === 1 && scaleY === 1 && minX === 0 && minY === 0 && x === 0 && y === 0) {\n      return parsedDim;\n    }\n\n    if (x || y) {\n      translateMatrix = ' translate(' + parseUnit(x) + ' ' + parseUnit(y) + ') ';\n    }\n\n    matrix = translateMatrix + ' matrix(' + scaleX +\n                  ' 0' +\n                  ' 0 ' +\n                  scaleY + ' ' +\n                  (minX * scaleX) + ' ' +\n                  (minY * scaleY) + ') ';\n\n    if (element.nodeName === 'svg') {\n      el = element.ownerDocument.createElement('g');\n      // element.firstChild != null\n      while (element.firstChild) {\n        el.appendChild(element.firstChild);\n      }\n      element.appendChild(el);\n    }\n    else {\n      el = element;\n      matrix = el.getAttribute('transform') + matrix;\n    }\n\n    el.setAttribute('transform', matrix);\n    return parsedDim;\n  }\n\n  function hasAncestorWithNodeName(element, nodeName) {\n    while (element && (element = element.parentNode)) {\n      if (element.nodeName && nodeName.test(element.nodeName.replace('svg:', ''))\n        && !element.getAttribute('instantiated_by_use')) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  /**\n   * Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback\n   * @static\n   * @function\n   * @memberOf fabric\n   * @param {SVGDocument} doc SVG document to parse\n   * @param {Function} callback Callback to call when parsing is finished;\n   * It's being passed an array of elements (parsed from a document).\n   * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n   * @param {Object} [parsingOptions] options for parsing document\n   * @param {String} [parsingOptions.crossOrigin] crossOrigin settings\n   */\n  fabric.parseSVGDocument = function(doc, callback, reviver, parsingOptions) {\n    if (!doc) {\n      return;\n    }\n\n    parseUseDirectives(doc);\n\n    var svgUid =  fabric.Object.__uid++,\n        options = applyViewboxTransform(doc),\n        descendants = fabric.util.toArray(doc.getElementsByTagName('*'));\n    options.crossOrigin = parsingOptions && parsingOptions.crossOrigin;\n    options.svgUid = svgUid;\n\n    if (descendants.length === 0 && fabric.isLikelyNode) {\n      // we're likely in node, where \"o3-xml\" library fails to gEBTN(\"*\")\n      // https://github.com/ajaxorg/node-o3-xml/issues/21\n      descendants = doc.selectNodes('//*[name(.)!=\"svg\"]');\n      var arr = [];\n      for (var i = 0, len = descendants.length; i < len; i++) {\n        arr[i] = descendants[i];\n      }\n      descendants = arr;\n    }\n\n    var elements = descendants.filter(function(el) {\n      applyViewboxTransform(el);\n      return reAllowedSVGTagNames.test(el.nodeName.replace('svg:', '')) &&\n            !hasAncestorWithNodeName(el, reNotAllowedAncestors); // http://www.w3.org/TR/SVG/struct.html#DefsElement\n    });\n\n    if (!elements || (elements && !elements.length)) {\n      callback && callback([], {});\n      return;\n    }\n\n    fabric.gradientDefs[svgUid] = fabric.getGradientDefs(doc);\n    fabric.cssRules[svgUid] = fabric.getCSSRules(doc);\n    // Precedence of rules:   style > class > attribute\n    fabric.parseElements(elements, function(instances) {\n      if (callback) {\n        callback(instances, options);\n      }\n    }, clone(options), reviver, parsingOptions);\n  };\n\n  var reFontDeclaration = new RegExp(\n    '(normal|italic)?\\\\s*(normal|small-caps)?\\\\s*' +\n    '(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\\\\s*(' +\n      fabric.reNum +\n    '(?:px|cm|mm|em|pt|pc|in)*)(?:\\\\/(normal|' + fabric.reNum + '))?\\\\s+(.*)');\n\n  extend(fabric, {\n    /**\n     * Parses a short font declaration, building adding its properties to a style object\n     * @static\n     * @function\n     * @memberOf fabric\n     * @param {String} value font declaration\n     * @param {Object} oStyle definition\n     */\n    parseFontDeclaration: function(value, oStyle) {\n      var match = value.match(reFontDeclaration);\n\n      if (!match) {\n        return;\n      }\n      var fontStyle = match[1],\n          // font variant is not used\n          // fontVariant = match[2],\n          fontWeight = match[3],\n          fontSize = match[4],\n          lineHeight = match[5],\n          fontFamily = match[6];\n\n      if (fontStyle) {\n        oStyle.fontStyle = fontStyle;\n      }\n      if (fontWeight) {\n        oStyle.fontWeight = isNaN(parseFloat(fontWeight)) ? fontWeight : parseFloat(fontWeight);\n      }\n      if (fontSize) {\n        oStyle.fontSize = parseUnit(fontSize);\n      }\n      if (fontFamily) {\n        oStyle.fontFamily = fontFamily;\n      }\n      if (lineHeight) {\n        oStyle.lineHeight = lineHeight === 'normal' ? 1 : lineHeight;\n      }\n    },\n\n    /**\n     * Parses an SVG document, returning all of the gradient declarations found in it\n     * @static\n     * @function\n     * @memberOf fabric\n     * @param {SVGDocument} doc SVG document to parse\n     * @return {Object} Gradient definitions; key corresponds to element id, value -- to gradient definition element\n     */\n    getGradientDefs: function(doc) {\n      var tagArray = [\n            'linearGradient',\n            'radialGradient',\n            'svg:linearGradient',\n            'svg:radialGradient'],\n          elList = _getMultipleNodes(doc, tagArray),\n          el, j = 0, id, xlink,\n          gradientDefs = { }, idsToXlinkMap = { };\n\n      j = elList.length;\n\n      while (j--) {\n        el = elList[j];\n        xlink = el.getAttribute('xlink:href');\n        id = el.getAttribute('id');\n        if (xlink) {\n          idsToXlinkMap[id] = xlink.substr(1);\n        }\n        gradientDefs[id] = el;\n      }\n\n      for (id in idsToXlinkMap) {\n        var el2 = gradientDefs[idsToXlinkMap[id]].cloneNode(true);\n        el = gradientDefs[id];\n        while (el2.firstChild) {\n          el.appendChild(el2.firstChild);\n        }\n      }\n      return gradientDefs;\n    },\n\n    /**\n     * Returns an object of attributes' name/value, given element and an array of attribute names;\n     * Parses parent \"g\" nodes recursively upwards.\n     * @static\n     * @memberOf fabric\n     * @param {DOMElement} element Element to parse\n     * @param {Array} attributes Array of attributes to parse\n     * @return {Object} object containing parsed attributes' names/values\n     */\n    parseAttributes: function(element, attributes, svgUid) {\n\n      if (!element) {\n        return;\n      }\n\n      var value,\n          parentAttributes = { },\n          fontSize;\n\n      if (typeof svgUid === 'undefined') {\n        svgUid = element.getAttribute('svgUid');\n      }\n      // if there's a parent container (`g` or `a` or `symbol` node), parse its attributes recursively upwards\n      if (element.parentNode && reAllowedParents.test(element.parentNode.nodeName)) {\n        parentAttributes = fabric.parseAttributes(element.parentNode, attributes, svgUid);\n      }\n      fontSize = (parentAttributes && parentAttributes.fontSize ) ||\n                 element.getAttribute('font-size') || fabric.Text.DEFAULT_SVG_FONT_SIZE;\n\n      var ownAttributes = attributes.reduce(function(memo, attr) {\n        value = element.getAttribute(attr);\n        if (value) { // eslint-disable-line\n          memo[attr] = value;\n        }\n        return memo;\n      }, { });\n      // add values parsed from style, which take precedence over attributes\n      // (see: http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes)\n      ownAttributes = extend(ownAttributes,\n        extend(getGlobalStylesForElement(element, svgUid), fabric.parseStyleAttribute(element)));\n\n      var normalizedAttr, normalizedValue, normalizedStyle = {};\n      for (var attr in ownAttributes) {\n        normalizedAttr = normalizeAttr(attr);\n        normalizedValue = normalizeValue(normalizedAttr, ownAttributes[attr], parentAttributes, fontSize);\n        normalizedStyle[normalizedAttr] = normalizedValue;\n      }\n      if (normalizedStyle && normalizedStyle.font) {\n        fabric.parseFontDeclaration(normalizedStyle.font, normalizedStyle);\n      }\n      var mergedAttrs = extend(parentAttributes, normalizedStyle);\n      return reAllowedParents.test(element.nodeName) ? mergedAttrs : _setStrokeFillOpacity(mergedAttrs);\n    },\n\n    /**\n     * Transforms an array of svg elements to corresponding fabric.* instances\n     * @static\n     * @memberOf fabric\n     * @param {Array} elements Array of elements to parse\n     * @param {Function} callback Being passed an array of fabric instances (transformed from SVG elements)\n     * @param {Object} [options] Options object\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     */\n    parseElements: function(elements, callback, options, reviver, parsingOptions) {\n      new fabric.ElementsParser(elements, callback, options, reviver, parsingOptions).parse();\n    },\n\n    /**\n     * Parses \"style\" attribute, retuning an object with values\n     * @static\n     * @memberOf fabric\n     * @param {SVGElement} element Element to parse\n     * @return {Object} Objects with values parsed from style attribute of an element\n     */\n    parseStyleAttribute: function(element) {\n      var oStyle = { },\n          style = element.getAttribute('style');\n\n      if (!style) {\n        return oStyle;\n      }\n\n      if (typeof style === 'string') {\n        parseStyleString(style, oStyle);\n      }\n      else {\n        parseStyleObject(style, oStyle);\n      }\n\n      return oStyle;\n    },\n\n    /**\n     * Parses \"points\" attribute, returning an array of values\n     * @static\n     * @memberOf fabric\n     * @param {String} points points attribute string\n     * @return {Array} array of points\n     */\n    parsePointsAttribute: function(points) {\n\n      // points attribute is required and must not be empty\n      if (!points) {\n        return null;\n      }\n\n      // replace commas with whitespace and remove bookending whitespace\n      points = points.replace(/,/g, ' ').trim();\n\n      points = points.split(/\\s+/);\n      var parsedPoints = [], i, len;\n\n      i = 0;\n      len = points.length;\n      for (; i < len; i += 2) {\n        parsedPoints.push({\n          x: parseFloat(points[i]),\n          y: parseFloat(points[i + 1])\n        });\n      }\n\n      // odd number of points is an error\n      // if (parsedPoints.length % 2 !== 0) {\n      //   return null;\n      // }\n\n      return parsedPoints;\n    },\n\n    /**\n     * Returns CSS rules for a given SVG document\n     * @static\n     * @function\n     * @memberOf fabric\n     * @param {SVGDocument} doc SVG document to parse\n     * @return {Object} CSS rules of this document\n     */\n    getCSSRules: function(doc) {\n      var styles = doc.getElementsByTagName('style'),\n          allRules = { }, rules;\n\n      // very crude parsing of style contents\n      for (var i = 0, len = styles.length; i < len; i++) {\n        // IE9 doesn't support textContent, but provides text instead.\n        var styleContents = styles[i].textContent || styles[i].text;\n\n        // remove comments\n        styleContents = styleContents.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\n        if (styleContents.trim() === '') {\n          continue;\n        }\n        rules = styleContents.match(/[^{]*\\{[\\s\\S]*?\\}/g);\n        rules = rules.map(function(rule) { return rule.trim(); });\n        rules.forEach(function(rule) {\n\n          var match = rule.match(/([\\s\\S]*?)\\s*\\{([^}]*)\\}/),\n              ruleObj = { }, declaration = match[2].trim(),\n              propertyValuePairs = declaration.replace(/;$/, '').split(/\\s*;\\s*/);\n\n          for (var i = 0, len = propertyValuePairs.length; i < len; i++) {\n            var pair = propertyValuePairs[i].split(/\\s*:\\s*/),\n                property = pair[0],\n                value = pair[1];\n            ruleObj[property] = value;\n          }\n          rule = match[1];\n          rule.split(',').forEach(function(_rule) {\n            _rule = _rule.replace(/^svg/i, '').trim();\n            if (_rule === '') {\n              return;\n            }\n            if (allRules[_rule]) {\n              fabric.util.object.extend(allRules[_rule], ruleObj);\n            }\n            else {\n              allRules[_rule] = fabric.util.object.clone(ruleObj);\n            }\n          });\n        });\n      }\n      return allRules;\n    },\n\n    /**\n     * Takes url corresponding to an SVG document, and parses it into a set of fabric objects.\n     * Note that SVG is fetched via XMLHttpRequest, so it needs to conform to SOP (Same Origin Policy)\n     * @memberOf fabric\n     * @param {String} url\n     * @param {Function} callback\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     * @param {Object} [options] Object containing options for parsing\n     * @param {String} [options.crossOrigin] crossOrigin crossOrigin setting to use for external resources\n     */\n    loadSVGFromURL: function(url, callback, reviver, options) {\n\n      url = url.replace(/^\\n\\s*/, '').trim();\n      new fabric.util.request(url, {\n        method: 'get',\n        onComplete: onComplete\n      });\n\n      function onComplete(r) {\n\n        var xml = r.responseXML;\n        if (xml && !xml.documentElement && fabric.window.ActiveXObject && r.responseText) {\n          xml = new ActiveXObject('Microsoft.XMLDOM');\n          xml.async = 'false';\n          //IE chokes on DOCTYPE\n          xml.loadXML(r.responseText.replace(/<!DOCTYPE[\\s\\S]*?(\\[[\\s\\S]*\\])*?>/i, ''));\n        }\n        if (!xml || !xml.documentElement) {\n          callback && callback(null);\n        }\n\n        fabric.parseSVGDocument(xml.documentElement, function (results, _options) {\n          callback && callback(results, _options);\n        }, reviver, options);\n      }\n    },\n\n    /**\n     * Takes string corresponding to an SVG document, and parses it into a set of fabric objects\n     * @memberOf fabric\n     * @param {String} string\n     * @param {Function} callback\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     * @param {Object} [options] Object containing options for parsing\n     * @param {String} [options.crossOrigin] crossOrigin crossOrigin setting to use for external resources\n     */\n    loadSVGFromString: function(string, callback, reviver, options) {\n      string = string.trim();\n      var doc;\n      if (typeof DOMParser !== 'undefined') {\n        var parser = new DOMParser();\n        if (parser && parser.parseFromString) {\n          doc = parser.parseFromString(string, 'text/xml');\n        }\n      }\n      else if (fabric.window.ActiveXObject) {\n        doc = new ActiveXObject('Microsoft.XMLDOM');\n        doc.async = 'false';\n        // IE chokes on DOCTYPE\n        doc.loadXML(string.replace(/<!DOCTYPE[\\s\\S]*?(\\[[\\s\\S]*\\])*?>/i, ''));\n      }\n\n      fabric.parseSVGDocument(doc.documentElement, function (results, _options) {\n        callback(results, _options);\n      }, reviver, options);\n    }\n  });\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\nfabric.ElementsParser = function(elements, callback, options, reviver, parsingOptions) {\n  this.elements = elements;\n  this.callback = callback;\n  this.options = options;\n  this.reviver = reviver;\n  this.svgUid = (options && options.svgUid) || 0;\n  this.parsingOptions = parsingOptions;\n};\n\nfabric.ElementsParser.prototype.parse = function() {\n  this.instances = new Array(this.elements.length);\n  this.numElements = this.elements.length;\n\n  this.createObjects();\n};\n\nfabric.ElementsParser.prototype.createObjects = function() {\n  for (var i = 0, len = this.elements.length; i < len; i++) {\n    this.elements[i].setAttribute('svgUid', this.svgUid);\n    (function(_obj, i) {\n      setTimeout(function() {\n        _obj.createObject(_obj.elements[i], i);\n      }, 0);\n    })(this, i);\n  }\n};\n\nfabric.ElementsParser.prototype.createObject = function(el, index) {\n  var klass = fabric[fabric.util.string.capitalize(el.tagName.replace('svg:', ''))];\n  if (klass && klass.fromElement) {\n    try {\n      this._createObject(klass, el, index);\n    }\n    catch (err) {\n      fabric.log(err);\n    }\n  }\n  else {\n    this.checkIfDone();\n  }\n};\n\nfabric.ElementsParser.prototype._createObject = function(klass, el, index) {\n  if (klass.async) {\n    klass.fromElement(el, this.createCallback(index, el), this.options);\n  }\n  else {\n    var obj = klass.fromElement(el, this.options);\n    this.resolveGradient(obj, 'fill');\n    this.resolveGradient(obj, 'stroke');\n    this.reviver && this.reviver(el, obj);\n    this.instances[index] = obj;\n    this.checkIfDone();\n  }\n};\n\nfabric.ElementsParser.prototype.createCallback = function(index, el) {\n  var _this = this;\n  return function(obj) {\n    _this.resolveGradient(obj, 'fill');\n    _this.resolveGradient(obj, 'stroke');\n    _this.reviver && _this.reviver(el, obj);\n    _this.instances[index] = obj;\n    _this.checkIfDone();\n  };\n};\n\nfabric.ElementsParser.prototype.resolveGradient = function(obj, property) {\n\n  var instanceFillValue = obj.get(property);\n  if (!(/^url\\(/).test(instanceFillValue)) {\n    return;\n  }\n  var gradientId = instanceFillValue.slice(5, instanceFillValue.length - 1);\n  if (fabric.gradientDefs[this.svgUid][gradientId]) {\n    obj.set(property,\n      fabric.Gradient.fromElement(fabric.gradientDefs[this.svgUid][gradientId], obj));\n  }\n};\n\nfabric.ElementsParser.prototype.checkIfDone = function() {\n  if (--this.numElements === 0) {\n    this.instances = this.instances.filter(function(el) {\n      // eslint-disable-next-line no-eq-null, eqeqeq\n      return el != null;\n    });\n    this.callback(this.instances);\n  }\n};\n\n\n(function(global) {\n\n  'use strict';\n\n  /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */\n\n  var fabric = global.fabric || (global.fabric = { });\n\n  if (fabric.Point) {\n    fabric.warn('fabric.Point is already defined');\n    return;\n  }\n\n  fabric.Point = Point;\n\n  /**\n   * Point class\n   * @class fabric.Point\n   * @memberOf fabric\n   * @constructor\n   * @param {Number} x\n   * @param {Number} y\n   * @return {fabric.Point} thisArg\n   */\n  function Point(x, y) {\n    this.x = x;\n    this.y = y;\n  }\n\n  Point.prototype = /** @lends fabric.Point.prototype */ {\n\n    type: 'point',\n\n    constructor: Point,\n\n    /**\n     * Adds another point to this one and returns another one\n     * @param {fabric.Point} that\n     * @return {fabric.Point} new Point instance with added values\n     */\n    add: function (that) {\n      return new Point(this.x + that.x, this.y + that.y);\n    },\n\n    /**\n     * Adds another point to this one\n     * @param {fabric.Point} that\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    addEquals: function (that) {\n      this.x += that.x;\n      this.y += that.y;\n      return this;\n    },\n\n    /**\n     * Adds value to this point and returns a new one\n     * @param {Number} scalar\n     * @return {fabric.Point} new Point with added value\n     */\n    scalarAdd: function (scalar) {\n      return new Point(this.x + scalar, this.y + scalar);\n    },\n\n    /**\n     * Adds value to this point\n     * @param {Number} scalar\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    scalarAddEquals: function (scalar) {\n      this.x += scalar;\n      this.y += scalar;\n      return this;\n    },\n\n    /**\n     * Subtracts another point from this point and returns a new one\n     * @param {fabric.Point} that\n     * @return {fabric.Point} new Point object with subtracted values\n     */\n    subtract: function (that) {\n      return new Point(this.x - that.x, this.y - that.y);\n    },\n\n    /**\n     * Subtracts another point from this point\n     * @param {fabric.Point} that\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    subtractEquals: function (that) {\n      this.x -= that.x;\n      this.y -= that.y;\n      return this;\n    },\n\n    /**\n     * Subtracts value from this point and returns a new one\n     * @param {Number} scalar\n     * @return {fabric.Point}\n     */\n    scalarSubtract: function (scalar) {\n      return new Point(this.x - scalar, this.y - scalar);\n    },\n\n    /**\n     * Subtracts value from this point\n     * @param {Number} scalar\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    scalarSubtractEquals: function (scalar) {\n      this.x -= scalar;\n      this.y -= scalar;\n      return this;\n    },\n\n    /**\n     * Miltiplies this point by a value and returns a new one\n     * TODO: rename in scalarMultiply in 2.0\n     * @param {Number} scalar\n     * @return {fabric.Point}\n     */\n    multiply: function (scalar) {\n      return new Point(this.x * scalar, this.y * scalar);\n    },\n\n    /**\n     * Miltiplies this point by a value\n     * TODO: rename in scalarMultiplyEquals in 2.0\n     * @param {Number} scalar\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    multiplyEquals: function (scalar) {\n      this.x *= scalar;\n      this.y *= scalar;\n      return this;\n    },\n\n    /**\n     * Divides this point by a value and returns a new one\n     * TODO: rename in scalarDivide in 2.0\n     * @param {Number} scalar\n     * @return {fabric.Point}\n     */\n    divide: function (scalar) {\n      return new Point(this.x / scalar, this.y / scalar);\n    },\n\n    /**\n     * Divides this point by a value\n     * TODO: rename in scalarDivideEquals in 2.0\n     * @param {Number} scalar\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    divideEquals: function (scalar) {\n      this.x /= scalar;\n      this.y /= scalar;\n      return this;\n    },\n\n    /**\n     * Returns true if this point is equal to another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    eq: function (that) {\n      return (this.x === that.x && this.y === that.y);\n    },\n\n    /**\n     * Returns true if this point is less than another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    lt: function (that) {\n      return (this.x < that.x && this.y < that.y);\n    },\n\n    /**\n     * Returns true if this point is less than or equal to another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    lte: function (that) {\n      return (this.x <= that.x && this.y <= that.y);\n    },\n\n    /**\n\n     * Returns true if this point is greater another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    gt: function (that) {\n      return (this.x > that.x && this.y > that.y);\n    },\n\n    /**\n     * Returns true if this point is greater than or equal to another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    gte: function (that) {\n      return (this.x >= that.x && this.y >= that.y);\n    },\n\n    /**\n     * Returns new point which is the result of linear interpolation with this one and another one\n     * @param {fabric.Point} that\n     * @param {Number} t , position of interpolation, between 0 and 1 default 0.5\n     * @return {fabric.Point}\n     */\n    lerp: function (that, t) {\n      if (typeof t === 'undefined') {\n        t = 0.5;\n      }\n      t = Math.max(Math.min(1, t), 0);\n      return new Point(this.x + (that.x - this.x) * t, this.y + (that.y - this.y) * t);\n    },\n\n    /**\n     * Returns distance from this point and another one\n     * @param {fabric.Point} that\n     * @return {Number}\n     */\n    distanceFrom: function (that) {\n      var dx = this.x - that.x,\n          dy = this.y - that.y;\n      return Math.sqrt(dx * dx + dy * dy);\n    },\n\n    /**\n     * Returns the point between this point and another one\n     * @param {fabric.Point} that\n     * @return {fabric.Point}\n     */\n    midPointFrom: function (that) {\n      return this.lerp(that);\n    },\n\n    /**\n     * Returns a new point which is the min of this and another one\n     * @param {fabric.Point} that\n     * @return {fabric.Point}\n     */\n    min: function (that) {\n      return new Point(Math.min(this.x, that.x), Math.min(this.y, that.y));\n    },\n\n    /**\n     * Returns a new point which is the max of this and another one\n     * @param {fabric.Point} that\n     * @return {fabric.Point}\n     */\n    max: function (that) {\n      return new Point(Math.max(this.x, that.x), Math.max(this.y, that.y));\n    },\n\n    /**\n     * Returns string representation of this point\n     * @return {String}\n     */\n    toString: function () {\n      return this.x + ',' + this.y;\n    },\n\n    /**\n     * Sets x/y of this point\n     * @param {Number} x\n     * @param {Number} y\n     * @chainable\n     */\n    setXY: function (x, y) {\n      this.x = x;\n      this.y = y;\n      return this;\n    },\n\n    /**\n     * Sets x of this point\n     * @param {Number} x\n     * @chainable\n     */\n    setX: function (x) {\n      this.x = x;\n      return this;\n    },\n\n    /**\n     * Sets y of this point\n     * @param {Number} y\n     * @chainable\n     */\n    setY: function (y) {\n      this.y = y;\n      return this;\n    },\n\n    /**\n     * Sets x/y of this point from another point\n     * @param {fabric.Point} that\n     * @chainable\n     */\n    setFromPoint: function (that) {\n      this.x = that.x;\n      this.y = that.y;\n      return this;\n    },\n\n    /**\n     * Swaps x/y of this point and another point\n     * @param {fabric.Point} that\n     */\n    swap: function (that) {\n      var x = this.x,\n          y = this.y;\n      this.x = that.x;\n      this.y = that.y;\n      that.x = x;\n      that.y = y;\n    },\n\n    /**\n     * return a cloned instance of the point\n     * @return {fabric.Point}\n     */\n    clone: function () {\n      return new Point(this.x, this.y);\n    }\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */\n  var fabric = global.fabric || (global.fabric = { });\n\n  if (fabric.Intersection) {\n    fabric.warn('fabric.Intersection is already defined');\n    return;\n  }\n\n  /**\n   * Intersection class\n   * @class fabric.Intersection\n   * @memberOf fabric\n   * @constructor\n   */\n  function Intersection(status) {\n    this.status = status;\n    this.points = [];\n  }\n\n  fabric.Intersection = Intersection;\n\n  fabric.Intersection.prototype = /** @lends fabric.Intersection.prototype */ {\n\n    constructor: Intersection,\n\n    /**\n     * Appends a point to intersection\n     * @param {fabric.Point} point\n     * @return {fabric.Intersection} thisArg\n     * @chainable\n     */\n    appendPoint: function (point) {\n      this.points.push(point);\n      return this;\n    },\n\n    /**\n     * Appends points to intersection\n     * @param {Array} points\n     * @return {fabric.Intersection} thisArg\n     * @chainable\n     */\n    appendPoints: function (points) {\n      this.points = this.points.concat(points);\n      return this;\n    }\n  };\n\n  /**\n   * Checks if one line intersects another\n   * TODO: rename in intersectSegmentSegment\n   * @static\n   * @param {fabric.Point} a1\n   * @param {fabric.Point} a2\n   * @param {fabric.Point} b1\n   * @param {fabric.Point} b2\n   * @return {fabric.Intersection}\n   */\n  fabric.Intersection.intersectLineLine = function (a1, a2, b1, b2) {\n    var result,\n        uaT = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x),\n        ubT = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x),\n        uB = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);\n    if (uB !== 0) {\n      var ua = uaT / uB,\n          ub = ubT / uB;\n      if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {\n        result = new Intersection('Intersection');\n        result.appendPoint(new fabric.Point(a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y)));\n      }\n      else {\n        result = new Intersection();\n      }\n    }\n    else {\n      if (uaT === 0 || ubT === 0) {\n        result = new Intersection('Coincident');\n      }\n      else {\n        result = new Intersection('Parallel');\n      }\n    }\n    return result;\n  };\n\n  /**\n   * Checks if line intersects polygon\n   * TODO: rename in intersectSegmentPolygon\n   * fix detection of coincident\n   * @static\n   * @param {fabric.Point} a1\n   * @param {fabric.Point} a2\n   * @param {Array} points\n   * @return {fabric.Intersection}\n   */\n  fabric.Intersection.intersectLinePolygon = function(a1, a2, points) {\n    var result = new Intersection(),\n        length = points.length,\n        b1, b2, inter;\n\n    for (var i = 0; i < length; i++) {\n      b1 = points[i];\n      b2 = points[(i + 1) % length];\n      inter = Intersection.intersectLineLine(a1, a2, b1, b2);\n\n      result.appendPoints(inter.points);\n    }\n    if (result.points.length > 0) {\n      result.status = 'Intersection';\n    }\n    return result;\n  };\n\n  /**\n   * Checks if polygon intersects another polygon\n   * @static\n   * @param {Array} points1\n   * @param {Array} points2\n   * @return {fabric.Intersection}\n   */\n  fabric.Intersection.intersectPolygonPolygon = function (points1, points2) {\n    var result = new Intersection(),\n        length = points1.length;\n\n    for (var i = 0; i < length; i++) {\n      var a1 = points1[i],\n          a2 = points1[(i + 1) % length],\n          inter = Intersection.intersectLinePolygon(a1, a2, points2);\n\n      result.appendPoints(inter.points);\n    }\n    if (result.points.length > 0) {\n      result.status = 'Intersection';\n    }\n    return result;\n  };\n\n  /**\n   * Checks if polygon intersects rectangle\n   * @static\n   * @param {Array} points\n   * @param {fabric.Point} r1\n   * @param {fabric.Point} r2\n   * @return {fabric.Intersection}\n   */\n  fabric.Intersection.intersectPolygonRectangle = function (points, r1, r2) {\n    var min = r1.min(r2),\n        max = r1.max(r2),\n        topRight = new fabric.Point(max.x, min.y),\n        bottomLeft = new fabric.Point(min.x, max.y),\n        inter1 = Intersection.intersectLinePolygon(min, topRight, points),\n        inter2 = Intersection.intersectLinePolygon(topRight, max, points),\n        inter3 = Intersection.intersectLinePolygon(max, bottomLeft, points),\n        inter4 = Intersection.intersectLinePolygon(bottomLeft, min, points),\n        result = new Intersection();\n\n    result.appendPoints(inter1.points);\n    result.appendPoints(inter2.points);\n    result.appendPoints(inter3.points);\n    result.appendPoints(inter4.points);\n\n    if (result.points.length > 0) {\n      result.status = 'Intersection';\n    }\n    return result;\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { });\n\n  if (fabric.Color) {\n    fabric.warn('fabric.Color is already defined.');\n    return;\n  }\n\n  /**\n   * Color class\n   * The purpose of {@link fabric.Color} is to abstract and encapsulate common color operations;\n   * {@link fabric.Color} is a constructor and creates instances of {@link fabric.Color} objects.\n   *\n   * @class fabric.Color\n   * @param {String} color optional in hex or rgb(a) or hsl format or from known color list\n   * @return {fabric.Color} thisArg\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#colors}\n   */\n  function Color(color) {\n    if (!color) {\n      this.setSource([0, 0, 0, 1]);\n    }\n    else {\n      this._tryParsingColor(color);\n    }\n  }\n\n  fabric.Color = Color;\n\n  fabric.Color.prototype = /** @lends fabric.Color.prototype */ {\n\n    /**\n     * @private\n     * @param {String|Array} color Color value to parse\n     */\n    _tryParsingColor: function(color) {\n      var source;\n\n      if (color in Color.colorNameMap) {\n        color = Color.colorNameMap[color];\n      }\n\n      if (color === 'transparent') {\n        source = [255, 255, 255, 0];\n      }\n\n      if (!source) {\n        source = Color.sourceFromHex(color);\n      }\n      if (!source) {\n        source = Color.sourceFromRgb(color);\n      }\n      if (!source) {\n        source = Color.sourceFromHsl(color);\n      }\n      if (!source) {\n        //if color is not recognize let's make black as canvas does\n        source = [0, 0, 0, 1];\n      }\n      if (source) {\n        this.setSource(source);\n      }\n    },\n\n    /**\n     * 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>\n     * @private\n     * @param {Number} r Red color value\n     * @param {Number} g Green color value\n     * @param {Number} b Blue color value\n     * @return {Array} Hsl color\n     */\n    _rgbToHsl: function(r, g, b) {\n      r /= 255; g /= 255; b /= 255;\n\n      var h, s, l,\n          max = fabric.util.array.max([r, g, b]),\n          min = fabric.util.array.min([r, g, b]);\n\n      l = (max + min) / 2;\n\n      if (max === min) {\n        h = s = 0; // achromatic\n      }\n      else {\n        var d = max - min;\n        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n        switch (max) {\n          case r:\n            h = (g - b) / d + (g < b ? 6 : 0);\n            break;\n          case g:\n            h = (b - r) / d + 2;\n            break;\n          case b:\n            h = (r - g) / d + 4;\n            break;\n        }\n        h /= 6;\n      }\n\n      return [\n        Math.round(h * 360),\n        Math.round(s * 100),\n        Math.round(l * 100)\n      ];\n    },\n\n    /**\n     * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n     * @return {Array}\n     */\n    getSource: function() {\n      return this._source;\n    },\n\n    /**\n     * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n     * @param {Array} source\n     */\n    setSource: function(source) {\n      this._source = source;\n    },\n\n    /**\n     * Returns color representation in RGB format\n     * @return {String} ex: rgb(0-255,0-255,0-255)\n     */\n    toRgb: function() {\n      var source = this.getSource();\n      return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')';\n    },\n\n    /**\n     * Returns color representation in RGBA format\n     * @return {String} ex: rgba(0-255,0-255,0-255,0-1)\n     */\n    toRgba: function() {\n      var source = this.getSource();\n      return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')';\n    },\n\n    /**\n     * Returns color representation in HSL format\n     * @return {String} ex: hsl(0-360,0%-100%,0%-100%)\n     */\n    toHsl: function() {\n      var source = this.getSource(),\n          hsl = this._rgbToHsl(source[0], source[1], source[2]);\n\n      return 'hsl(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%)';\n    },\n\n    /**\n     * Returns color representation in HSLA format\n     * @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1)\n     */\n    toHsla: function() {\n      var source = this.getSource(),\n          hsl = this._rgbToHsl(source[0], source[1], source[2]);\n\n      return 'hsla(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%,' + source[3] + ')';\n    },\n\n    /**\n     * Returns color representation in HEX format\n     * @return {String} ex: FF5555\n     */\n    toHex: function() {\n      var source = this.getSource(), r, g, b;\n\n      r = source[0].toString(16);\n      r = (r.length === 1) ? ('0' + r) : r;\n\n      g = source[1].toString(16);\n      g = (g.length === 1) ? ('0' + g) : g;\n\n      b = source[2].toString(16);\n      b = (b.length === 1) ? ('0' + b) : b;\n\n      return r.toUpperCase() + g.toUpperCase() + b.toUpperCase();\n    },\n\n    /**\n     * Returns color representation in HEXA format\n     * @return {String} ex: FF5555CC\n     */\n    toHexa: function() {\n      var source = this.getSource(), a;\n\n      a = source[3] * 255;\n      a = a.toString(16);\n      a = (a.length === 1) ? ('0' + a) : a;\n\n      return this.toHex() + a.toUpperCase();\n    },\n\n    /**\n     * Gets value of alpha channel for this color\n     * @return {Number} 0-1\n     */\n    getAlpha: function() {\n      return this.getSource()[3];\n    },\n\n    /**\n     * Sets value of alpha channel for this color\n     * @param {Number} alpha Alpha value 0-1\n     * @return {fabric.Color} thisArg\n     */\n    setAlpha: function(alpha) {\n      var source = this.getSource();\n      source[3] = alpha;\n      this.setSource(source);\n      return this;\n    },\n\n    /**\n     * Transforms color to its grayscale representation\n     * @return {fabric.Color} thisArg\n     */\n    toGrayscale: function() {\n      var source = this.getSource(),\n          average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10),\n          currentAlpha = source[3];\n      this.setSource([average, average, average, currentAlpha]);\n      return this;\n    },\n\n    /**\n     * Transforms color to its black and white representation\n     * @param {Number} threshold\n     * @return {fabric.Color} thisArg\n     */\n    toBlackWhite: function(threshold) {\n      var source = this.getSource(),\n          average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0),\n          currentAlpha = source[3];\n\n      threshold = threshold || 127;\n\n      average = (Number(average) < Number(threshold)) ? 0 : 255;\n      this.setSource([average, average, average, currentAlpha]);\n      return this;\n    },\n\n    /**\n     * Overlays color with another color\n     * @param {String|fabric.Color} otherColor\n     * @return {fabric.Color} thisArg\n     */\n    overlayWith: function(otherColor) {\n      if (!(otherColor instanceof Color)) {\n        otherColor = new Color(otherColor);\n      }\n\n      var result = [],\n          alpha = this.getAlpha(),\n          otherAlpha = 0.5,\n          source = this.getSource(),\n          otherSource = otherColor.getSource();\n\n      for (var i = 0; i < 3; i++) {\n        result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha)));\n      }\n\n      result[3] = alpha;\n      this.setSource(result);\n      return this;\n    }\n  };\n\n  /**\n   * 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))\n   * @static\n   * @field\n   * @memberOf fabric.Color\n   */\n   // eslint-disable-next-line max-len\n  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*)?\\)$/;\n\n  /**\n   * 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 ))\n   * @static\n   * @field\n   * @memberOf fabric.Color\n   */\n  fabric.Color.reHSLa = /^hsla?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}\\%)\\s*,\\s*(\\d{1,3}\\%)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$/;\n\n  /**\n   * Regex matching color in HEX format (ex: #FF5544CC, #FF5555, 010155, aff)\n   * @static\n   * @field\n   * @memberOf fabric.Color\n   */\n  fabric.Color.reHex = /^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i;\n\n  /**\n   * Map of the 17 basic color names with HEX code\n   * @static\n   * @field\n   * @memberOf fabric.Color\n   * @see: http://www.w3.org/TR/CSS2/syndata.html#color-units\n   */\n  fabric.Color.colorNameMap = {\n    aqua:    '#00FFFF',\n    black:   '#000000',\n    blue:    '#0000FF',\n    fuchsia: '#FF00FF',\n    gray:    '#808080',\n    grey:    '#808080',\n    green:   '#008000',\n    lime:    '#00FF00',\n    maroon:  '#800000',\n    navy:    '#000080',\n    olive:   '#808000',\n    orange:  '#FFA500',\n    purple:  '#800080',\n    red:     '#FF0000',\n    silver:  '#C0C0C0',\n    teal:    '#008080',\n    white:   '#FFFFFF',\n    yellow:  '#FFFF00'\n  };\n\n  /**\n   * @private\n   * @param {Number} p\n   * @param {Number} q\n   * @param {Number} t\n   * @return {Number}\n   */\n  function hue2rgb(p, q, t) {\n    if (t < 0) {\n      t += 1;\n    }\n    if (t > 1) {\n      t -= 1;\n    }\n    if (t < 1 / 6) {\n      return p + (q - p) * 6 * t;\n    }\n    if (t < 1 / 2) {\n      return q;\n    }\n    if (t < 2 / 3) {\n      return p + (q - p) * (2 / 3 - t) * 6;\n    }\n    return p;\n  }\n\n  /**\n   * Returns new color object, when given a color in RGB format\n   * @memberOf fabric.Color\n   * @param {String} color Color value ex: rgb(0-255,0-255,0-255)\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromRgb = function(color) {\n    return Color.fromSource(Color.sourceFromRgb(color));\n  };\n\n  /**\n   * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format\n   * @memberOf fabric.Color\n   * @param {String} color Color value ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%)\n   * @return {Array} source\n   */\n  fabric.Color.sourceFromRgb = function(color) {\n    var match = color.match(Color.reRGBa);\n    if (match) {\n      var r = parseInt(match[1], 10) / (/%$/.test(match[1]) ? 100 : 1) * (/%$/.test(match[1]) ? 255 : 1),\n          g = parseInt(match[2], 10) / (/%$/.test(match[2]) ? 100 : 1) * (/%$/.test(match[2]) ? 255 : 1),\n          b = parseInt(match[3], 10) / (/%$/.test(match[3]) ? 100 : 1) * (/%$/.test(match[3]) ? 255 : 1);\n\n      return [\n        parseInt(r, 10),\n        parseInt(g, 10),\n        parseInt(b, 10),\n        match[4] ? parseFloat(match[4]) : 1\n      ];\n    }\n  };\n\n  /**\n   * Returns new color object, when given a color in RGBA format\n   * @static\n   * @function\n   * @memberOf fabric.Color\n   * @param {String} color\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromRgba = Color.fromRgb;\n\n  /**\n   * Returns new color object, when given a color in HSL format\n   * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%)\n   * @memberOf fabric.Color\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromHsl = function(color) {\n    return Color.fromSource(Color.sourceFromHsl(color));\n  };\n\n  /**\n   * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format.\n   * 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>\n   * @memberOf fabric.Color\n   * @param {String} color Color value ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1)\n   * @return {Array} source\n   * @see http://http://www.w3.org/TR/css3-color/#hsl-color\n   */\n  fabric.Color.sourceFromHsl = function(color) {\n    var match = color.match(Color.reHSLa);\n    if (!match) {\n      return;\n    }\n\n    var h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360,\n        s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1),\n        l = parseFloat(match[3]) / (/%$/.test(match[3]) ? 100 : 1),\n        r, g, b;\n\n    if (s === 0) {\n      r = g = b = l;\n    }\n    else {\n      var q = l <= 0.5 ? l * (s + 1) : l + s - l * s,\n          p = l * 2 - q;\n\n      r = hue2rgb(p, q, h + 1 / 3);\n      g = hue2rgb(p, q, h);\n      b = hue2rgb(p, q, h - 1 / 3);\n    }\n\n    return [\n      Math.round(r * 255),\n      Math.round(g * 255),\n      Math.round(b * 255),\n      match[4] ? parseFloat(match[4]) : 1\n    ];\n  };\n\n  /**\n   * Returns new color object, when given a color in HSLA format\n   * @static\n   * @function\n   * @memberOf fabric.Color\n   * @param {String} color\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromHsla = Color.fromHsl;\n\n  /**\n   * Returns new color object, when given a color in HEX format\n   * @static\n   * @memberOf fabric.Color\n   * @param {String} color Color value ex: FF5555\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromHex = function(color) {\n    return Color.fromSource(Color.sourceFromHex(color));\n  };\n\n  /**\n   * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HEX format\n   * @static\n   * @memberOf fabric.Color\n   * @param {String} color ex: FF5555 or FF5544CC (RGBa)\n   * @return {Array} source\n   */\n  fabric.Color.sourceFromHex = function(color) {\n    if (color.match(Color.reHex)) {\n      var value = color.slice(color.indexOf('#') + 1),\n          isShortNotation = (value.length === 3 || value.length === 4),\n          isRGBa = (value.length === 8 || value.length === 4),\n          r = isShortNotation ? (value.charAt(0) + value.charAt(0)) : value.substring(0, 2),\n          g = isShortNotation ? (value.charAt(1) + value.charAt(1)) : value.substring(2, 4),\n          b = isShortNotation ? (value.charAt(2) + value.charAt(2)) : value.substring(4, 6),\n          a = isRGBa ? (isShortNotation ? (value.charAt(3) + value.charAt(3)) : value.substring(6, 8)) : 'FF';\n\n      return [\n        parseInt(r, 16),\n        parseInt(g, 16),\n        parseInt(b, 16),\n        parseFloat((parseInt(a, 16) / 255).toFixed(2))\n      ];\n    }\n  };\n\n  /**\n   * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5])\n   * @static\n   * @memberOf fabric.Color\n   * @param {Array} source\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromSource = function(source) {\n    var oColor = new Color();\n    oColor.setSource(source);\n    return oColor;\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n  /* _FROM_SVG_START_ */\n  function getColorStop(el) {\n    var style = el.getAttribute('style'),\n        offset = el.getAttribute('offset') || 0,\n        color, colorAlpha, opacity;\n\n    // convert percents to absolute values\n    offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);\n    offset = offset < 0 ? 0 : offset > 1 ? 1 : offset;\n    if (style) {\n      var keyValuePairs = style.split(/\\s*;\\s*/);\n\n      if (keyValuePairs[keyValuePairs.length - 1] === '') {\n        keyValuePairs.pop();\n      }\n\n      for (var i = keyValuePairs.length; i--; ) {\n\n        var split = keyValuePairs[i].split(/\\s*:\\s*/),\n            key = split[0].trim(),\n            value = split[1].trim();\n\n        if (key === 'stop-color') {\n          color = value;\n        }\n        else if (key === 'stop-opacity') {\n          opacity = value;\n        }\n      }\n    }\n\n    if (!color) {\n      color = el.getAttribute('stop-color') || 'rgb(0,0,0)';\n    }\n    if (!opacity) {\n      opacity = el.getAttribute('stop-opacity');\n    }\n\n    color = new fabric.Color(color);\n    colorAlpha = color.getAlpha();\n    opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity);\n    opacity *= colorAlpha;\n\n    return {\n      offset: offset,\n      color: color.toRgb(),\n      opacity: opacity\n    };\n  }\n\n  function getLinearCoords(el) {\n    return {\n      x1: el.getAttribute('x1') || 0,\n      y1: el.getAttribute('y1') || 0,\n      x2: el.getAttribute('x2') || '100%',\n      y2: el.getAttribute('y2') || 0\n    };\n  }\n\n  function getRadialCoords(el) {\n    return {\n      x1: el.getAttribute('fx') || el.getAttribute('cx') || '50%',\n      y1: el.getAttribute('fy') || el.getAttribute('cy') || '50%',\n      r1: 0,\n      x2: el.getAttribute('cx') || '50%',\n      y2: el.getAttribute('cy') || '50%',\n      r2: el.getAttribute('r') || '50%'\n    };\n  }\n  /* _FROM_SVG_END_ */\n\n  var clone = fabric.util.object.clone;\n\n  /**\n   * Gradient class\n   * @class fabric.Gradient\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#gradients}\n   * @see {@link fabric.Gradient#initialize} for constructor definition\n   */\n  fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ {\n\n    /**\n     * Horizontal offset for aligning gradients coming from SVG when outside pathgroups\n     * @type Number\n     * @default 0\n     */\n    offsetX: 0,\n\n    /**\n     * Vertical offset for aligning gradients coming from SVG when outside pathgroups\n     * @type Number\n     * @default 0\n     */\n    offsetY: 0,\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object with type, coords, gradientUnits and colorStops\n     * @return {fabric.Gradient} thisArg\n     */\n    initialize: function(options) {\n      options || (options = { });\n\n      var coords = { };\n\n      this.id = fabric.Object.__uid++;\n      this.type = options.type || 'linear';\n\n      coords = {\n        x1: options.coords.x1 || 0,\n        y1: options.coords.y1 || 0,\n        x2: options.coords.x2 || 0,\n        y2: options.coords.y2 || 0\n      };\n\n      if (this.type === 'radial') {\n        coords.r1 = options.coords.r1 || 0;\n        coords.r2 = options.coords.r2 || 0;\n      }\n      this.coords = coords;\n      this.colorStops = options.colorStops.slice();\n      if (options.gradientTransform) {\n        this.gradientTransform = options.gradientTransform;\n      }\n      this.offsetX = options.offsetX || this.offsetX;\n      this.offsetY = options.offsetY || this.offsetY;\n    },\n\n    /**\n     * Adds another colorStop\n     * @param {Object} colorStop Object with offset and color\n     * @return {fabric.Gradient} thisArg\n     */\n    addColorStop: function(colorStops) {\n      for (var position in colorStops) {\n        var color = new fabric.Color(colorStops[position]);\n        this.colorStops.push({\n          offset: parseFloat(position),\n          color: color.toRgb(),\n          opacity: color.getAlpha()\n        });\n      }\n      return this;\n    },\n\n    /**\n     * Returns object representation of a gradient\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object}\n     */\n    toObject: function(propertiesToInclude) {\n      var object = {\n        type: this.type,\n        coords: this.coords,\n        colorStops: this.colorStops,\n        offsetX: this.offsetX,\n        offsetY: this.offsetY,\n        gradientTransform: this.gradientTransform ? this.gradientTransform.concat() : this.gradientTransform\n      };\n      fabric.util.populateWithProperties(this, object, propertiesToInclude);\n\n      return object;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of an gradient\n     * @param {Object} object Object to create a gradient for\n     * @return {String} SVG representation of an gradient (linear/radial)\n     */\n    toSVG: function(object) {\n      var coords = clone(this.coords, true),\n          markup, commonAttributes, colorStops = clone(this.colorStops, true),\n          needsSwap = coords.r1 > coords.r2;\n      // colorStops must be sorted ascending\n      colorStops.sort(function(a, b) {\n        return a.offset - b.offset;\n      });\n\n      if (!(object.group && object.group.type === 'path-group')) {\n        for (var prop in coords) {\n          if (prop === 'x1' || prop === 'x2') {\n            coords[prop] += this.offsetX - object.width / 2;\n          }\n          else if (prop === 'y1' || prop === 'y2') {\n            coords[prop] += this.offsetY - object.height / 2;\n          }\n        }\n      }\n\n      commonAttributes = 'id=\"SVGID_' + this.id +\n                     '\" gradientUnits=\"userSpaceOnUse\"';\n      if (this.gradientTransform) {\n        commonAttributes += ' gradientTransform=\"matrix(' + this.gradientTransform.join(' ') + ')\" ';\n      }\n      if (this.type === 'linear') {\n        markup = [\n          '<linearGradient ',\n          commonAttributes,\n          ' x1=\"', coords.x1,\n          '\" y1=\"', coords.y1,\n          '\" x2=\"', coords.x2,\n          '\" y2=\"', coords.y2,\n          '\">\\n'\n        ];\n      }\n      else if (this.type === 'radial') {\n        // svg radial gradient has just 1 radius. the biggest.\n        markup = [\n          '<radialGradient ',\n          commonAttributes,\n          ' cx=\"', needsSwap ? coords.x1 : coords.x2,\n          '\" cy=\"', needsSwap ? coords.y1 : coords.y2,\n          '\" r=\"', needsSwap ? coords.r1 : coords.r2,\n          '\" fx=\"', needsSwap ? coords.x2 : coords.x1,\n          '\" fy=\"', needsSwap ? coords.y2 : coords.y1,\n          '\">\\n'\n        ];\n      }\n\n      if (this.type === 'radial') {\n        if (needsSwap) {\n          // svg goes from internal to external radius. if radius are inverted, swap color stops.\n          colorStops = colorStops.concat();\n          colorStops.reverse();\n          for (var i = 0; i < colorStops.length; i++) {\n            colorStops[i].offset = 1 - colorStops[i].offset;\n          }\n        }\n        var minRadius = Math.min(coords.r1, coords.r2);\n        if (minRadius > 0) {\n          // i have to shift all colorStops and add new one in 0.\n          var maxRadius = Math.max(coords.r1, coords.r2),\n              percentageShift = minRadius / maxRadius;\n          for (var i = 0; i < colorStops.length; i++) {\n            colorStops[i].offset += percentageShift * (1 - colorStops[i].offset);\n          }\n        }\n      }\n\n      for (var i = 0; i < colorStops.length; i++) {\n        var colorStop = colorStops[i];\n        markup.push(\n          '<stop ',\n            'offset=\"', (colorStop.offset * 100) + '%',\n            '\" style=\"stop-color:', colorStop.color,\n            (colorStop.opacity !== null ? ';stop-opacity: ' + colorStop.opacity : ';'),\n          '\"/>\\n'\n        );\n      }\n\n      markup.push((this.type === 'linear' ? '</linearGradient>\\n' : '</radialGradient>\\n'));\n\n      return markup.join('');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns an instance of CanvasGradient\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Object} object\n     * @return {CanvasGradient}\n     */\n    toLive: function(ctx, object) {\n      var gradient, prop, coords = fabric.util.object.clone(this.coords);\n\n      if (!this.type) {\n        return;\n      }\n\n      if (object.group && object.group.type === 'path-group') {\n        for (prop in coords) {\n          if (prop === 'x1' || prop === 'x2') {\n            coords[prop] += -this.offsetX + object.width / 2;\n          }\n          else if (prop === 'y1' || prop === 'y2') {\n            coords[prop] += -this.offsetY + object.height / 2;\n          }\n        }\n      }\n\n      if (this.type === 'linear') {\n        gradient = ctx.createLinearGradient(\n          coords.x1, coords.y1, coords.x2, coords.y2);\n      }\n      else if (this.type === 'radial') {\n        gradient = ctx.createRadialGradient(\n          coords.x1, coords.y1, coords.r1, coords.x2, coords.y2, coords.r2);\n      }\n\n      for (var i = 0, len = this.colorStops.length; i < len; i++) {\n        var color = this.colorStops[i].color,\n            opacity = this.colorStops[i].opacity,\n            offset = this.colorStops[i].offset;\n\n        if (typeof opacity !== 'undefined') {\n          color = new fabric.Color(color).setAlpha(opacity).toRgba();\n        }\n        gradient.addColorStop(offset, color);\n      }\n\n      return gradient;\n    }\n  });\n\n  fabric.util.object.extend(fabric.Gradient, {\n\n    /* _FROM_SVG_START_ */\n    /**\n     * Returns {@link fabric.Gradient} instance from an SVG element\n     * @static\n     * @memberOf fabric.Gradient\n     * @param {SVGGradientElement} el SVG gradient element\n     * @param {fabric.Object} instance\n     * @return {fabric.Gradient} Gradient instance\n     * @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement\n     * @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement\n     */\n    fromElement: function(el, instance) {\n\n      /**\n       *  @example:\n       *\n       *  <linearGradient id=\"linearGrad1\">\n       *    <stop offset=\"0%\" stop-color=\"white\"/>\n       *    <stop offset=\"100%\" stop-color=\"black\"/>\n       *  </linearGradient>\n       *\n       *  OR\n       *\n       *  <linearGradient id=\"linearGrad2\">\n       *    <stop offset=\"0\" style=\"stop-color:rgb(255,255,255)\"/>\n       *    <stop offset=\"1\" style=\"stop-color:rgb(0,0,0)\"/>\n       *  </linearGradient>\n       *\n       *  OR\n       *\n       *  <radialGradient id=\"radialGrad1\">\n       *    <stop offset=\"0%\" stop-color=\"white\" stop-opacity=\"1\" />\n       *    <stop offset=\"50%\" stop-color=\"black\" stop-opacity=\"0.5\" />\n       *    <stop offset=\"100%\" stop-color=\"white\" stop-opacity=\"1\" />\n       *  </radialGradient>\n       *\n       *  OR\n       *\n       *  <radialGradient id=\"radialGrad2\">\n       *    <stop offset=\"0\" stop-color=\"rgb(255,255,255)\" />\n       *    <stop offset=\"0.5\" stop-color=\"rgb(0,0,0)\" />\n       *    <stop offset=\"1\" stop-color=\"rgb(255,255,255)\" />\n       *  </radialGradient>\n       *\n       */\n\n      var colorStopEls = el.getElementsByTagName('stop'),\n          type,\n          gradientUnits = el.getAttribute('gradientUnits') || 'objectBoundingBox',\n          gradientTransform = el.getAttribute('gradientTransform'),\n          colorStops = [],\n          coords, ellipseMatrix;\n\n      if (el.nodeName === 'linearGradient' || el.nodeName === 'LINEARGRADIENT') {\n        type = 'linear';\n      }\n      else {\n        type = 'radial';\n      }\n\n      if (type === 'linear') {\n        coords = getLinearCoords(el);\n      }\n      else if (type === 'radial') {\n        coords = getRadialCoords(el);\n      }\n\n      for (var i = colorStopEls.length; i--; ) {\n        colorStops.push(getColorStop(colorStopEls[i]));\n      }\n\n      ellipseMatrix = _convertPercentUnitsToValues(instance, coords, gradientUnits);\n\n      var gradient = new fabric.Gradient({\n        type: type,\n        coords: coords,\n        colorStops: colorStops,\n        offsetX: -instance.left,\n        offsetY: -instance.top\n      });\n\n      if (gradientTransform || ellipseMatrix !== '') {\n        gradient.gradientTransform = fabric.parseTransformAttribute((gradientTransform || '') + ellipseMatrix);\n      }\n      return gradient;\n    },\n    /* _FROM_SVG_END_ */\n\n    /**\n     * Returns {@link fabric.Gradient} instance from its object representation\n     * @static\n     * @memberOf fabric.Gradient\n     * @param {Object} obj\n     * @param {Object} [options] Options object\n     */\n    forObject: function(obj, options) {\n      options || (options = { });\n      _convertPercentUnitsToValues(obj, options.coords, 'userSpaceOnUse');\n      return new fabric.Gradient(options);\n    }\n  });\n\n  /**\n   * @private\n   */\n  function _convertPercentUnitsToValues(object, options, gradientUnits) {\n    var propValue, addFactor = 0, multFactor = 1, ellipseMatrix = '';\n    for (var prop in options) {\n      if (options[prop] === 'Infinity') {\n        options[prop] = 1;\n      }\n      else if (options[prop] === '-Infinity') {\n        options[prop] = 0;\n      }\n      propValue = parseFloat(options[prop], 10);\n      if (typeof options[prop] === 'string' && /^\\d+%$/.test(options[prop])) {\n        multFactor = 0.01;\n      }\n      else {\n        multFactor = 1;\n      }\n      if (prop === 'x1' || prop === 'x2' || prop === 'r2') {\n        multFactor *= gradientUnits === 'objectBoundingBox' ? object.width : 1;\n        addFactor = gradientUnits === 'objectBoundingBox' ? object.left || 0 : 0;\n      }\n      else if (prop === 'y1' || prop === 'y2') {\n        multFactor *= gradientUnits === 'objectBoundingBox' ? object.height : 1;\n        addFactor = gradientUnits === 'objectBoundingBox' ? object.top || 0 : 0;\n      }\n      options[prop] = propValue * multFactor + addFactor;\n    }\n    if (object.type === 'ellipse' &&\n        options.r2 !== null &&\n        gradientUnits === 'objectBoundingBox' &&\n        object.rx !== object.ry) {\n\n      var scaleFactor = object.ry / object.rx;\n      ellipseMatrix = ' scale(1, ' + scaleFactor + ')';\n      if (options.y1) {\n        options.y1 /= scaleFactor;\n      }\n      if (options.y2) {\n        options.y2 /= scaleFactor;\n      }\n    }\n    return ellipseMatrix;\n  }\n})();\n\n\n(function() {\n\n  'use strict';\n\n  var toFixed = fabric.util.toFixed;\n\n  /**\n   * Pattern class\n   * @class fabric.Pattern\n   * @see {@link http://fabricjs.com/patterns|Pattern demo}\n   * @see {@link http://fabricjs.com/dynamic-patterns|DynamicPattern demo}\n   * @see {@link fabric.Pattern#initialize} for constructor definition\n   */\n\n\n  fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ {\n\n    /**\n     * Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)\n     * @type String\n     * @default\n     */\n    repeat: 'repeat',\n\n    /**\n     * Pattern horizontal offset from object's left/top corner\n     * @type Number\n     * @default\n     */\n    offsetX: 0,\n\n    /**\n     * Pattern vertical offset from object's left/top corner\n     * @type Number\n     * @default\n     */\n    offsetY: 0,\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     * @param {Function} [callback] function to invoke after callback init.\n     * @return {fabric.Pattern} thisArg\n     */\n    initialize: function(options, callback) {\n      options || (options = { });\n\n      this.id = fabric.Object.__uid++;\n      this.setOptions(options);\n      if (!options.source || (options.source && typeof options.source !== 'string')) {\n        callback && callback(this);\n        return;\n      }\n      // function string\n      if (typeof fabric.util.getFunctionBody(options.source) !== 'undefined') {\n        this.source = new Function(fabric.util.getFunctionBody(options.source));\n        callback && callback(this);\n      }\n      else {\n        // img src string\n        var _this = this;\n        this.source = fabric.util.createImage();\n        fabric.util.loadImage(options.source, function(img) {\n          _this.source = img;\n          callback && callback(_this);\n        });\n      }\n    },\n\n    /**\n     * Returns object representation of a pattern\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of a pattern instance\n     */\n    toObject: function(propertiesToInclude) {\n      var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n          source, object;\n\n      // callback\n      if (typeof this.source === 'function') {\n        source = String(this.source);\n      }\n      // <img> element\n      else if (typeof this.source.src === 'string') {\n        source = this.source.src;\n      }\n      // <canvas> element\n      else if (typeof this.source === 'object' && this.source.toDataURL) {\n        source = this.source.toDataURL();\n      }\n\n      object = {\n        type: 'pattern',\n        source: source,\n        repeat: this.repeat,\n        offsetX: toFixed(this.offsetX, NUM_FRACTION_DIGITS),\n        offsetY: toFixed(this.offsetY, NUM_FRACTION_DIGITS),\n      };\n      fabric.util.populateWithProperties(this, object, propertiesToInclude);\n\n      return object;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of a pattern\n     * @param {fabric.Object} object\n     * @return {String} SVG representation of a pattern\n     */\n    toSVG: function(object) {\n      var patternSource = typeof this.source === 'function' ? this.source() : this.source,\n          patternWidth = patternSource.width / object.width,\n          patternHeight = patternSource.height / object.height,\n          patternOffsetX = this.offsetX / object.width,\n          patternOffsetY = this.offsetY / object.height,\n          patternImgSrc = '';\n      if (this.repeat === 'repeat-x' || this.repeat === 'no-repeat') {\n        patternHeight = 1;\n      }\n      if (this.repeat === 'repeat-y' || this.repeat === 'no-repeat') {\n        patternWidth = 1;\n      }\n      if (patternSource.src) {\n        patternImgSrc = patternSource.src;\n      }\n      else if (patternSource.toDataURL) {\n        patternImgSrc = patternSource.toDataURL();\n      }\n\n      return '<pattern id=\"SVGID_' + this.id +\n                    '\" x=\"' + patternOffsetX +\n                    '\" y=\"' + patternOffsetY +\n                    '\" width=\"' + patternWidth +\n                    '\" height=\"' + patternHeight + '\">\\n' +\n               '<image x=\"0\" y=\"0\"' +\n                      ' width=\"' + patternSource.width +\n                      '\" height=\"' + patternSource.height +\n                      '\" xlink:href=\"' + patternImgSrc +\n               '\"></image>\\n' +\n             '</pattern>\\n';\n    },\n    /* _TO_SVG_END_ */\n\n    setOptions: function(options) {\n      for (var prop in options) {\n        this[prop] = options[prop];\n      }\n    },\n\n    /**\n     * Returns an instance of CanvasPattern\n     * @param {CanvasRenderingContext2D} ctx Context to create pattern\n     * @return {CanvasPattern}\n     */\n    toLive: function(ctx) {\n      var source = typeof this.source === 'function' ? this.source() : this.source;\n\n      // if the image failed to load, return, and allow rest to continue loading\n      if (!source) {\n        return '';\n      }\n\n      // if an image\n      if (typeof source.src !== 'undefined') {\n        if (!source.complete) {\n          return '';\n        }\n        if (source.naturalWidth === 0 || source.naturalHeight === 0) {\n          return '';\n        }\n      }\n      return ctx.createPattern(source, this.repeat);\n    }\n  });\n})();\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      toFixed = fabric.util.toFixed;\n\n  if (fabric.Shadow) {\n    fabric.warn('fabric.Shadow is already defined.');\n    return;\n  }\n\n  /**\n   * Shadow class\n   * @class fabric.Shadow\n   * @see {@link http://fabricjs.com/shadows|Shadow demo}\n   * @see {@link fabric.Shadow#initialize} for constructor definition\n   */\n  fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ {\n\n    /**\n     * Shadow color\n     * @type String\n     * @default\n     */\n    color: 'rgb(0,0,0)',\n\n    /**\n     * Shadow blur\n     * @type Number\n     */\n    blur: 0,\n\n    /**\n     * Shadow horizontal offset\n     * @type Number\n     * @default\n     */\n    offsetX: 0,\n\n    /**\n     * Shadow vertical offset\n     * @type Number\n     * @default\n     */\n    offsetY: 0,\n\n    /**\n     * Whether the shadow should affect stroke operations\n     * @type Boolean\n     * @default\n     */\n    affectStroke: false,\n\n    /**\n     * Indicates whether toObject should include default values\n     * @type Boolean\n     * @default\n     */\n    includeDefaultValues: true,\n\n    /**\n     * Constructor\n     * @param {Object|String} [options] Options object with any of color, blur, offsetX, offsetX properties or string (e.g. \"rgba(0,0,0,0.2) 2px 2px 10px, \"2px 2px 10px rgba(0,0,0,0.2)\")\n     * @return {fabric.Shadow} thisArg\n     */\n    initialize: function(options) {\n\n      if (typeof options === 'string') {\n        options = this._parseShadow(options);\n      }\n\n      for (var prop in options) {\n        this[prop] = options[prop];\n      }\n\n      this.id = fabric.Object.__uid++;\n    },\n\n    /**\n     * @private\n     * @param {String} shadow Shadow value to parse\n     * @return {Object} Shadow object with color, offsetX, offsetY and blur\n     */\n    _parseShadow: function(shadow) {\n      var shadowStr = shadow.trim(),\n          offsetsAndBlur = fabric.Shadow.reOffsetsAndBlur.exec(shadowStr) || [],\n          color = shadowStr.replace(fabric.Shadow.reOffsetsAndBlur, '') || 'rgb(0,0,0)';\n\n      return {\n        color: color.trim(),\n        offsetX: parseInt(offsetsAndBlur[1], 10) || 0,\n        offsetY: parseInt(offsetsAndBlur[2], 10) || 0,\n        blur: parseInt(offsetsAndBlur[3], 10) || 0\n      };\n    },\n\n    /**\n     * Returns a string representation of an instance\n     * @see http://www.w3.org/TR/css-text-decor-3/#text-shadow\n     * @return {String} Returns CSS3 text-shadow declaration\n     */\n    toString: function() {\n      return [this.offsetX, this.offsetY, this.blur, this.color].join('px ');\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of a shadow\n     * @param {fabric.Object} object\n     * @return {String} SVG representation of a shadow\n     */\n    toSVG: function(object) {\n      var fBoxX = 40, fBoxY = 40, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n          offset = fabric.util.rotateVector(\n            { x: this.offsetX, y: this.offsetY },\n            fabric.util.degreesToRadians(-object.angle)),\n          BLUR_BOX = 20;\n\n      if (object.width && object.height) {\n        //http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion\n        // we add some extra space to filter box to contain the blur ( 20 )\n        fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;\n        fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;\n      }\n      if (object.flipX) {\n        offset.x *= -1;\n      }\n      if (object.flipY) {\n        offset.y *= -1;\n      }\n      return (\n        '<filter id=\"SVGID_' + this.id + '\" y=\"-' + fBoxY + '%\" height=\"' + (100 + 2 * fBoxY) + '%\" ' +\n          'x=\"-' + fBoxX + '%\" width=\"' + (100 + 2 * fBoxX) + '%\" ' + '>\\n' +\n          '\\t<feGaussianBlur in=\"SourceAlpha\" stdDeviation=\"' +\n            toFixed(this.blur ? this.blur / 2 : 0, NUM_FRACTION_DIGITS) + '\"></feGaussianBlur>\\n' +\n          '\\t<feOffset dx=\"' + toFixed(offset.x, NUM_FRACTION_DIGITS) +\n          '\" dy=\"' + toFixed(offset.y, NUM_FRACTION_DIGITS) + '\" result=\"oBlur\" ></feOffset>\\n' +\n          '\\t<feFlood flood-color=\"' + this.color + '\"/>\\n' +\n          '\\t<feComposite in2=\"oBlur\" operator=\"in\" />\\n' +\n          '\\t<feMerge>\\n' +\n            '\\t\\t<feMergeNode></feMergeNode>\\n' +\n            '\\t\\t<feMergeNode in=\"SourceGraphic\"></feMergeNode>\\n' +\n          '\\t</feMerge>\\n' +\n        '</filter>\\n');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns object representation of a shadow\n     * @return {Object} Object representation of a shadow instance\n     */\n    toObject: function() {\n      if (this.includeDefaultValues) {\n        return {\n          color: this.color,\n          blur: this.blur,\n          offsetX: this.offsetX,\n          offsetY: this.offsetY,\n          affectStroke: this.affectStroke\n        };\n      }\n      var obj = { }, proto = fabric.Shadow.prototype;\n\n      ['color', 'blur', 'offsetX', 'offsetY', 'affectStroke'].forEach(function(prop) {\n        if (this[prop] !== proto[prop]) {\n          obj[prop] = this[prop];\n        }\n      }, this);\n\n      return obj;\n    }\n  });\n\n  /**\n   * Regex matching shadow offsetX, offsetY and blur (ex: \"2px 2px 10px rgba(0,0,0,0.2)\", \"rgb(0,255,0) 2px 2px\")\n   * @static\n   * @field\n   * @memberOf fabric.Shadow\n   */\n  // eslint-disable-next-line max-len\n  fabric.Shadow.reOffsetsAndBlur = /(?:\\s|^)(-?\\d+(?:px)?(?:\\s?|$))?(-?\\d+(?:px)?(?:\\s?|$))?(\\d+(?:px)?)?(?:\\s?|$)(?:$|\\s)/;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function () {\n\n  'use strict';\n\n  if (fabric.StaticCanvas) {\n    fabric.warn('fabric.StaticCanvas is already defined.');\n    return;\n  }\n\n  // aliases for faster resolution\n  var extend = fabric.util.object.extend,\n      getElementOffset = fabric.util.getElementOffset,\n      removeFromArray = fabric.util.removeFromArray,\n      toFixed = fabric.util.toFixed,\n      transformPoint = fabric.util.transformPoint,\n      invertTransform = fabric.util.invertTransform,\n\n      CANVAS_INIT_ERROR = new Error('Could not initialize `canvas` element');\n\n  /**\n   * Static canvas class\n   * @class fabric.StaticCanvas\n   * @mixes fabric.Collection\n   * @mixes fabric.Observable\n   * @see {@link http://fabricjs.com/static_canvas|StaticCanvas demo}\n   * @see {@link fabric.StaticCanvas#initialize} for constructor definition\n   * @fires before:render\n   * @fires after:render\n   * @fires canvas:cleared\n   * @fires object:added\n   * @fires object:removed\n   */\n  fabric.StaticCanvas = fabric.util.createClass(fabric.CommonMethods, /** @lends fabric.StaticCanvas.prototype */ {\n\n    /**\n     * Constructor\n     * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on\n     * @param {Object} [options] Options object\n     * @return {Object} thisArg\n     */\n    initialize: function(el, options) {\n      options || (options = { });\n\n      this._initStatic(el, options);\n    },\n\n    /**\n     * Background color of canvas instance.\n     * Should be set via {@link fabric.StaticCanvas#setBackgroundColor}.\n     * @type {(String|fabric.Pattern)}\n     * @default\n     */\n    backgroundColor: '',\n\n    /**\n     * Background image of canvas instance.\n     * Should be set via {@link fabric.StaticCanvas#setBackgroundImage}.\n     * <b>Backwards incompatibility note:</b> The \"backgroundImageOpacity\"\n     * and \"backgroundImageStretch\" properties are deprecated since 1.3.9.\n     * Use {@link fabric.Image#opacity}, {@link fabric.Image#width} and {@link fabric.Image#height}.\n     * @type fabric.Image\n     * @default\n     */\n    backgroundImage: null,\n\n    /**\n     * Overlay color of canvas instance.\n     * Should be set via {@link fabric.StaticCanvas#setOverlayColor}\n     * @since 1.3.9\n     * @type {(String|fabric.Pattern)}\n     * @default\n     */\n    overlayColor: '',\n\n    /**\n     * Overlay image of canvas instance.\n     * Should be set via {@link fabric.StaticCanvas#setOverlayImage}.\n     * <b>Backwards incompatibility note:</b> The \"overlayImageLeft\"\n     * and \"overlayImageTop\" properties are deprecated since 1.3.9.\n     * Use {@link fabric.Image#left} and {@link fabric.Image#top}.\n     * @type fabric.Image\n     * @default\n     */\n    overlayImage: null,\n\n    /**\n     * Indicates whether toObject/toDatalessObject should include default values\n     * @type Boolean\n     * @default\n     */\n    includeDefaultValues: true,\n\n    /**\n     * Indicates whether objects' state should be saved\n     * @type Boolean\n     * @default\n     */\n    stateful: false,\n\n    /**\n     * Indicates whether {@link fabric.Collection.add}, {@link fabric.Collection.insertAt} and {@link fabric.Collection.remove} should also re-render canvas.\n     * Disabling this option could give a great performance boost when adding/removing a lot of objects to/from canvas at once\n     * (followed by a manual rendering after addition/deletion)\n     * @type Boolean\n     * @default\n     */\n    renderOnAddRemove: true,\n\n    /**\n     * Function that determines clipping of entire canvas area\n     * Being passed context as first argument. See clipping canvas area in {@link https://github.com/kangax/fabric.js/wiki/FAQ}\n     * @type Function\n     * @default\n     */\n    clipTo: null,\n\n    /**\n     * Indicates whether object controls (borders/controls) are rendered above overlay image\n     * @type Boolean\n     * @default\n     */\n    controlsAboveOverlay: false,\n\n    /**\n     * Indicates whether the browser can be scrolled when using a touchscreen and dragging on the canvas\n     * @type Boolean\n     * @default\n     */\n    allowTouchScrolling: false,\n\n    /**\n     * Indicates whether this canvas will use image smoothing, this is on by default in browsers\n     * @type Boolean\n     * @default\n     */\n    imageSmoothingEnabled: true,\n\n    /**\n     * The transformation (in the format of Canvas transform) which focuses the viewport\n     * @type Array\n     * @default\n     */\n    viewportTransform: fabric.iMatrix.concat(),\n\n    /**\n     * if set to false background image is not affected by viewport transform\n     * @since 1.6.3\n     * @type Boolean\n     * @default\n     */\n    backgroundVpt: true,\n\n    /**\n     * if set to false overlya image is not affected by viewport transform\n     * @since 1.6.3\n     * @type Boolean\n     * @default\n     */\n    overlayVpt: true,\n\n    /**\n     * Callback; invoked right before object is about to be scaled/rotated\n     */\n    onBeforeScaleRotate: function () {\n      /* NOOP */\n    },\n\n    /**\n     * When true, canvas is scaled by devicePixelRatio for better rendering on retina screens\n     */\n    enableRetinaScaling: true,\n\n    /**\n     * Describe canvas element extension over design\n     * properties are tl,tr,bl,br.\n     * if canvas is not zoomed/panned those points are the four corner of canvas\n     * if canvas is viewportTransformed you those points indicate the extension\n     * of canvas element in plain untrasformed coordinates\n     * The coordinates get updated with @method calcViewportBoundaries.\n     * @memberOf fabric.StaticCanvas.prototype\n     */\n    vptCoords: { },\n\n    /**\n     * Based on vptCoords and object.aCoords, skip rendering of objects that\n     * are not included in current viewport.\n     * May greatly help in applications with crowded canvas and use of zoom/pan\n     * If One of the corner of the bounding box of the object is on the canvas\n     * the objects get rendered.\n     * @memberOf fabric.StaticCanvas.prototype\n     */\n    skipOffscreen: false,\n\n    /**\n     * @private\n     * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on\n     * @param {Object} [options] Options object\n     */\n    _initStatic: function(el, options) {\n      var cb = fabric.StaticCanvas.prototype.renderAll.bind(this);\n      this._objects = [];\n      this._createLowerCanvas(el);\n      this._initOptions(options);\n      this._setImageSmoothing();\n      // only initialize retina scaling once\n      if (!this.interactive) {\n        this._initRetinaScaling();\n      }\n\n      if (options.overlayImage) {\n        this.setOverlayImage(options.overlayImage, cb);\n      }\n      if (options.backgroundImage) {\n        this.setBackgroundImage(options.backgroundImage, cb);\n      }\n      if (options.backgroundColor) {\n        this.setBackgroundColor(options.backgroundColor, cb);\n      }\n      if (options.overlayColor) {\n        this.setOverlayColor(options.overlayColor, cb);\n      }\n      this.calcOffset();\n    },\n\n    /**\n     * @private\n     */\n    _isRetinaScaling: function() {\n      return (fabric.devicePixelRatio !== 1 && this.enableRetinaScaling);\n    },\n\n    /**\n     * @private\n     * @return {Number} retinaScaling if applied, otherwise 1;\n     */\n    getRetinaScaling: function() {\n      return this._isRetinaScaling() ? fabric.devicePixelRatio : 1;\n    },\n\n    /**\n     * @private\n     */\n    _initRetinaScaling: function() {\n      if (!this._isRetinaScaling()) {\n        return;\n      }\n      this.lowerCanvasEl.setAttribute('width', this.width * fabric.devicePixelRatio);\n      this.lowerCanvasEl.setAttribute('height', this.height * fabric.devicePixelRatio);\n\n      this.contextContainer.scale(fabric.devicePixelRatio, fabric.devicePixelRatio);\n    },\n\n    /**\n     * Calculates canvas element offset relative to the document\n     * This method is also attached as \"resize\" event handler of window\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    calcOffset: function () {\n      this._offset = getElementOffset(this.lowerCanvasEl);\n      return this;\n    },\n\n    /**\n     * Sets {@link fabric.StaticCanvas#overlayImage|overlay image} for this canvas\n     * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set overlay to\n     * @param {Function} callback callback to invoke when image is loaded and set as an overlay\n     * @param {Object} [options] Optional options to set for the {@link fabric.Image|overlay image}.\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/MnzHT/|jsFiddle demo}\n     * @example <caption>Normal overlayImage with left/top = 0</caption>\n     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   // Needed to position overlayImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>overlayImage with different properties</caption>\n     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>Stretched overlayImage #1 - width/height correspond to canvas width/height</caption>\n     * fabric.Image.fromURL('http://fabricjs.com/assets/jail_cell_bars.png', function(img) {\n     *    img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});\n     *    canvas.setOverlayImage(img, canvas.renderAll.bind(canvas));\n     * });\n     * @example <caption>Stretched overlayImage #2 - width/height correspond to canvas width/height</caption>\n     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   width: canvas.width,\n     *   height: canvas.height,\n     *   // Needed to position overlayImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>overlayImage loaded from cross-origin</caption>\n     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top',\n     *   crossOrigin: 'anonymous'\n     * });\n     */\n    setOverlayImage: function (image, callback, options) {\n      return this.__setBgOverlayImage('overlayImage', image, callback, options);\n    },\n\n    /**\n     * Sets {@link fabric.StaticCanvas#backgroundImage|background image} for this canvas\n     * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set background to\n     * @param {Function} callback Callback to invoke when image is loaded and set as background\n     * @param {Object} [options] Optional options to set for the {@link fabric.Image|background image}.\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/YH9yD/|jsFiddle demo}\n     * @example <caption>Normal backgroundImage with left/top = 0</caption>\n     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   // Needed to position backgroundImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>backgroundImage with different properties</caption>\n     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>Stretched backgroundImage #1 - width/height correspond to canvas width/height</caption>\n     * fabric.Image.fromURL('http://fabricjs.com/assets/honey_im_subtle.png', function(img) {\n     *    img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});\n     *    canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));\n     * });\n     * @example <caption>Stretched backgroundImage #2 - width/height correspond to canvas width/height</caption>\n     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   width: canvas.width,\n     *   height: canvas.height,\n     *   // Needed to position backgroundImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>backgroundImage loaded from cross-origin</caption>\n     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top',\n     *   crossOrigin: 'anonymous'\n     * });\n     */\n    setBackgroundImage: function (image, callback, options) {\n      return this.__setBgOverlayImage('backgroundImage', image, callback, options);\n    },\n\n    /**\n     * Sets {@link fabric.StaticCanvas#overlayColor|background color} for this canvas\n     * @param {(String|fabric.Pattern)} overlayColor Color or pattern to set background color to\n     * @param {Function} callback Callback to invoke when background color is set\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/pB55h/|jsFiddle demo}\n     * @example <caption>Normal overlayColor - color value</caption>\n     * canvas.setOverlayColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));\n     * @example <caption>fabric.Pattern used as overlayColor</caption>\n     * canvas.setOverlayColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png'\n     * }, canvas.renderAll.bind(canvas));\n     * @example <caption>fabric.Pattern used as overlayColor with repeat and offset</caption>\n     * canvas.setOverlayColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png',\n     *   repeat: 'repeat',\n     *   offsetX: 200,\n     *   offsetY: 100\n     * }, canvas.renderAll.bind(canvas));\n     */\n    setOverlayColor: function(overlayColor, callback) {\n      return this.__setBgOverlayColor('overlayColor', overlayColor, callback);\n    },\n\n    /**\n     * Sets {@link fabric.StaticCanvas#backgroundColor|background color} for this canvas\n     * @param {(String|fabric.Pattern)} backgroundColor Color or pattern to set background color to\n     * @param {Function} callback Callback to invoke when background color is set\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/hXzvk/|jsFiddle demo}\n     * @example <caption>Normal backgroundColor - color value</caption>\n     * canvas.setBackgroundColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));\n     * @example <caption>fabric.Pattern used as backgroundColor</caption>\n     * canvas.setBackgroundColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png'\n     * }, canvas.renderAll.bind(canvas));\n     * @example <caption>fabric.Pattern used as backgroundColor with repeat and offset</caption>\n     * canvas.setBackgroundColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png',\n     *   repeat: 'repeat',\n     *   offsetX: 200,\n     *   offsetY: 100\n     * }, canvas.renderAll.bind(canvas));\n     */\n    setBackgroundColor: function(backgroundColor, callback) {\n      return this.__setBgOverlayColor('backgroundColor', backgroundColor, callback);\n    },\n\n    /**\n     * @private\n     * @see {@link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-imagesmoothingenabled|WhatWG Canvas Standard}\n     */\n    _setImageSmoothing: function() {\n      var ctx = this.getContext();\n\n      ctx.imageSmoothingEnabled = ctx.imageSmoothingEnabled || ctx.webkitImageSmoothingEnabled\n        || ctx.mozImageSmoothingEnabled || ctx.msImageSmoothingEnabled || ctx.oImageSmoothingEnabled;\n      ctx.imageSmoothingEnabled = this.imageSmoothingEnabled;\n    },\n\n    /**\n     * @private\n     * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundImage|backgroundImage}\n     * or {@link fabric.StaticCanvas#overlayImage|overlayImage})\n     * @param {(fabric.Image|String|null)} image fabric.Image instance, URL of an image or null to set background or overlay to\n     * @param {Function} callback Callback to invoke when image is loaded and set as background or overlay\n     * @param {Object} [options] Optional options to set for the {@link fabric.Image|image}.\n     */\n    __setBgOverlayImage: function(property, image, callback, options) {\n      if (typeof image === 'string') {\n        fabric.util.loadImage(image, function(img) {\n          img && (this[property] = new fabric.Image(img, options));\n          callback && callback(img);\n        }, this, options && options.crossOrigin);\n      }\n      else {\n        options && image.setOptions(options);\n        this[property] = image;\n        callback && callback(image);\n      }\n\n      return this;\n    },\n\n    /**\n     * @private\n     * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundColor|backgroundColor}\n     * or {@link fabric.StaticCanvas#overlayColor|overlayColor})\n     * @param {(Object|String|null)} color Object with pattern information, color value or null\n     * @param {Function} [callback] Callback is invoked when color is set\n     */\n    __setBgOverlayColor: function(property, color, callback) {\n      this[property] = color;\n      this._initGradient(color, property);\n      this._initPattern(color, property, callback);\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _createCanvasElement: function(canvasEl) {\n      var element = fabric.util.createCanvasElement(canvasEl);\n      if (!element.style) {\n        element.style = { };\n      }\n      if (!element) {\n        throw CANVAS_INIT_ERROR;\n      }\n      if (typeof element.getContext === 'undefined') {\n        throw CANVAS_INIT_ERROR;\n      }\n      return element;\n    },\n\n    /**\n     * @private\n     * @param {Object} [options] Options object\n     */\n    _initOptions: function (options) {\n      this._setOptions(options);\n\n      this.width = this.width || parseInt(this.lowerCanvasEl.width, 10) || 0;\n      this.height = this.height || parseInt(this.lowerCanvasEl.height, 10) || 0;\n\n      if (!this.lowerCanvasEl.style) {\n        return;\n      }\n\n      this.lowerCanvasEl.width = this.width;\n      this.lowerCanvasEl.height = this.height;\n\n      this.lowerCanvasEl.style.width = this.width + 'px';\n      this.lowerCanvasEl.style.height = this.height + 'px';\n\n      this.viewportTransform = this.viewportTransform.slice();\n    },\n\n    /**\n     * Creates a bottom canvas\n     * @private\n     * @param {HTMLElement} [canvasEl]\n     */\n    _createLowerCanvas: function (canvasEl) {\n      this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement(canvasEl);\n\n      fabric.util.addClass(this.lowerCanvasEl, 'lower-canvas');\n\n      if (this.interactive) {\n        this._applyCanvasStyle(this.lowerCanvasEl);\n      }\n\n      this.contextContainer = this.lowerCanvasEl.getContext('2d');\n    },\n\n    /**\n     * Returns canvas width (in px)\n     * @return {Number}\n     */\n    getWidth: function () {\n      return this.width;\n    },\n\n    /**\n     * Returns canvas height (in px)\n     * @return {Number}\n     */\n    getHeight: function () {\n      return this.height;\n    },\n\n    /**\n     * Sets width of this canvas instance\n     * @param {Number|String} value                         Value to set width to\n     * @param {Object}        [options]                     Options object\n     * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n     * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    setWidth: function (value, options) {\n      return this.setDimensions({ width: value }, options);\n    },\n\n    /**\n     * Sets height of this canvas instance\n     * @param {Number|String} value                         Value to set height to\n     * @param {Object}        [options]                     Options object\n     * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n     * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    setHeight: function (value, options) {\n      return this.setDimensions({ height: value }, options);\n    },\n\n    /**\n     * Sets dimensions (width, height) of this canvas instance. when options.cssOnly flag active you should also supply the unit of measure (px/%/em)\n     * @param {Object}        dimensions                    Object with width/height properties\n     * @param {Number|String} [dimensions.width]            Width of canvas element\n     * @param {Number|String} [dimensions.height]           Height of canvas element\n     * @param {Object}        [options]                     Options object\n     * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n     * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    setDimensions: function (dimensions, options) {\n      var cssValue;\n\n      options = options || {};\n\n      for (var prop in dimensions) {\n        cssValue = dimensions[prop];\n\n        if (!options.cssOnly) {\n          this._setBackstoreDimension(prop, dimensions[prop]);\n          cssValue += 'px';\n        }\n\n        if (!options.backstoreOnly) {\n          this._setCssDimension(prop, cssValue);\n        }\n      }\n      this._initRetinaScaling();\n      this._setImageSmoothing();\n      this.calcOffset();\n\n      if (!options.cssOnly) {\n        this.renderAll();\n      }\n\n      return this;\n    },\n\n    /**\n     * Helper for setting width/height\n     * @private\n     * @param {String} prop property (width|height)\n     * @param {Number} value value to set property to\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    _setBackstoreDimension: function (prop, value) {\n      this.lowerCanvasEl[prop] = value;\n\n      if (this.upperCanvasEl) {\n        this.upperCanvasEl[prop] = value;\n      }\n\n      if (this.cacheCanvasEl) {\n        this.cacheCanvasEl[prop] = value;\n      }\n\n      this[prop] = value;\n\n      return this;\n    },\n\n    /**\n     * Helper for setting css width/height\n     * @private\n     * @param {String} prop property (width|height)\n     * @param {String} value value to set property to\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    _setCssDimension: function (prop, value) {\n      this.lowerCanvasEl.style[prop] = value;\n\n      if (this.upperCanvasEl) {\n        this.upperCanvasEl.style[prop] = value;\n      }\n\n      if (this.wrapperEl) {\n        this.wrapperEl.style[prop] = value;\n      }\n\n      return this;\n    },\n\n    /**\n     * Returns canvas zoom level\n     * @return {Number}\n     */\n    getZoom: function () {\n      return this.viewportTransform[0];\n    },\n\n    /**\n     * Sets viewport transform of this canvas instance\n     * @param {Array} vpt the transform in the form of context.transform\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    setViewportTransform: function (vpt) {\n      var activeGroup = this._activeGroup, object, ignoreVpt = false, skipAbsolute = true;\n      this.viewportTransform = vpt;\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        object = this._objects[i];\n        object.group || object.setCoords(ignoreVpt, skipAbsolute);\n      }\n      if (activeGroup) {\n        activeGroup.setCoords(ignoreVpt, skipAbsolute);\n      }\n      this.calcViewportBoundaries();\n      this.renderAll();\n      return this;\n    },\n\n    /**\n     * Sets zoom level of this canvas instance, zoom centered around point\n     * @param {fabric.Point} point to zoom with respect to\n     * @param {Number} value to set zoom to, less than 1 zooms out\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    zoomToPoint: function (point, value) {\n      // TODO: just change the scale, preserve other transformations\n      var before = point, vpt = this.viewportTransform.slice(0);\n      point = transformPoint(point, invertTransform(this.viewportTransform));\n      vpt[0] = value;\n      vpt[3] = value;\n      var after = transformPoint(point, vpt);\n      vpt[4] += before.x - after.x;\n      vpt[5] += before.y - after.y;\n      return this.setViewportTransform(vpt);\n    },\n\n    /**\n     * Sets zoom level of this canvas instance\n     * @param {Number} value to set zoom to, less than 1 zooms out\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    setZoom: function (value) {\n      this.zoomToPoint(new fabric.Point(0, 0), value);\n      return this;\n    },\n\n    /**\n     * Pan viewport so as to place point at top left corner of canvas\n     * @param {fabric.Point} point to move to\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    absolutePan: function (point) {\n      var vpt = this.viewportTransform.slice(0);\n      vpt[4] = -point.x;\n      vpt[5] = -point.y;\n      return this.setViewportTransform(vpt);\n    },\n\n    /**\n     * Pans viewpoint relatively\n     * @param {fabric.Point} point (position vector) to move by\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    relativePan: function (point) {\n      return this.absolutePan(new fabric.Point(\n        -point.x - this.viewportTransform[4],\n        -point.y - this.viewportTransform[5]\n      ));\n    },\n\n    /**\n     * Returns &lt;canvas> element corresponding to this instance\n     * @return {HTMLCanvasElement}\n     */\n    getElement: function () {\n      return this.lowerCanvasEl;\n    },\n\n    /**\n     * @private\n     * @param {fabric.Object} obj Object that was added\n     */\n    _onObjectAdded: function(obj) {\n      this.stateful && obj.setupState();\n      obj._set('canvas', this);\n      obj.setCoords();\n      this.fire('object:added', { target: obj });\n      obj.fire('added');\n    },\n\n    /**\n     * @private\n     * @param {fabric.Object} obj Object that was removed\n     */\n    _onObjectRemoved: function(obj) {\n      this.fire('object:removed', { target: obj });\n      obj.fire('removed');\n      delete obj.canvas;\n    },\n\n    /**\n     * Clears specified context of canvas element\n     * @param {CanvasRenderingContext2D} ctx Context to clear\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    clearContext: function(ctx) {\n      ctx.clearRect(0, 0, this.width, this.height);\n      return this;\n    },\n\n    /**\n     * Returns context of canvas where objects are drawn\n     * @return {CanvasRenderingContext2D}\n     */\n    getContext: function () {\n      return this.contextContainer;\n    },\n\n    /**\n     * Clears all contexts (background, main, top) of an instance\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    clear: function () {\n      this._objects.length = 0;\n      this.backgroundImage = null;\n      this.overlayImage = null;\n      this.backgroundColor = '';\n      this.overlayColor = '';\n      if (this._hasITextHandlers) {\n        this.off('mouse:up', this._mouseUpITextHandler);\n        this._iTextInstances = null;\n        this._hasITextHandlers = false;\n      }\n      this.clearContext(this.contextContainer);\n      this.fire('canvas:cleared');\n      this.renderAll();\n      return this;\n    },\n\n    /**\n     * Renders the canvas\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    renderAll: function () {\n      var canvasToDrawOn = this.contextContainer;\n      this.renderCanvas(canvasToDrawOn, this._objects);\n      return this;\n    },\n\n    /**\n     * Calculate the position of the 4 corner of canvas with current viewportTransform.\n     * helps to determinate when an object is in the current rendering viewport using\n     * object absolute coordinates ( aCoords )\n     * @return {Object} points.tl\n     * @chainable\n     */\n    calcViewportBoundaries: function() {\n      var points = { }, width = this.getWidth(), height = this.getHeight(),\n          iVpt = invertTransform(this.viewportTransform);\n      points.tl = transformPoint({ x: 0, y: 0 }, iVpt);\n      points.br = transformPoint({ x: width, y: height }, iVpt);\n      points.tr = new fabric.Point(points.br.x, points.tl.y);\n      points.bl = new fabric.Point(points.tl.x, points.br.y);\n      this.vptCoords = points;\n      return points;\n    },\n\n    /**\n     * Renders background, objects, overlay and controls.\n     * @param {CanvasRenderingContext2D} ctx\n     * @param {Array} objects to render\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    renderCanvas: function(ctx, objects) {\n      this.calcViewportBoundaries();\n      this.clearContext(ctx);\n      this.fire('before:render');\n      if (this.clipTo) {\n        fabric.util.clipContext(this, ctx);\n      }\n      this._renderBackground(ctx);\n\n      ctx.save();\n      //apply viewport transform once for all rendering process\n      ctx.transform.apply(ctx, this.viewportTransform);\n      this._renderObjects(ctx, objects);\n      ctx.restore();\n      if (!this.controlsAboveOverlay && this.interactive) {\n        this.drawControls(ctx);\n      }\n      if (this.clipTo) {\n        ctx.restore();\n      }\n      this._renderOverlay(ctx);\n      if (this.controlsAboveOverlay && this.interactive) {\n        this.drawControls(ctx);\n      }\n      this.fire('after:render');\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Array} objects to render\n     */\n    _renderObjects: function(ctx, objects) {\n      for (var i = 0, length = objects.length; i < length; ++i) {\n        objects[i] && objects[i].render(ctx);\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {string} property 'background' or 'overlay'\n     */\n    _renderBackgroundOrOverlay: function(ctx, property) {\n      var object = this[property + 'Color'];\n      if (object) {\n        ctx.fillStyle = object.toLive\n          ? object.toLive(ctx, this)\n          : object;\n\n        ctx.fillRect(\n          object.offsetX || 0,\n          object.offsetY || 0,\n          this.width,\n          this.height);\n      }\n      object = this[property + 'Image'];\n      if (object) {\n        if (this[property + 'Vpt']) {\n          ctx.save();\n          ctx.transform.apply(ctx, this.viewportTransform);\n        }\n        object.render(ctx);\n        this[property + 'Vpt'] && ctx.restore();\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderBackground: function(ctx) {\n      this._renderBackgroundOrOverlay(ctx, 'background');\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderOverlay: function(ctx) {\n      this._renderBackgroundOrOverlay(ctx, 'overlay');\n    },\n\n    /**\n     * Returns coordinates of a center of canvas.\n     * Returned value is an object with top and left properties\n     * @return {Object} object with \"top\" and \"left\" number values\n     */\n    getCenter: function () {\n      return {\n        top: this.getHeight() / 2,\n        left: this.getWidth() / 2\n      };\n    },\n\n    /**\n     * Centers object horizontally in the canvas\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @param {fabric.Object} object Object to center horizontally\n     * @return {fabric.Canvas} thisArg\n     */\n    centerObjectH: function (object) {\n      return this._centerObject(object, new fabric.Point(this.getCenter().left, object.getCenterPoint().y));\n    },\n\n    /**\n     * Centers object vertically in the canvas\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @param {fabric.Object} object Object to center vertically\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    centerObjectV: function (object) {\n      return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, this.getCenter().top));\n    },\n\n    /**\n     * Centers object vertically and horizontally in the canvas\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @param {fabric.Object} object Object to center vertically and horizontally\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    centerObject: function(object) {\n      var center = this.getCenter();\n\n      return this._centerObject(object, new fabric.Point(center.left, center.top));\n    },\n\n    /**\n     * Centers object vertically and horizontally in the viewport\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @param {fabric.Object} object Object to center vertically and horizontally\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    viewportCenterObject: function(object) {\n      var vpCenter = this.getVpCenter();\n\n      return this._centerObject(object, vpCenter);\n    },\n\n    /**\n     * Centers object horizontally in the viewport, object.top is unchanged\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @param {fabric.Object} object Object to center vertically and horizontally\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    viewportCenterObjectH: function(object) {\n      var vpCenter = this.getVpCenter();\n      this._centerObject(object, new fabric.Point(vpCenter.x, object.getCenterPoint().y));\n      return this;\n    },\n\n    /**\n     * Centers object Vertically in the viewport, object.top is unchanged\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @param {fabric.Object} object Object to center vertically and horizontally\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    viewportCenterObjectV: function(object) {\n      var vpCenter = this.getVpCenter();\n\n      return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, vpCenter.y));\n    },\n\n    /**\n     * Calculate the point in canvas that correspond to the center of actual viewport.\n     * @return {fabric.Point} vpCenter, viewport center\n     * @chainable\n     */\n    getVpCenter: function() {\n      var center = this.getCenter(),\n          iVpt = invertTransform(this.viewportTransform);\n      return transformPoint({ x: center.left, y: center.top }, iVpt);\n    },\n\n    /**\n     * @private\n     * @param {fabric.Object} object Object to center\n     * @param {fabric.Point} center Center point\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    _centerObject: function(object, center) {\n      object.setPositionByOrigin(center, 'center', 'center');\n      this.renderAll();\n      return this;\n    },\n\n    /**\n     * Returs dataless JSON representation of canvas\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {String} json string\n     */\n    toDatalessJSON: function (propertiesToInclude) {\n      return this.toDatalessObject(propertiesToInclude);\n    },\n\n    /**\n     * Returns object representation of canvas\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function (propertiesToInclude) {\n      return this._toObjectMethod('toObject', propertiesToInclude);\n    },\n\n    /**\n     * Returns dataless object representation of canvas\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toDatalessObject: function (propertiesToInclude) {\n      return this._toObjectMethod('toDatalessObject', propertiesToInclude);\n    },\n\n    /**\n     * @private\n     */\n    _toObjectMethod: function (methodName, propertiesToInclude) {\n\n      var data = {\n        objects: this._toObjects(methodName, propertiesToInclude)\n      };\n\n      extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude));\n\n      fabric.util.populateWithProperties(this, data, propertiesToInclude);\n\n      return data;\n    },\n\n    /**\n     * @private\n     */\n    _toObjects: function(methodName, propertiesToInclude) {\n      return this.getObjects().filter(function(object) {\n        return !object.excludeFromExport;\n      }).map(function(instance) {\n        return this._toObject(instance, methodName, propertiesToInclude);\n      }, this);\n    },\n\n    /**\n     * @private\n     */\n    _toObject: function(instance, methodName, propertiesToInclude) {\n      var originalValue;\n\n      if (!this.includeDefaultValues) {\n        originalValue = instance.includeDefaultValues;\n        instance.includeDefaultValues = false;\n      }\n\n      var object = instance[methodName](propertiesToInclude);\n      if (!this.includeDefaultValues) {\n        instance.includeDefaultValues = originalValue;\n      }\n      return object;\n    },\n\n    /**\n     * @private\n     */\n    __serializeBgOverlay: function(methodName, propertiesToInclude) {\n      var data = { }, bgImage = this.backgroundImage, overlay = this.overlayImage;\n\n      if (this.backgroundColor) {\n        data.background = this.backgroundColor.toObject\n          ? this.backgroundColor.toObject(propertiesToInclude)\n          : this.backgroundColor;\n      }\n\n      if (this.overlayColor) {\n        data.overlay = this.overlayColor.toObject\n          ? this.overlayColor.toObject(propertiesToInclude)\n          : this.overlayColor;\n      }\n      if (bgImage && !bgImage.excludeFromExport) {\n        data.backgroundImage = this._toObject(bgImage, methodName, propertiesToInclude);\n      }\n      if (overlay && !overlay.excludeFromExport) {\n        data.overlayImage = this._toObject(overlay, methodName, propertiesToInclude);\n      }\n\n      return data;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * When true, getSvgTransform() will apply the StaticCanvas.viewportTransform to the SVG transformation. When true,\n     * a zoomed canvas will then produce zoomed SVG output.\n     * @type Boolean\n     * @default\n     */\n    svgViewportTransformation: true,\n\n    /**\n     * Returns SVG representation of canvas\n     * @function\n     * @param {Object} [options] Options object for SVG output\n     * @param {Boolean} [options.suppressPreamble=false] If true xml tag is not included\n     * @param {Object} [options.viewBox] SVG viewbox object\n     * @param {Number} [options.viewBox.x] x-cooridnate of viewbox\n     * @param {Number} [options.viewBox.y] y-coordinate of viewbox\n     * @param {Number} [options.viewBox.width] Width of viewbox\n     * @param {Number} [options.viewBox.height] Height of viewbox\n     * @param {String} [options.encoding=UTF-8] Encoding of SVG output\n     * @param {String} [options.width] desired width of svg with or without units\n     * @param {String} [options.height] desired height of svg with or without units\n     * @param {Function} [reviver] Method for further parsing of svg elements, called after each fabric object converted into svg representation.\n     * @return {String} SVG string\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization}\n     * @see {@link http://jsfiddle.net/fabricjs/jQ3ZZ/|jsFiddle demo}\n     * @example <caption>Normal SVG output</caption>\n     * var svg = canvas.toSVG();\n     * @example <caption>SVG output without preamble (without &lt;?xml ../>)</caption>\n     * var svg = canvas.toSVG({suppressPreamble: true});\n     * @example <caption>SVG output with viewBox attribute</caption>\n     * var svg = canvas.toSVG({\n     *   viewBox: {\n     *     x: 100,\n     *     y: 100,\n     *     width: 200,\n     *     height: 300\n     *   }\n     * });\n     * @example <caption>SVG output with different encoding (default: UTF-8)</caption>\n     * var svg = canvas.toSVG({encoding: 'ISO-8859-1'});\n     * @example <caption>Modify SVG output with reviver function</caption>\n     * var svg = canvas.toSVG(null, function(svg) {\n     *   return svg.replace('stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; ', '');\n     * });\n     */\n    toSVG: function(options, reviver) {\n      options || (options = { });\n\n      var markup = [];\n\n      this._setSVGPreamble(markup, options);\n      this._setSVGHeader(markup, options);\n\n      this._setSVGBgOverlayColor(markup, 'backgroundColor');\n      this._setSVGBgOverlayImage(markup, 'backgroundImage', reviver);\n\n      this._setSVGObjects(markup, reviver);\n\n      this._setSVGBgOverlayColor(markup, 'overlayColor');\n      this._setSVGBgOverlayImage(markup, 'overlayImage', reviver);\n\n      markup.push('</svg>');\n\n      return markup.join('');\n    },\n\n    /**\n     * @private\n     */\n    _setSVGPreamble: function(markup, options) {\n      if (options.suppressPreamble) {\n        return;\n      }\n      markup.push(\n        '<?xml version=\"1.0\" encoding=\"', (options.encoding || 'UTF-8'), '\" standalone=\"no\" ?>\\n',\n          '<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ',\n            '\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\\n'\n      );\n    },\n\n    /**\n     * @private\n     */\n    _setSVGHeader: function(markup, options) {\n      var width = options.width || this.width,\n          height = options.height || this.height,\n          vpt, viewBox = 'viewBox=\"0 0 ' + this.width + ' ' + this.height + '\" ',\n          NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n\n      if (options.viewBox) {\n        viewBox = 'viewBox=\"' +\n                options.viewBox.x + ' ' +\n                options.viewBox.y + ' ' +\n                options.viewBox.width + ' ' +\n                options.viewBox.height + '\" ';\n      }\n      else {\n        if (this.svgViewportTransformation) {\n          vpt = this.viewportTransform;\n          viewBox = 'viewBox=\"' +\n                  toFixed(-vpt[4] / vpt[0], NUM_FRACTION_DIGITS) + ' ' +\n                  toFixed(-vpt[5] / vpt[3], NUM_FRACTION_DIGITS) + ' ' +\n                  toFixed(this.width / vpt[0], NUM_FRACTION_DIGITS) + ' ' +\n                  toFixed(this.height / vpt[3], NUM_FRACTION_DIGITS) + '\" ';\n        }\n      }\n\n      markup.push(\n        '<svg ',\n          'xmlns=\"http://www.w3.org/2000/svg\" ',\n          'xmlns:xlink=\"http://www.w3.org/1999/xlink\" ',\n          'version=\"1.1\" ',\n          'width=\"', width, '\" ',\n          'height=\"', height, '\" ',\n          viewBox,\n          'xml:space=\"preserve\">\\n',\n        '<desc>Created with Fabric.js ', fabric.version, '</desc>\\n',\n        '<defs>\\n',\n          this.createSVGFontFacesMarkup(),\n          this.createSVGRefElementsMarkup(),\n        '</defs>\\n'\n      );\n    },\n\n    /**\n     * Creates markup containing SVG referenced elements like patterns, gradients etc.\n     * @return {String}\n     */\n    createSVGRefElementsMarkup: function() {\n      var _this = this,\n          markup = ['backgroundColor', 'overlayColor'].map(function(prop) {\n            var fill = _this[prop];\n            if (fill && fill.toLive) {\n              return fill.toSVG(_this, false);\n            }\n          });\n      return markup.join('');\n    },\n\n    /**\n     * Creates markup containing SVG font faces,\n     * font URLs for font faces must be collected by developers\n     * and are not extracted from the DOM by fabricjs\n     * @param {Array} objects Array of fabric objects\n     * @return {String}\n     */\n    createSVGFontFacesMarkup: function() {\n      var markup = '', fontList = { }, obj, fontFamily,\n          style, row, rowIndex, _char, charIndex,\n          fontPaths = fabric.fontPaths, objects = this.getObjects();\n\n      for (var i = 0, len = objects.length; i < len; i++) {\n        obj = objects[i];\n        fontFamily = obj.fontFamily;\n        if (obj.type.indexOf('text') === -1 || fontList[fontFamily] || !fontPaths[fontFamily]) {\n          continue;\n        }\n        fontList[fontFamily] = true;\n        if (!obj.styles) {\n          continue;\n        }\n        style = obj.styles;\n        for (rowIndex in style) {\n          row = style[rowIndex];\n          for (charIndex in row) {\n            _char = row[charIndex];\n            fontFamily = _char.fontFamily;\n            if (!fontList[fontFamily] && fontPaths[fontFamily]) {\n              fontList[fontFamily] = true;\n            }\n          }\n        }\n      }\n\n      for (var j in fontList) {\n        markup += [\n          '\\t\\t@font-face {\\n',\n          '\\t\\t\\tfont-family: \\'', j, '\\';\\n',\n          '\\t\\t\\tsrc: url(\\'', fontPaths[j], '\\');\\n',\n          '\\t\\t}\\n'\n        ].join('');\n      }\n\n      if (markup) {\n        markup = [\n          '\\t<style type=\"text/css\">',\n          '<![CDATA[\\n',\n          markup,\n          ']]>',\n          '</style>\\n'\n        ].join('');\n      }\n\n      return markup;\n    },\n\n    /**\n     * @private\n     */\n    _setSVGObjects: function(markup, reviver) {\n      var instance;\n      for (var i = 0, objects = this.getObjects(), len = objects.length; i < len; i++) {\n        instance = objects[i];\n        if (instance.excludeFromExport) {\n          continue;\n        }\n        this._setSVGObject(markup, instance, reviver);\n      }\n    },\n\n    /**\n     * push single object svg representation in the markup\n     * @private\n     */\n    _setSVGObject: function(markup, instance, reviver) {\n      markup.push(instance.toSVG(reviver));\n    },\n\n    /**\n     * @private\n     */\n    _setSVGBgOverlayImage: function(markup, property, reviver) {\n      if (this[property] && this[property].toSVG) {\n        markup.push(this[property].toSVG(reviver));\n      }\n    },\n\n    /**\n     * @private\n     */\n    _setSVGBgOverlayColor: function(markup, property) {\n      var filler = this[property];\n      if (!filler) {\n        return;\n      }\n      if (filler.toLive) {\n        var repeat = filler.repeat;\n        markup.push(\n          '<rect transform=\"translate(', this.width / 2, ',', this.height / 2, ')\"',\n            ' x=\"', filler.offsetX - this.width / 2, '\" y=\"', filler.offsetY - this.height / 2, '\" ',\n            'width=\"',\n              (repeat === 'repeat-y' || repeat === 'no-repeat'\n                ? filler.source.width\n                : this.width),\n            '\" height=\"',\n              (repeat === 'repeat-x' || repeat === 'no-repeat'\n                ? filler.source.height\n                : this.height),\n            '\" fill=\"url(#SVGID_' + filler.id + ')\"',\n          '></rect>\\n'\n        );\n      }\n      else {\n        markup.push(\n          '<rect x=\"0\" y=\"0\" ',\n            'width=\"', this.width,\n            '\" height=\"', this.height,\n            '\" fill=\"', this[property], '\"',\n          '></rect>\\n'\n        );\n      }\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Moves an object or the objects of a multiple selection\n     * to the bottom of the stack of drawn objects\n     * @param {fabric.Object} object Object to send to back\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    sendToBack: function (object) {\n      if (!object) {\n        return this;\n      }\n      var activeGroup = this._activeGroup,\n          i, obj, objs;\n      if (object === activeGroup) {\n        objs = activeGroup._objects;\n        for (i = objs.length; i--;) {\n          obj = objs[i];\n          removeFromArray(this._objects, obj);\n          this._objects.unshift(obj);\n        }\n      }\n      else {\n        removeFromArray(this._objects, object);\n        this._objects.unshift(object);\n      }\n      return this.renderAll && this.renderAll();\n    },\n\n    /**\n     * Moves an object or the objects of a multiple selection\n     * to the top of the stack of drawn objects\n     * @param {fabric.Object} object Object to send\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    bringToFront: function (object) {\n      if (!object) {\n        return this;\n      }\n      var activeGroup = this._activeGroup,\n          i, obj, objs;\n      if (object === activeGroup) {\n        objs = activeGroup._objects;\n        for (i = 0; i < objs.length; i++) {\n          obj = objs[i];\n          removeFromArray(this._objects, obj);\n          this._objects.push(obj);\n        }\n      }\n      else {\n        removeFromArray(this._objects, object);\n        this._objects.push(object);\n      }\n      return this.renderAll && this.renderAll();\n    },\n\n    /**\n     * Moves an object or a selection down in stack of drawn objects\n     * @param {fabric.Object} object Object to send\n     * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    sendBackwards: function (object, intersecting) {\n      if (!object) {\n        return this;\n      }\n\n      var activeGroup = this._activeGroup,\n          i, obj, idx, newIdx, objs, objsMoved = 0;\n\n      if (object === activeGroup) {\n        objs = activeGroup._objects;\n        for (i = 0; i < objs.length; i++) {\n          obj = objs[i];\n          idx = this._objects.indexOf(obj);\n          if (idx > 0 + objsMoved) {\n            newIdx = idx - 1;\n            removeFromArray(this._objects, obj);\n            this._objects.splice(newIdx, 0, obj);\n          }\n          objsMoved++;\n        }\n      }\n      else {\n        idx = this._objects.indexOf(object);\n        if (idx !== 0) {\n          // if object is not on the bottom of stack\n          newIdx = this._findNewLowerIndex(object, idx, intersecting);\n          removeFromArray(this._objects, object);\n          this._objects.splice(newIdx, 0, object);\n        }\n      }\n      this.renderAll && this.renderAll();\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _findNewLowerIndex: function(object, idx, intersecting) {\n      var newIdx;\n\n      if (intersecting) {\n        newIdx = idx;\n\n        // traverse down the stack looking for the nearest intersecting object\n        for (var i = idx - 1; i >= 0; --i) {\n\n          var isIntersecting = object.intersectsWithObject(this._objects[i]) ||\n                               object.isContainedWithinObject(this._objects[i]) ||\n                               this._objects[i].isContainedWithinObject(object);\n\n          if (isIntersecting) {\n            newIdx = i;\n            break;\n          }\n        }\n      }\n      else {\n        newIdx = idx - 1;\n      }\n\n      return newIdx;\n    },\n\n    /**\n     * Moves an object or a selection up in stack of drawn objects\n     * @param {fabric.Object} object Object to send\n     * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    bringForward: function (object, intersecting) {\n      if (!object) {\n        return this;\n      }\n\n      var activeGroup = this._activeGroup,\n          i, obj, idx, newIdx, objs, objsMoved = 0;\n\n      if (object === activeGroup) {\n        objs = activeGroup._objects;\n        for (i = objs.length; i--;) {\n          obj = objs[i];\n          idx = this._objects.indexOf(obj);\n          if (idx < this._objects.length - 1 - objsMoved) {\n            newIdx = idx + 1;\n            removeFromArray(this._objects, obj);\n            this._objects.splice(newIdx, 0, obj);\n          }\n          objsMoved++;\n        }\n      }\n      else {\n        idx = this._objects.indexOf(object);\n        if (idx !== this._objects.length - 1) {\n          // if object is not on top of stack (last item in an array)\n          newIdx = this._findNewUpperIndex(object, idx, intersecting);\n          removeFromArray(this._objects, object);\n          this._objects.splice(newIdx, 0, object);\n        }\n      }\n      this.renderAll && this.renderAll();\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _findNewUpperIndex: function(object, idx, intersecting) {\n      var newIdx;\n\n      if (intersecting) {\n        newIdx = idx;\n\n        // traverse up the stack looking for the nearest intersecting object\n        for (var i = idx + 1; i < this._objects.length; ++i) {\n\n          var isIntersecting = object.intersectsWithObject(this._objects[i]) ||\n                               object.isContainedWithinObject(this._objects[i]) ||\n                               this._objects[i].isContainedWithinObject(object);\n\n          if (isIntersecting) {\n            newIdx = i;\n            break;\n          }\n        }\n      }\n      else {\n        newIdx = idx + 1;\n      }\n\n      return newIdx;\n    },\n\n    /**\n     * Moves an object to specified level in stack of drawn objects\n     * @param {fabric.Object} object Object to send\n     * @param {Number} index Position to move to\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    moveTo: function (object, index) {\n      removeFromArray(this._objects, object);\n      this._objects.splice(index, 0, object);\n      return this.renderAll && this.renderAll();\n    },\n\n    /**\n     * Clears a canvas element and removes all event listeners\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    dispose: function () {\n      this.clear();\n      return this;\n    },\n\n    /**\n     * Returns a string representation of an instance\n     * @return {String} string representation of an instance\n     */\n    toString: function () {\n      return '#<fabric.Canvas (' + this.complexity() + '): ' +\n               '{ objects: ' + this.getObjects().length + ' }>';\n    }\n  });\n\n  extend(fabric.StaticCanvas.prototype, fabric.Observable);\n  extend(fabric.StaticCanvas.prototype, fabric.Collection);\n  extend(fabric.StaticCanvas.prototype, fabric.DataURLExporter);\n\n  extend(fabric.StaticCanvas, /** @lends fabric.StaticCanvas */ {\n\n    /**\n     * @static\n     * @type String\n     * @default\n     */\n    EMPTY_JSON: '{\"objects\": [], \"background\": \"white\"}',\n\n    /**\n     * Provides a way to check support of some of the canvas methods\n     * (either those of HTMLCanvasElement itself, or rendering context)\n     *\n     * @param {String} methodName Method to check support for;\n     *                            Could be one of \"getImageData\", \"toDataURL\", \"toDataURLWithQuality\" or \"setLineDash\"\n     * @return {Boolean | null} `true` if method is supported (or at least exists),\n     *                          `null` if canvas element or context can not be initialized\n     */\n    supports: function (methodName) {\n      var el = fabric.util.createCanvasElement();\n\n      if (!el || !el.getContext) {\n        return null;\n      }\n\n      var ctx = el.getContext('2d');\n      if (!ctx) {\n        return null;\n      }\n\n      switch (methodName) {\n\n        case 'getImageData':\n          return typeof ctx.getImageData !== 'undefined';\n\n        case 'setLineDash':\n          return typeof ctx.setLineDash !== 'undefined';\n\n        case 'toDataURL':\n          return typeof el.toDataURL !== 'undefined';\n\n        case 'toDataURLWithQuality':\n          try {\n            el.toDataURL('image/jpeg', 0);\n            return true;\n          }\n          catch (e) { }\n          return false;\n\n        default:\n          return null;\n      }\n    }\n  });\n\n  /**\n   * Returns JSON representation of canvas\n   * @function\n   * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n   * @return {String} JSON string\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization}\n   * @see {@link http://jsfiddle.net/fabricjs/pec86/|jsFiddle demo}\n   * @example <caption>JSON without additional properties</caption>\n   * var json = canvas.toJSON();\n   * @example <caption>JSON with additional properties included</caption>\n   * var json = canvas.toJSON(['lockMovementX', 'lockMovementY', 'lockRotation', 'lockScalingX', 'lockScalingY', 'lockUniScaling']);\n   * @example <caption>JSON without default values</caption>\n   * canvas.includeDefaultValues = false;\n   * var json = canvas.toJSON();\n   */\n  fabric.StaticCanvas.prototype.toJSON = fabric.StaticCanvas.prototype.toObject;\n\n})();\n\n\n/**\n * BaseBrush class\n * @class fabric.BaseBrush\n * @see {@link http://fabricjs.com/freedrawing|Freedrawing demo}\n */\nfabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ {\n\n  /**\n   * Color of a brush\n   * @type String\n   * @default\n   */\n  color: 'rgb(0, 0, 0)',\n\n  /**\n   * Width of a brush\n   * @type Number\n   * @default\n   */\n  width: 1,\n\n  /**\n   * Shadow object representing shadow of this shape.\n   * <b>Backwards incompatibility note:</b> This property replaces \"shadowColor\" (String), \"shadowOffsetX\" (Number),\n   * \"shadowOffsetY\" (Number) and \"shadowBlur\" (Number) since v1.2.12\n   * @type fabric.Shadow\n   * @default\n   */\n  shadow: null,\n\n  /**\n   * Line endings style of a brush (one of \"butt\", \"round\", \"square\")\n   * @type String\n   * @default\n   */\n  strokeLineCap: 'round',\n\n  /**\n   * Corner style of a brush (one of \"bevil\", \"round\", \"miter\")\n   * @type String\n   * @default\n   */\n  strokeLineJoin: 'round',\n\n  /**\n   * Stroke Dash Array.\n   * @type Array\n   * @default\n   */\n  strokeDashArray: null,\n\n  /**\n   * Sets shadow of an object\n   * @param {Object|String} [options] Options object or string (e.g. \"2px 2px 10px rgba(0,0,0,0.2)\")\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  setShadow: function(options) {\n    this.shadow = new fabric.Shadow(options);\n    return this;\n  },\n\n  /**\n   * Sets brush styles\n   * @private\n   */\n  _setBrushStyles: function() {\n    var ctx = this.canvas.contextTop;\n\n    ctx.strokeStyle = this.color;\n    ctx.lineWidth = this.width;\n    ctx.lineCap = this.strokeLineCap;\n    ctx.lineJoin = this.strokeLineJoin;\n    if (this.strokeDashArray && fabric.StaticCanvas.supports('setLineDash')) {\n      ctx.setLineDash(this.strokeDashArray);\n    }\n  },\n\n  /**\n   * Sets brush shadow styles\n   * @private\n   */\n  _setShadow: function() {\n    if (!this.shadow) {\n      return;\n    }\n\n    var ctx = this.canvas.contextTop,\n        zoom = this.canvas.getZoom();\n\n    ctx.shadowColor = this.shadow.color;\n    ctx.shadowBlur = this.shadow.blur * zoom;\n    ctx.shadowOffsetX = this.shadow.offsetX * zoom;\n    ctx.shadowOffsetY = this.shadow.offsetY * zoom;\n  },\n\n  /**\n   * Removes brush shadow styles\n   * @private\n   */\n  _resetShadow: function() {\n    var ctx = this.canvas.contextTop;\n\n    ctx.shadowColor = '';\n    ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;\n  }\n});\n\n\n(function() {\n\n  /**\n   * PencilBrush class\n   * @class fabric.PencilBrush\n   * @extends fabric.BaseBrush\n   */\n  fabric.PencilBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.PencilBrush.prototype */ {\n\n    /**\n     * Constructor\n     * @param {fabric.Canvas} canvas\n     * @return {fabric.PencilBrush} Instance of a pencil brush\n     */\n    initialize: function(canvas) {\n      this.canvas = canvas;\n      this._points = [];\n    },\n\n    /**\n     * Inovoked on mouse down\n     * @param {Object} pointer\n     */\n    onMouseDown: function(pointer) {\n      this._prepareForDrawing(pointer);\n      // capture coordinates immediately\n      // this allows to draw dots (when movement never occurs)\n      this._captureDrawingPath(pointer);\n      this._render();\n    },\n\n    /**\n     * Inovoked on mouse move\n     * @param {Object} pointer\n     */\n    onMouseMove: function(pointer) {\n      this._captureDrawingPath(pointer);\n      // redraw curve\n      // clear top canvas\n      this.canvas.clearContext(this.canvas.contextTop);\n      this._render();\n    },\n\n    /**\n     * Invoked on mouse up\n     */\n    onMouseUp: function() {\n      this._finalizeAndAddPath();\n    },\n\n    /**\n     * @private\n     * @param {Object} pointer Actual mouse position related to the canvas.\n     */\n    _prepareForDrawing: function(pointer) {\n\n      var p = new fabric.Point(pointer.x, pointer.y);\n\n      this._reset();\n      this._addPoint(p);\n\n      this.canvas.contextTop.moveTo(p.x, p.y);\n    },\n\n    /**\n     * @private\n     * @param {fabric.Point} point Point to be added to points array\n     */\n    _addPoint: function(point) {\n      if (this._points.length > 1 && point.eq(this._points[this._points.length - 1])) {\n        return;\n      }\n      this._points.push(point);\n    },\n\n    /**\n     * Clear points array and set contextTop canvas style.\n     * @private\n     */\n    _reset: function() {\n      this._points.length = 0;\n\n      this._setBrushStyles();\n      this._setShadow();\n    },\n\n    /**\n     * @private\n     * @param {Object} pointer Actual mouse position related to the canvas.\n     */\n    _captureDrawingPath: function(pointer) {\n      var pointerPoint = new fabric.Point(pointer.x, pointer.y);\n      this._addPoint(pointerPoint);\n    },\n\n    /**\n     * Draw a smooth path on the topCanvas using quadraticCurveTo\n     * @private\n     */\n    _render: function() {\n      var ctx  = this.canvas.contextTop, i, len,\n          v = this.canvas.viewportTransform,\n          p1 = this._points[0],\n          p2 = this._points[1];\n\n      ctx.save();\n      ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n      ctx.beginPath();\n\n      //if we only have 2 points in the path and they are the same\n      //it means that the user only clicked the canvas without moving the mouse\n      //then we should be drawing a dot. A path isn't drawn between two identical dots\n      //that's why we set them apart a bit\n      if (this._points.length === 2 && p1.x === p2.x && p1.y === p2.y) {\n        var width = this.width / 1000;\n        p1 = new fabric.Point(p1.x, p1.y);\n        p2 = new fabric.Point(p2.x, p2.y);\n        p1.x -= width;\n        p2.x += width;\n      }\n      ctx.moveTo(p1.x, p1.y);\n\n      for (i = 1, len = this._points.length; i < len; i++) {\n        // we pick the point between pi + 1 & pi + 2 as the\n        // end point and p1 as our control point.\n        var midPoint = p1.midPointFrom(p2);\n        ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);\n\n        p1 = this._points[i];\n        p2 = this._points[i + 1];\n      }\n      // Draw last line as a straight line while\n      // we wait for the next point to be able to calculate\n      // the bezier control point\n      ctx.lineTo(p1.x, p1.y);\n      ctx.stroke();\n      ctx.restore();\n    },\n\n    /**\n     * Converts points to SVG path\n     * @param {Array} points Array of points\n     * @return {String} SVG path\n     */\n    convertPointsToSVGPath: function(points) {\n      var path = [], i, width = this.width / 1000,\n          p1 = new fabric.Point(points[0].x, points[0].y),\n          p2 = new fabric.Point(points[1].x, points[1].y),\n          len = points.length, multSignX = 1, multSignY = 1, manyPoints = len > 2;\n\n      if (manyPoints) {\n        multSignX = points[2].x < p2.x ? -1 : points[2].x === p2.x ? 0 : 1;\n        multSignY = points[2].y < p2.y ? -1 : points[2].y === p2.y ? 0 : 1;\n      }\n      path.push('M ', p1.x - multSignX * width, ' ', p1.y - multSignY * width, ' ');\n      for (i = 1; i < len; i++) {\n        if (!p1.eq(p2)) {\n          var midPoint = p1.midPointFrom(p2);\n          // p1 is our bezier control point\n          // midpoint is our endpoint\n          // start point is p(i-1) value.\n          path.push('Q ', p1.x, ' ', p1.y, ' ', midPoint.x, ' ', midPoint.y, ' ');\n        }\n        p1 = points[i];\n        if ((i + 1) < points.length) {\n          p2 = points[i + 1];\n        }\n      }\n      if (manyPoints) {\n        multSignX = p1.x > points[i - 2].x ? 1 : p1.x === points[i - 2].x ? 0 : -1;\n        multSignY = p1.y > points[i - 2].y ? 1 : p1.y === points[i - 2].y ? 0 : -1;\n      }\n      path.push('L ', p1.x + multSignX * width, ' ', p1.y + multSignY * width);\n      return path;\n    },\n\n    /**\n     * Creates fabric.Path object to add on canvas\n     * @param {String} pathData Path data\n     * @return {fabric.Path} Path to add on canvas\n     */\n    createPath: function(pathData) {\n      var path = new fabric.Path(pathData, {\n        fill: null,\n        stroke: this.color,\n        strokeWidth: this.width,\n        strokeLineCap: this.strokeLineCap,\n        strokeLineJoin: this.strokeLineJoin,\n        strokeDashArray: this.strokeDashArray,\n        originX: 'center',\n        originY: 'center'\n      });\n      var position = new fabric.Point(path.left, path.top);\n      path.originX = fabric.Object.prototype.originX;\n      path.originY = fabric.Object.prototype.originY;\n      position = path.translateToGivenOrigin(\n        position, 'center', 'center', path.originX, path.originY);\n      path.top = position.y;\n      path.left = position.x;\n      if (this.shadow) {\n        this.shadow.affectStroke = true;\n        path.setShadow(this.shadow);\n      }\n\n      return path;\n    },\n\n    /**\n     * On mouseup after drawing the path on contextTop canvas\n     * we use the points captured to create an new fabric path object\n     * and add it to the fabric canvas.\n     */\n    _finalizeAndAddPath: function() {\n      var ctx = this.canvas.contextTop;\n      ctx.closePath();\n\n      var pathData = this.convertPointsToSVGPath(this._points).join('');\n      if (pathData === 'M 0 0 Q 0 0 0 0 L 0 0') {\n        // do not create 0 width/height paths, as they are\n        // rendered inconsistently across browsers\n        // Firefox 4, for example, renders a dot,\n        // whereas Chrome 10 renders nothing\n        this.canvas.renderAll();\n        return;\n      }\n\n      var path = this.createPath(pathData);\n\n      this.canvas.add(path);\n      path.setCoords();\n\n      this.canvas.clearContext(this.canvas.contextTop);\n      this._resetShadow();\n      this.canvas.renderAll();\n\n      // fire event 'path' created\n      this.canvas.fire('path:created', { path: path });\n    }\n  });\n})();\n\n\n/**\n * CircleBrush class\n * @class fabric.CircleBrush\n */\nfabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.CircleBrush.prototype */ {\n\n  /**\n   * Width of a brush\n   * @type Number\n   * @default\n   */\n  width: 10,\n\n  /**\n   * Constructor\n   * @param {fabric.Canvas} canvas\n   * @return {fabric.CircleBrush} Instance of a circle brush\n   */\n  initialize: function(canvas) {\n    this.canvas = canvas;\n    this.points = [];\n  },\n\n  /**\n   * Invoked inside on mouse down and mouse move\n   * @param {Object} pointer\n   */\n  drawDot: function(pointer) {\n    var point = this.addPoint(pointer),\n        ctx = this.canvas.contextTop,\n        v = this.canvas.viewportTransform;\n    ctx.save();\n    ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n\n    ctx.fillStyle = point.fill;\n    ctx.beginPath();\n    ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);\n    ctx.closePath();\n    ctx.fill();\n\n    ctx.restore();\n  },\n\n  /**\n   * Invoked on mouse down\n   */\n  onMouseDown: function(pointer) {\n    this.points.length = 0;\n    this.canvas.clearContext(this.canvas.contextTop);\n    this._setShadow();\n    this.drawDot(pointer);\n  },\n\n  /**\n   * Invoked on mouse move\n   * @param {Object} pointer\n   */\n  onMouseMove: function(pointer) {\n    this.drawDot(pointer);\n  },\n\n  /**\n   * Invoked on mouse up\n   */\n  onMouseUp: function() {\n    var originalRenderOnAddRemove = this.canvas.renderOnAddRemove;\n    this.canvas.renderOnAddRemove = false;\n\n    var circles = [];\n\n    for (var i = 0, len = this.points.length; i < len; i++) {\n      var point = this.points[i],\n          circle = new fabric.Circle({\n            radius: point.radius,\n            left: point.x,\n            top: point.y,\n            originX: 'center',\n            originY: 'center',\n            fill: point.fill\n          });\n\n      this.shadow && circle.setShadow(this.shadow);\n\n      circles.push(circle);\n    }\n    var group = new fabric.Group(circles, { originX: 'center', originY: 'center' });\n    group.canvas = this.canvas;\n\n    this.canvas.add(group);\n    this.canvas.fire('path:created', { path: group });\n\n    this.canvas.clearContext(this.canvas.contextTop);\n    this._resetShadow();\n    this.canvas.renderOnAddRemove = originalRenderOnAddRemove;\n    this.canvas.renderAll();\n  },\n\n  /**\n   * @param {Object} pointer\n   * @return {fabric.Point} Just added pointer point\n   */\n  addPoint: function(pointer) {\n    var pointerPoint = new fabric.Point(pointer.x, pointer.y),\n\n        circleRadius = fabric.util.getRandomInt(\n                        Math.max(0, this.width - 20), this.width + 20) / 2,\n\n        circleColor = new fabric.Color(this.color)\n                        .setAlpha(fabric.util.getRandomInt(0, 100) / 100)\n                        .toRgba();\n\n    pointerPoint.radius = circleRadius;\n    pointerPoint.fill = circleColor;\n\n    this.points.push(pointerPoint);\n\n    return pointerPoint;\n  }\n});\n\n\n/**\n * SprayBrush class\n * @class fabric.SprayBrush\n */\nfabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric.SprayBrush.prototype */ {\n\n  /**\n   * Width of a spray\n   * @type Number\n   * @default\n   */\n  width:              10,\n\n  /**\n   * Density of a spray (number of dots per chunk)\n   * @type Number\n   * @default\n   */\n  density:            20,\n\n  /**\n   * Width of spray dots\n   * @type Number\n   * @default\n   */\n  dotWidth:           1,\n\n  /**\n   * Width variance of spray dots\n   * @type Number\n   * @default\n   */\n  dotWidthVariance:   1,\n\n  /**\n   * Whether opacity of a dot should be random\n   * @type Boolean\n   * @default\n   */\n  randomOpacity:        false,\n\n  /**\n   * Whether overlapping dots (rectangles) should be removed (for performance reasons)\n   * @type Boolean\n   * @default\n   */\n  optimizeOverlapping:  true,\n\n  /**\n   * Constructor\n   * @param {fabric.Canvas} canvas\n   * @return {fabric.SprayBrush} Instance of a spray brush\n   */\n  initialize: function(canvas) {\n    this.canvas = canvas;\n    this.sprayChunks = [];\n  },\n\n  /**\n   * Invoked on mouse down\n   * @param {Object} pointer\n   */\n  onMouseDown: function(pointer) {\n    this.sprayChunks.length = 0;\n    this.canvas.clearContext(this.canvas.contextTop);\n    this._setShadow();\n\n    this.addSprayChunk(pointer);\n    this.render();\n  },\n\n  /**\n   * Invoked on mouse move\n   * @param {Object} pointer\n   */\n  onMouseMove: function(pointer) {\n    this.addSprayChunk(pointer);\n    this.render();\n  },\n\n  /**\n   * Invoked on mouse up\n   */\n  onMouseUp: function() {\n    var originalRenderOnAddRemove = this.canvas.renderOnAddRemove;\n    this.canvas.renderOnAddRemove = false;\n\n    var rects = [];\n\n    for (var i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {\n      var sprayChunk = this.sprayChunks[i];\n\n      for (var j = 0, jlen = sprayChunk.length; j < jlen; j++) {\n\n        var rect = new fabric.Rect({\n          width: sprayChunk[j].width,\n          height: sprayChunk[j].width,\n          left: sprayChunk[j].x + 1,\n          top: sprayChunk[j].y + 1,\n          originX: 'center',\n          originY: 'center',\n          fill: this.color\n        });\n\n        this.shadow && rect.setShadow(this.shadow);\n        rects.push(rect);\n      }\n    }\n\n    if (this.optimizeOverlapping) {\n      rects = this._getOptimizedRects(rects);\n    }\n\n    var group = new fabric.Group(rects, { originX: 'center', originY: 'center' });\n    group.canvas = this.canvas;\n\n    this.canvas.add(group);\n    this.canvas.fire('path:created', { path: group });\n\n    this.canvas.clearContext(this.canvas.contextTop);\n    this._resetShadow();\n    this.canvas.renderOnAddRemove = originalRenderOnAddRemove;\n    this.canvas.renderAll();\n  },\n\n  /**\n   * @private\n   * @param {Array} rects\n   */\n  _getOptimizedRects: function(rects) {\n\n    // avoid creating duplicate rects at the same coordinates\n    var uniqueRects = { }, key;\n\n    for (var i = 0, len = rects.length; i < len; i++) {\n      key = rects[i].left + '' + rects[i].top;\n      if (!uniqueRects[key]) {\n        uniqueRects[key] = rects[i];\n      }\n    }\n    var uniqueRectsArray = [];\n    for (key in uniqueRects) {\n      uniqueRectsArray.push(uniqueRects[key]);\n    }\n\n    return uniqueRectsArray;\n  },\n\n  /**\n   * Renders brush\n   */\n  render: function() {\n    var ctx = this.canvas.contextTop;\n    ctx.fillStyle = this.color;\n\n    var v = this.canvas.viewportTransform;\n    ctx.save();\n    ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n\n    for (var i = 0, len = this.sprayChunkPoints.length; i < len; i++) {\n      var point = this.sprayChunkPoints[i];\n      if (typeof point.opacity !== 'undefined') {\n        ctx.globalAlpha = point.opacity;\n      }\n      ctx.fillRect(point.x, point.y, point.width, point.width);\n    }\n    ctx.restore();\n  },\n\n  /**\n   * @param {Object} pointer\n   */\n  addSprayChunk: function(pointer) {\n    this.sprayChunkPoints = [];\n\n    var x, y, width, radius = this.width / 2;\n\n    for (var i = 0; i < this.density; i++) {\n\n      x = fabric.util.getRandomInt(pointer.x - radius, pointer.x + radius);\n      y = fabric.util.getRandomInt(pointer.y - radius, pointer.y + radius);\n\n      if (this.dotWidthVariance) {\n        width = fabric.util.getRandomInt(\n          // bottom clamp width to 1\n          Math.max(1, this.dotWidth - this.dotWidthVariance),\n          this.dotWidth + this.dotWidthVariance);\n      }\n      else {\n        width = this.dotWidth;\n      }\n\n      var point = new fabric.Point(x, y);\n      point.width = width;\n\n      if (this.randomOpacity) {\n        point.opacity = fabric.util.getRandomInt(0, 100) / 100;\n      }\n\n      this.sprayChunkPoints.push(point);\n    }\n\n    this.sprayChunks.push(this.sprayChunkPoints);\n  }\n});\n\n\n/**\n * PatternBrush class\n * @class fabric.PatternBrush\n * @extends fabric.BaseBrush\n */\nfabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fabric.PatternBrush.prototype */ {\n\n  getPatternSrc: function() {\n\n    var dotWidth = 20,\n        dotDistance = 5,\n        patternCanvas = fabric.document.createElement('canvas'),\n        patternCtx = patternCanvas.getContext('2d');\n\n    patternCanvas.width = patternCanvas.height = dotWidth + dotDistance;\n\n    patternCtx.fillStyle = this.color;\n    patternCtx.beginPath();\n    patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false);\n    patternCtx.closePath();\n    patternCtx.fill();\n\n    return patternCanvas;\n  },\n\n  getPatternSrcFunction: function() {\n    return String(this.getPatternSrc).replace('this.color', '\"' + this.color + '\"');\n  },\n\n  /**\n   * Creates \"pattern\" instance property\n   */\n  getPattern: function() {\n    return this.canvas.contextTop.createPattern(this.source || this.getPatternSrc(), 'repeat');\n  },\n\n  /**\n   * Sets brush styles\n   */\n  _setBrushStyles: function() {\n    this.callSuper('_setBrushStyles');\n    this.canvas.contextTop.strokeStyle = this.getPattern();\n  },\n\n  /**\n   * Creates path\n   */\n  createPath: function(pathData) {\n    var path = this.callSuper('createPath', pathData),\n        topLeft = path._getLeftTopCoords().scalarAdd(path.strokeWidth / 2);\n\n    path.stroke = new fabric.Pattern({\n      source: this.source || this.getPatternSrcFunction(),\n      offsetX: -topLeft.x,\n      offsetY: -topLeft.y\n    });\n    return path;\n  }\n});\n\n\n(function() {\n\n  var getPointer = fabric.util.getPointer,\n      degreesToRadians = fabric.util.degreesToRadians,\n      radiansToDegrees = fabric.util.radiansToDegrees,\n      atan2 = Math.atan2,\n      abs = Math.abs,\n      supportLineDash = fabric.StaticCanvas.supports('setLineDash'),\n\n      STROKE_OFFSET = 0.5;\n\n  /**\n   * Canvas class\n   * @class fabric.Canvas\n   * @extends fabric.StaticCanvas\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#canvas}\n   * @see {@link fabric.Canvas#initialize} for constructor definition\n   *\n   * @fires object:added\n   * @fires object:modified\n   * @fires object:rotating\n   * @fires object:scaling\n   * @fires object:moving\n   * @fires object:selected\n   *\n   * @fires before:selection:cleared\n   * @fires selection:cleared\n   * @fires selection:created\n   *\n   * @fires path:created\n   * @fires mouse:down\n   * @fires mouse:move\n   * @fires mouse:up\n   * @fires mouse:over\n   * @fires mouse:out\n   *\n   */\n  fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ {\n\n    /**\n     * Constructor\n     * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on\n     * @param {Object} [options] Options object\n     * @return {Object} thisArg\n     */\n    initialize: function(el, options) {\n      options || (options = { });\n\n      this._initStatic(el, options);\n      this._initInteractive();\n      this._createCacheCanvas();\n    },\n\n    /**\n     * When true, objects can be transformed by one side (unproportionally)\n     * @type Boolean\n     * @default\n     */\n    uniScaleTransform:      false,\n\n    /**\n     * Indicates which key enable unproportional scaling\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * If `null` or 'none' or any other string that is not a modifier key\n     * feature is disabled feature disabled.\n     * @since 1.6.2\n     * @type String\n     * @default\n     */\n    uniScaleKey:           'shiftKey',\n\n    /**\n     * When true, objects use center point as the origin of scale transformation.\n     * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n     * @since 1.3.4\n     * @type Boolean\n     * @default\n     */\n    centeredScaling:        false,\n\n    /**\n     * When true, objects use center point as the origin of rotate transformation.\n     * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n     * @since 1.3.4\n     * @type Boolean\n     * @default\n     */\n    centeredRotation:       false,\n\n    /**\n     * Indicates which key enable centered Transfrom\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * If `null` or 'none' or any other string that is not a modifier key\n     * feature is disabled feature disabled.\n     * @since 1.6.2\n     * @type String\n     * @default\n     */\n    centeredKey:           'altKey',\n\n    /**\n     * Indicates which key enable alternate action on corner\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * If `null` or 'none' or any other string that is not a modifier key\n     * feature is disabled feature disabled.\n     * @since 1.6.2\n     * @type String\n     * @default\n     */\n    altActionKey:           'shiftKey',\n\n    /**\n     * Indicates that canvas is interactive. This property should not be changed.\n     * @type Boolean\n     * @default\n     */\n    interactive:            true,\n\n    /**\n     * Indicates whether group selection should be enabled\n     * @type Boolean\n     * @default\n     */\n    selection:              true,\n\n    /**\n     * Indicates which key enable multiple click selection\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * If `null` or 'none' or any other string that is not a modifier key\n     * feature is disabled feature disabled.\n     * @since 1.6.2\n     * @type String\n     * @default\n     */\n    selectionKey:           'shiftKey',\n\n    /**\n     * Indicates which key enable alternative selection\n     * in case of target overlapping with active object\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * If `null` or 'none' or any other string that is not a modifier key\n     * feature is disabled feature disabled.\n     * @since 1.6.5\n     * @type null|String\n     * @default\n     */\n    altSelectionKey:           null,\n\n    /**\n     * Color of selection\n     * @type String\n     * @default\n     */\n    selectionColor:         'rgba(100, 100, 255, 0.3)', // blue\n\n    /**\n     * Default dash array pattern\n     * If not empty the selection border is dashed\n     * @type Array\n     */\n    selectionDashArray:     [],\n\n    /**\n     * Color of the border of selection (usually slightly darker than color of selection itself)\n     * @type String\n     * @default\n     */\n    selectionBorderColor:   'rgba(255, 255, 255, 0.3)',\n\n    /**\n     * Width of a line used in object/group selection\n     * @type Number\n     * @default\n     */\n    selectionLineWidth:     1,\n\n    /**\n     * Default cursor value used when hovering over an object on canvas\n     * @type String\n     * @default\n     */\n    hoverCursor:            'move',\n\n    /**\n     * Default cursor value used when moving an object on canvas\n     * @type String\n     * @default\n     */\n    moveCursor:             'move',\n\n    /**\n     * Default cursor value used for the entire canvas\n     * @type String\n     * @default\n     */\n    defaultCursor:          'default',\n\n    /**\n     * Cursor value used during free drawing\n     * @type String\n     * @default\n     */\n    freeDrawingCursor:      'crosshair',\n\n    /**\n     * Cursor value used for rotation point\n     * @type String\n     * @default\n     */\n    rotationCursor:         'crosshair',\n\n    /**\n     * Default element class that's given to wrapper (div) element of canvas\n     * @type String\n     * @default\n     */\n    containerClass:         'canvas-container',\n\n    /**\n     * When true, object detection happens on per-pixel basis rather than on per-bounding-box\n     * @type Boolean\n     * @default\n     */\n    perPixelTargetFind:     false,\n\n    /**\n     * Number of pixels around target pixel to tolerate (consider active) during object detection\n     * @type Number\n     * @default\n     */\n    targetFindTolerance:    0,\n\n    /**\n     * When true, target detection is skipped when hovering over canvas. This can be used to improve performance.\n     * @type Boolean\n     * @default\n     */\n    skipTargetFind:         false,\n\n    /**\n     * When true, mouse events on canvas (mousedown/mousemove/mouseup) result in free drawing.\n     * After mousedown, mousemove creates a shape,\n     * and then mouseup finalizes it and adds an instance of `fabric.Path` onto canvas.\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-4#free_drawing}\n     * @type Boolean\n     * @default\n     */\n    isDrawingMode:          false,\n\n    /**\n     * Indicates whether objects should remain in current stack position when selected.\n     * When false objects are brought to top and rendered as part of the selection group\n     * @type Boolean\n     * @default\n     */\n    preserveObjectStacking: false,\n\n    /**\n     * Indicates the angle that an object will lock to while rotating.\n     * @type Number\n     * @since 1.6.7\n     * @default\n     */\n    snapAngle: 0,\n\n    /**\n     * Indicates the distance from the snapAngle the rotation will lock to the snapAngle.\n     * When `null`, the snapThreshold will default to the snapAngle.\n     * @type null|Number\n     * @since 1.6.7\n     * @default\n     */\n    snapThreshold: null,\n\n    /**\n     * Indicates if the right click on canvas can output the context menu or not\n     * @type Boolean\n     * @since 1.6.5\n     * @default\n     */\n    stopContextMenu: false,\n\n    /**\n     * Indicates if the canvas can fire right click events\n     * @type Boolean\n     * @since 1.6.5\n     * @default\n     */\n    fireRightClick: false,\n\n    /**\n     * Indicates if the canvas can fire middle click events\n     * @type Boolean\n     * @since 1.7.8\n     * @default\n     */\n    fireMiddleClick: false,\n\n    /**\n     * @private\n     */\n    _initInteractive: function() {\n      this._currentTransform = null;\n      this._groupSelector = null;\n      this._initWrapperElement();\n      this._createUpperCanvas();\n      this._initEventListeners();\n\n      this._initRetinaScaling();\n\n      this.freeDrawingBrush = fabric.PencilBrush && new fabric.PencilBrush(this);\n\n      this.calcOffset();\n    },\n\n    /**\n     * Divides objects in two groups, one to render immediately\n     * and one to render as activeGroup.\n     * @return {Array} objects to render immediately and pushes the other in the activeGroup.\n     */\n    _chooseObjectsToRender: function() {\n      var activeGroup = this.getActiveGroup(),\n          activeObject = this.getActiveObject(),\n          object, objsToRender = [], activeGroupObjects = [];\n\n      if ((activeGroup || activeObject) && !this.preserveObjectStacking) {\n        for (var i = 0, length = this._objects.length; i < length; i++) {\n          object = this._objects[i];\n          if ((!activeGroup || !activeGroup.contains(object)) && object !== activeObject) {\n            objsToRender.push(object);\n          }\n          else {\n            activeGroupObjects.push(object);\n          }\n        }\n        if (activeGroup) {\n          activeGroup._set('_objects', activeGroupObjects);\n          objsToRender.push(activeGroup);\n        }\n        activeObject && objsToRender.push(activeObject);\n      }\n      else {\n        objsToRender = this._objects;\n      }\n      return objsToRender;\n    },\n\n    /**\n     * Renders both the top canvas and the secondary container canvas.\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    renderAll: function () {\n      if (this.contextTopDirty && !this._groupSelector && !this.isDrawingMode) {\n        this.clearContext(this.contextTop);\n        this.contextTopDirty = false;\n      }\n      var canvasToDrawOn = this.contextContainer;\n      this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender());\n      return this;\n    },\n\n    /**\n     * Method to render only the top canvas.\n     * Also used to render the group selection box.\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    renderTop: function () {\n      var ctx = this.contextTop;\n      this.clearContext(ctx);\n\n      // we render the top context - last object\n      if (this.selection && this._groupSelector) {\n        this._drawSelection(ctx);\n      }\n\n      this.fire('after:render');\n      this.contextTopDirty = true;\n      return this;\n    },\n\n    /**\n     * Resets the current transform to its original values and chooses the type of resizing based on the event\n     * @private\n     */\n    _resetCurrentTransform: function() {\n      var t = this._currentTransform;\n\n      t.target.set({\n        scaleX: t.original.scaleX,\n        scaleY: t.original.scaleY,\n        skewX: t.original.skewX,\n        skewY: t.original.skewY,\n        left: t.original.left,\n        top: t.original.top\n      });\n\n      if (this._shouldCenterTransform(t.target)) {\n        if (t.action === 'rotate') {\n          this._setOriginToCenter(t.target);\n        }\n        else {\n          if (t.originX !== 'center') {\n            if (t.originX === 'right') {\n              t.mouseXSign = -1;\n            }\n            else {\n              t.mouseXSign = 1;\n            }\n          }\n          if (t.originY !== 'center') {\n            if (t.originY === 'bottom') {\n              t.mouseYSign = -1;\n            }\n            else {\n              t.mouseYSign = 1;\n            }\n          }\n\n          t.originX = 'center';\n          t.originY = 'center';\n        }\n      }\n      else {\n        t.originX = t.original.originX;\n        t.originY = t.original.originY;\n      }\n    },\n\n    /**\n     * Checks if point is contained within an area of given object\n     * @param {Event} e Event object\n     * @param {fabric.Object} target Object to test against\n     * @param {Object} [point] x,y object of point coordinates we want to check.\n     * @return {Boolean} true if point is contained within an area of given object\n     */\n    containsPoint: function (e, target, point) {\n      var ignoreZoom = true,\n          pointer = point || this.getPointer(e, ignoreZoom),\n          xy;\n\n      if (target.group && target.group === this.getActiveGroup()) {\n        xy = this._normalizePointer(target.group, pointer);\n      }\n      else {\n        xy = { x: pointer.x, y: pointer.y };\n      }\n      // http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html\n      // http://idav.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html\n      return (target.containsPoint(xy) || target._findTargetCorner(pointer));\n    },\n\n    /**\n     * @private\n     */\n    _normalizePointer: function (object, pointer) {\n      var m = object.calcTransformMatrix(),\n          invertedM = fabric.util.invertTransform(m),\n          vptPointer = this.restorePointerVpt(pointer);\n      return fabric.util.transformPoint(vptPointer, invertedM);\n    },\n\n    /**\n     * Returns true if object is transparent at a certain location\n     * @param {fabric.Object} target Object to check\n     * @param {Number} x Left coordinate\n     * @param {Number} y Top coordinate\n     * @return {Boolean}\n     */\n    isTargetTransparent: function (target, x, y) {\n      var hasBorders = target.hasBorders,\n          transparentCorners = target.transparentCorners,\n          ctx = this.contextCache,\n          originalColor = target.selectionBackgroundColor;\n\n      target.hasBorders = target.transparentCorners = false;\n      target.selectionBackgroundColor = '';\n\n      ctx.save();\n      ctx.transform.apply(ctx, this.viewportTransform);\n      target.render(ctx);\n      ctx.restore();\n\n      target.active && target._renderControls(ctx);\n\n      target.hasBorders = hasBorders;\n      target.transparentCorners = transparentCorners;\n      target.selectionBackgroundColor = originalColor;\n\n      var isTransparent = fabric.util.isTransparent(\n        ctx, x, y, this.targetFindTolerance);\n\n      this.clearContext(ctx);\n\n      return isTransparent;\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @param {fabric.Object} target\n     */\n    _shouldClearSelection: function (e, target) {\n      var activeGroup = this.getActiveGroup(),\n          activeObject = this.getActiveObject();\n\n      return (\n        !target\n        ||\n        (target &&\n          activeGroup &&\n          !activeGroup.contains(target) &&\n          activeGroup !== target &&\n          !e[this.selectionKey])\n        ||\n        (target && !target.evented)\n        ||\n        (target &&\n          !target.selectable &&\n          activeObject &&\n          activeObject !== target)\n      );\n    },\n\n    /**\n     * @private\n     * @param {fabric.Object} target\n     */\n    _shouldCenterTransform: function (target) {\n      if (!target) {\n        return;\n      }\n\n      var t = this._currentTransform,\n          centerTransform;\n\n      if (t.action === 'scale' || t.action === 'scaleX' || t.action === 'scaleY') {\n        centerTransform = this.centeredScaling || target.centeredScaling;\n      }\n      else if (t.action === 'rotate') {\n        centerTransform = this.centeredRotation || target.centeredRotation;\n      }\n\n      return centerTransform ? !t.altKey : t.altKey;\n    },\n\n    /**\n     * @private\n     */\n    _getOriginFromCorner: function(target, corner) {\n      var origin = {\n        x: target.originX,\n        y: target.originY\n      };\n\n      if (corner === 'ml' || corner === 'tl' || corner === 'bl') {\n        origin.x = 'right';\n      }\n      else if (corner === 'mr' || corner === 'tr' || corner === 'br') {\n        origin.x = 'left';\n      }\n\n      if (corner === 'tl' || corner === 'mt' || corner === 'tr') {\n        origin.y = 'bottom';\n      }\n      else if (corner === 'bl' || corner === 'mb' || corner === 'br') {\n        origin.y = 'top';\n      }\n\n      return origin;\n    },\n\n    /**\n     * @private\n     */\n    _getActionFromCorner: function(target, corner, e) {\n      if (!corner) {\n        return 'drag';\n      }\n\n      switch (corner) {\n        case 'mtr':\n          return 'rotate';\n        case 'ml':\n        case 'mr':\n          return e[this.altActionKey] ? 'skewY' : 'scaleX';\n        case 'mt':\n        case 'mb':\n          return e[this.altActionKey] ? 'skewX' : 'scaleY';\n        default:\n          return 'scale';\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @param {fabric.Object} target\n     */\n    _setupCurrentTransform: function (e, target) {\n      if (!target) {\n        return;\n      }\n\n      var pointer = this.getPointer(e),\n          corner = target._findTargetCorner(this.getPointer(e, true)),\n          action = this._getActionFromCorner(target, corner, e),\n          origin = this._getOriginFromCorner(target, corner);\n\n      this._currentTransform = {\n        target: target,\n        action: action,\n        corner: corner,\n        scaleX: target.scaleX,\n        scaleY: target.scaleY,\n        skewX: target.skewX,\n        skewY: target.skewY,\n        offsetX: pointer.x - target.left,\n        offsetY: pointer.y - target.top,\n        originX: origin.x,\n        originY: origin.y,\n        ex: pointer.x,\n        ey: pointer.y,\n        lastX: pointer.x,\n        lastY: pointer.y,\n        left: target.left,\n        top: target.top,\n        theta: degreesToRadians(target.angle),\n        width: target.width * target.scaleX,\n        mouseXSign: 1,\n        mouseYSign: 1,\n        shiftKey: e.shiftKey,\n        altKey: e[this.centeredKey]\n      };\n\n      this._currentTransform.original = {\n        left: target.left,\n        top: target.top,\n        scaleX: target.scaleX,\n        scaleY: target.scaleY,\n        skewX: target.skewX,\n        skewY: target.skewY,\n        originX: origin.x,\n        originY: origin.y\n      };\n\n      this._resetCurrentTransform();\n    },\n\n    /**\n     * Translates object by \"setting\" its left/top\n     * @private\n     * @param {Number} x pointer's x coordinate\n     * @param {Number} y pointer's y coordinate\n     * @return {Boolean} true if the translation occurred\n     */\n    _translateObject: function (x, y) {\n      var transform = this._currentTransform,\n          target = transform.target,\n          newLeft = x - transform.offsetX,\n          newTop = y - transform.offsetY,\n          moveX = !target.get('lockMovementX') && target.left !== newLeft,\n          moveY = !target.get('lockMovementY') && target.top !== newTop;\n\n      moveX && target.set('left', newLeft);\n      moveY && target.set('top', newTop);\n      return moveX || moveY;\n    },\n\n    /**\n     * Check if we are increasing a positive skew or lower it,\n     * checking mouse direction and pressed corner.\n     * @private\n     */\n    _changeSkewTransformOrigin: function(mouseMove, t, by) {\n      var property = 'originX', origins = { 0: 'center' },\n          skew = t.target.skewX, originA = 'left', originB = 'right',\n          corner = t.corner === 'mt' || t.corner === 'ml' ? 1 : -1,\n          flipSign = 1;\n\n      mouseMove = mouseMove > 0 ? 1 : -1;\n      if (by === 'y') {\n        skew = t.target.skewY;\n        originA = 'top';\n        originB = 'bottom';\n        property = 'originY';\n      }\n      origins[-1] = originA;\n      origins[1] = originB;\n\n      t.target.flipX && (flipSign *= -1);\n      t.target.flipY && (flipSign *= -1);\n\n      if (skew === 0) {\n        t.skewSign = -corner * mouseMove * flipSign;\n        t[property] = origins[-mouseMove];\n      }\n      else {\n        skew = skew > 0 ? 1 : -1;\n        t.skewSign = skew;\n        t[property] = origins[skew * corner * flipSign];\n      }\n    },\n\n    /**\n     * Skew object by mouse events\n     * @private\n     * @param {Number} x pointer's x coordinate\n     * @param {Number} y pointer's y coordinate\n     * @param {String} by Either 'x' or 'y'\n     * @return {Boolean} true if the skewing occurred\n     */\n    _skewObject: function (x, y, by) {\n      var t = this._currentTransform,\n          target = t.target, skewed = false,\n          lockSkewingX = target.get('lockSkewingX'),\n          lockSkewingY = target.get('lockSkewingY');\n\n      if ((lockSkewingX && by === 'x') || (lockSkewingY && by === 'y')) {\n        return false;\n      }\n\n      // Get the constraint point\n      var center = target.getCenterPoint(),\n          actualMouseByCenter = target.toLocalPoint(new fabric.Point(x, y), 'center', 'center')[by],\n          lastMouseByCenter = target.toLocalPoint(new fabric.Point(t.lastX, t.lastY), 'center', 'center')[by],\n          actualMouseByOrigin, constraintPosition, dim = target._getTransformedDimensions();\n\n      this._changeSkewTransformOrigin(actualMouseByCenter - lastMouseByCenter, t, by);\n      actualMouseByOrigin = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY)[by];\n      constraintPosition = target.translateToOriginPoint(center, t.originX, t.originY);\n      // Actually skew the object\n      skewed = this._setObjectSkew(actualMouseByOrigin, t, by, dim);\n      t.lastX = x;\n      t.lastY = y;\n      // Make sure the constraints apply\n      target.setPositionByOrigin(constraintPosition, t.originX, t.originY);\n      return skewed;\n    },\n\n    /**\n     * Set object skew\n     * @private\n     * @return {Boolean} true if the skewing occurred\n     */\n    _setObjectSkew: function(localMouse, transform, by, _dim) {\n      var target = transform.target, newValue, skewed = false,\n          skewSign = transform.skewSign, newDim, dimNoSkew,\n          otherBy, _otherBy, _by, newDimMouse, skewX, skewY;\n\n      if (by === 'x') {\n        otherBy = 'y';\n        _otherBy = 'Y';\n        _by = 'X';\n        skewX = 0;\n        skewY = target.skewY;\n      }\n      else {\n        otherBy = 'x';\n        _otherBy = 'X';\n        _by = 'Y';\n        skewX = target.skewX;\n        skewY = 0;\n      }\n\n      dimNoSkew = target._getTransformedDimensions(skewX, skewY);\n      newDimMouse = 2 * Math.abs(localMouse) - dimNoSkew[by];\n      if (newDimMouse <= 2) {\n        newValue = 0;\n      }\n      else {\n        newValue = skewSign * Math.atan((newDimMouse / target['scale' + _by]) /\n                                        (dimNoSkew[otherBy] / target['scale' + _otherBy]));\n        newValue = fabric.util.radiansToDegrees(newValue);\n      }\n      skewed = target['skew' + _by] !== newValue;\n      target.set('skew' + _by, newValue);\n      if (target['skew' + _otherBy] !== 0) {\n        newDim = target._getTransformedDimensions();\n        newValue = (_dim[otherBy] / newDim[otherBy]) * target['scale' + _otherBy];\n        target.set('scale' + _otherBy, newValue);\n      }\n      return skewed;\n    },\n\n    /**\n     * Scales object by invoking its scaleX/scaleY methods\n     * @private\n     * @param {Number} x pointer's x coordinate\n     * @param {Number} y pointer's y coordinate\n     * @param {String} by Either 'x' or 'y' - specifies dimension constraint by which to scale an object.\n     *                    When not provided, an object is scaled by both dimensions equally\n     * @return {Boolean} true if the scaling occurred\n     */\n    _scaleObject: function (x, y, by) {\n      var t = this._currentTransform,\n          target = t.target,\n          lockScalingX = target.get('lockScalingX'),\n          lockScalingY = target.get('lockScalingY'),\n          lockScalingFlip = target.get('lockScalingFlip');\n\n      if (lockScalingX && lockScalingY) {\n        return false;\n      }\n\n      // Get the constraint point\n      var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY),\n          localMouse = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY),\n          dim = target._getTransformedDimensions(), scaled = false;\n\n      this._setLocalMouse(localMouse, t);\n\n      // Actually scale the object\n      scaled = this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by, lockScalingFlip, dim);\n\n      // Make sure the constraints apply\n      target.setPositionByOrigin(constraintPosition, t.originX, t.originY);\n      return scaled;\n    },\n\n    /**\n     * @private\n     * @return {Boolean} true if the scaling occurred\n     */\n    _setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {\n      var target = transform.target, forbidScalingX = false, forbidScalingY = false, scaled = false,\n          changeX, changeY, scaleX, scaleY;\n\n      scaleX = localMouse.x * target.scaleX / _dim.x;\n      scaleY = localMouse.y * target.scaleY / _dim.y;\n      changeX = target.scaleX !== scaleX;\n      changeY = target.scaleY !== scaleY;\n\n      if (lockScalingFlip && scaleX <= 0 && scaleX < target.scaleX) {\n        forbidScalingX = true;\n      }\n\n      if (lockScalingFlip && scaleY <= 0 && scaleY < target.scaleY) {\n        forbidScalingY = true;\n      }\n\n      if (by === 'equally' && !lockScalingX && !lockScalingY) {\n        forbidScalingX || forbidScalingY || (scaled = this._scaleObjectEqually(localMouse, target, transform, _dim));\n      }\n      else if (!by) {\n        forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = scaled || changeX));\n        forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY));\n      }\n      else if (by === 'x' && !target.get('lockUniScaling')) {\n        forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = scaled || changeX));\n      }\n      else if (by === 'y' && !target.get('lockUniScaling')) {\n        forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY));\n      }\n      transform.newScaleX = scaleX;\n      transform.newScaleY = scaleY;\n      forbidScalingX || forbidScalingY || this._flipObject(transform, by);\n      return scaled;\n    },\n\n    /**\n     * @private\n     * @return {Boolean} true if the scaling occurred\n     */\n    _scaleObjectEqually: function(localMouse, target, transform, _dim) {\n\n      var dist = localMouse.y + localMouse.x,\n          lastDist = _dim.y * transform.original.scaleY / target.scaleY +\n                     _dim.x * transform.original.scaleX / target.scaleX,\n          scaled, signX = localMouse.x / Math.abs(localMouse.x),\n          signY = localMouse.y / Math.abs(localMouse.y);\n\n      // We use transform.scaleX/Y instead of target.scaleX/Y\n      // because the object may have a min scale and we'll loose the proportions\n      transform.newScaleX = signX * Math.abs(transform.original.scaleX * dist / lastDist);\n      transform.newScaleY = signY * Math.abs(transform.original.scaleY * dist / lastDist);\n      scaled = transform.newScaleX !== target.scaleX || transform.newScaleY !== target.scaleY;\n      target.set('scaleX', transform.newScaleX);\n      target.set('scaleY', transform.newScaleY);\n      return scaled;\n    },\n\n    /**\n     * @private\n     */\n    _flipObject: function(transform, by) {\n      if (transform.newScaleX < 0 && by !== 'y') {\n        if (transform.originX === 'left') {\n          transform.originX = 'right';\n        }\n        else if (transform.originX === 'right') {\n          transform.originX = 'left';\n        }\n      }\n\n      if (transform.newScaleY < 0 && by !== 'x') {\n        if (transform.originY === 'top') {\n          transform.originY = 'bottom';\n        }\n        else if (transform.originY === 'bottom') {\n          transform.originY = 'top';\n        }\n      }\n    },\n\n    /**\n     * @private\n     */\n    _setLocalMouse: function(localMouse, t) {\n      var target = t.target, zoom = this.getZoom(),\n          padding = target.padding / zoom;\n\n      if (t.originX === 'right') {\n        localMouse.x *= -1;\n      }\n      else if (t.originX === 'center') {\n        localMouse.x *= t.mouseXSign * 2;\n        if (localMouse.x < 0) {\n          t.mouseXSign = -t.mouseXSign;\n        }\n      }\n\n      if (t.originY === 'bottom') {\n        localMouse.y *= -1;\n      }\n      else if (t.originY === 'center') {\n        localMouse.y *= t.mouseYSign * 2;\n        if (localMouse.y < 0) {\n          t.mouseYSign = -t.mouseYSign;\n        }\n      }\n\n      // adjust the mouse coordinates when dealing with padding\n      if (abs(localMouse.x) > padding) {\n        if (localMouse.x < 0) {\n          localMouse.x += padding;\n        }\n        else {\n          localMouse.x -= padding;\n        }\n      }\n      else { // mouse is within the padding, set to 0\n        localMouse.x = 0;\n      }\n\n      if (abs(localMouse.y) > padding) {\n        if (localMouse.y < 0) {\n          localMouse.y += padding;\n        }\n        else {\n          localMouse.y -= padding;\n        }\n      }\n      else {\n        localMouse.y = 0;\n      }\n    },\n\n    /**\n     * Rotates object by invoking its rotate method\n     * @private\n     * @param {Number} x pointer's x coordinate\n     * @param {Number} y pointer's y coordinate\n     * @return {Boolean} true if the rotation occurred\n     */\n    _rotateObject: function (x, y) {\n\n      var t = this._currentTransform;\n\n      if (t.target.get('lockRotation')) {\n        return false;\n      }\n\n      var lastAngle = atan2(t.ey - t.top, t.ex - t.left),\n          curAngle = atan2(y - t.top, x - t.left),\n          angle = radiansToDegrees(curAngle - lastAngle + t.theta),\n          hasRoated = true;\n\n      if (t.target.snapAngle > 0) {\n        var snapAngle  = t.target.snapAngle,\n            snapThreshold  = t.target.snapThreshold || snapAngle,\n            rightAngleLocked = Math.ceil(angle / snapAngle) * snapAngle,\n            leftAngleLocked = Math.floor(angle / snapAngle) * snapAngle;\n\n        if (Math.abs(angle - leftAngleLocked) < snapThreshold) {\n          angle = leftAngleLocked;\n        }\n        else if (Math.abs(angle - rightAngleLocked) < snapThreshold) {\n          angle = rightAngleLocked;\n        }\n      }\n\n      // normalize angle to positive value\n      if (angle < 0) {\n        angle = 360 + angle;\n      }\n      angle %= 360;\n\n      if (t.target.angle === angle) {\n        hasRoated = false;\n      }\n      else {\n        t.target.angle = angle;\n      }\n\n      return hasRoated;\n    },\n\n    /**\n     * Set the cursor type of the canvas element\n     * @param {String} value Cursor type of the canvas element.\n     * @see http://www.w3.org/TR/css3-ui/#cursor\n     */\n    setCursor: function (value) {\n      this.upperCanvasEl.style.cursor = value;\n    },\n\n    /**\n     * @param {fabric.Object} target to reset transform\n     * @private\n     */\n    _resetObjectTransform: function (target) {\n      target.scaleX = 1;\n      target.scaleY = 1;\n      target.skewX = 0;\n      target.skewY = 0;\n      target.setAngle(0);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx to draw the selection on\n     */\n    _drawSelection: function (ctx) {\n      var groupSelector = this._groupSelector,\n          left = groupSelector.left,\n          top = groupSelector.top,\n          aleft = abs(left),\n          atop = abs(top);\n\n      if (this.selectionColor) {\n        ctx.fillStyle = this.selectionColor;\n\n        ctx.fillRect(\n          groupSelector.ex - ((left > 0) ? 0 : -left),\n          groupSelector.ey - ((top > 0) ? 0 : -top),\n          aleft,\n          atop\n        );\n      }\n\n      if (!this.selectionLineWidth || !this.selectionBorderColor) {\n        return;\n      }\n      ctx.lineWidth = this.selectionLineWidth;\n      ctx.strokeStyle = this.selectionBorderColor;\n\n      // selection border\n      if (this.selectionDashArray.length > 1 && !supportLineDash) {\n\n        var px = groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),\n            py = groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop);\n\n        ctx.beginPath();\n\n        fabric.util.drawDashedLine(ctx, px, py, px + aleft, py, this.selectionDashArray);\n        fabric.util.drawDashedLine(ctx, px, py + atop - 1, px + aleft, py + atop - 1, this.selectionDashArray);\n        fabric.util.drawDashedLine(ctx, px, py, px, py + atop, this.selectionDashArray);\n        fabric.util.drawDashedLine(ctx, px + aleft - 1, py, px + aleft - 1, py + atop, this.selectionDashArray);\n\n        ctx.closePath();\n        ctx.stroke();\n      }\n      else {\n        fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray);\n        ctx.strokeRect(\n          groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),\n          groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop),\n          aleft,\n          atop\n        );\n      }\n    },\n\n    /**\n     * Method that determines what object we are clicking on\n     * the skipGroup parameter is for internal use, is needed for shift+click action\n     * @param {Event} e mouse event\n     * @param {Boolean} skipGroup when true, activeGroup is skipped and only objects are traversed through\n     */\n    findTarget: function (e, skipGroup) {\n      if (this.skipTargetFind) {\n        return;\n      }\n\n      var ignoreZoom = true,\n          pointer = this.getPointer(e, ignoreZoom),\n          activeGroup = this.getActiveGroup(),\n          activeObject = this.getActiveObject(),\n          activeTarget, activeTargetSubs;\n      // first check current group (if one exists)\n      // active group does not check sub targets like normal groups.\n      // if active group just exits.\n      this.targets = [];\n      if (activeGroup && !skipGroup && activeGroup === this._searchPossibleTargets([activeGroup], pointer)) {\n        this._fireOverOutEvents(activeGroup, e);\n        return activeGroup;\n      }\n      // if we hit the corner of an activeObject, let's return that.\n      if (activeObject && activeObject._findTargetCorner(pointer)) {\n        this._fireOverOutEvents(activeObject, e);\n        return activeObject;\n      }\n      if (activeObject && activeObject === this._searchPossibleTargets([activeObject], pointer)) {\n        if (!this.preserveObjectStacking) {\n          this._fireOverOutEvents(activeObject, e);\n          return activeObject;\n        }\n        else {\n          activeTarget = activeObject;\n          activeTargetSubs = this.targets;\n          this.targets = [];\n        }\n      }\n\n      var target = this._searchPossibleTargets(this._objects, pointer);\n      if (e[this.altSelectionKey] && target && activeTarget && target !== activeTarget) {\n        target = activeTarget;\n        this.targets = activeTargetSubs;\n      }\n      this._fireOverOutEvents(target, e);\n      return target;\n    },\n\n    /**\n     * @private\n     */\n    _fireOverOutEvents: function(target, e) {\n      var overOpt, outOpt, hoveredTarget = this._hoveredTarget;\n      if (hoveredTarget !== target) {\n        overOpt = { e: e, target: target, previousTarget: this._hoveredTarget };\n        outOpt = { e: e, target: this._hoveredTarget, nextTarget: target };\n        this._hoveredTarget = target;\n      }\n      if (target) {\n        if (hoveredTarget !== target) {\n          if (hoveredTarget) {\n            this.fire('mouse:out', outOpt);\n            hoveredTarget.fire('mouseout', outOpt);\n          }\n          this.fire('mouse:over', overOpt);\n          target.fire('mouseover', overOpt);\n        }\n      }\n      else if (hoveredTarget) {\n        this.fire('mouse:out', outOpt);\n        hoveredTarget.fire('mouseout', outOpt);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _checkTarget: function(pointer, obj) {\n      if (obj &&\n          obj.visible &&\n          obj.evented &&\n          this.containsPoint(null, obj, pointer)){\n        if ((this.perPixelTargetFind || obj.perPixelTargetFind) && !obj.isEditing) {\n          var isTransparent = this.isTargetTransparent(obj, pointer.x, pointer.y);\n          if (!isTransparent) {\n            return true;\n          }\n        }\n        else {\n          return true;\n        }\n      }\n    },\n\n    /**\n     * @private\n     */\n    _searchPossibleTargets: function(objects, pointer) {\n\n      // Cache all targets where their bounding box contains point.\n      var target, i = objects.length, normalizedPointer, subTarget;\n      // Do not check for currently grouped objects, since we check the parent group itself.\n      // untill we call this function specifically to search inside the activeGroup\n      while (i--) {\n        if (this._checkTarget(pointer, objects[i])) {\n          target = objects[i];\n          if (target.type === 'group' && target.subTargetCheck) {\n            normalizedPointer = this._normalizePointer(target, pointer);\n            subTarget = this._searchPossibleTargets(target._objects, normalizedPointer);\n            subTarget && this.targets.push(subTarget);\n          }\n          break;\n        }\n      }\n      return target;\n    },\n\n    /**\n     * Returns pointer coordinates without the effect of the viewport\n     * @param {Object} pointer with \"x\" and \"y\" number values\n     * @return {Object} object with \"x\" and \"y\" number values\n     */\n    restorePointerVpt: function(pointer) {\n      return fabric.util.transformPoint(\n        pointer,\n        fabric.util.invertTransform(this.viewportTransform)\n      );\n    },\n\n    /**\n     * Returns pointer coordinates relative to canvas.\n     * Can return coordinates with or without viewportTransform.\n     * ignoreZoom false gives back coordinates that represent\n     * the point clicked on canvas element.\n     * ignoreZoom true gives back coordinates after being processed\n     * by the viewportTransform ( sort of coordinates of what is displayed\n     * on the canvas where you are clicking.\n     * To interact with your shapes top and left you want to use ignoreZoom true\n     * most of the time, while ignoreZoom false will give you coordinates\n     * compatible with the object.oCoords system.\n     * of the time.\n     * @param {Event} e\n     * @param {Boolean} ignoreZoom\n     * @return {Object} object with \"x\" and \"y\" number values\n     */\n    getPointer: function (e, ignoreZoom, upperCanvasEl) {\n      if (!upperCanvasEl) {\n        upperCanvasEl = this.upperCanvasEl;\n      }\n      var pointer = getPointer(e),\n          bounds = upperCanvasEl.getBoundingClientRect(),\n          boundsWidth = bounds.width || 0,\n          boundsHeight = bounds.height || 0,\n          cssScale;\n\n      if (!boundsWidth || !boundsHeight ) {\n        if ('top' in bounds && 'bottom' in bounds) {\n          boundsHeight = Math.abs( bounds.top - bounds.bottom );\n        }\n        if ('right' in bounds && 'left' in bounds) {\n          boundsWidth = Math.abs( bounds.right - bounds.left );\n        }\n      }\n\n      this.calcOffset();\n\n      pointer.x = pointer.x - this._offset.left;\n      pointer.y = pointer.y - this._offset.top;\n      if (!ignoreZoom) {\n        pointer = this.restorePointerVpt(pointer);\n      }\n\n      if (boundsWidth === 0 || boundsHeight === 0) {\n        // If bounds are not available (i.e. not visible), do not apply scale.\n        cssScale = { width: 1, height: 1 };\n      }\n      else {\n        cssScale = {\n          width: upperCanvasEl.width / boundsWidth,\n          height: upperCanvasEl.height / boundsHeight\n        };\n      }\n\n      return {\n        x: pointer.x * cssScale.width,\n        y: pointer.y * cssScale.height\n      };\n    },\n\n    /**\n     * @private\n     * @throws {CANVAS_INIT_ERROR} If canvas can not be initialized\n     */\n    _createUpperCanvas: function () {\n      var lowerCanvasClass = this.lowerCanvasEl.className.replace(/\\s*lower-canvas\\s*/, '');\n\n      if (this.upperCanvasEl) {\n        this.upperCanvasEl.className = '';\n      }\n      else {\n        this.upperCanvasEl = this._createCanvasElement();\n      }\n      fabric.util.addClass(this.upperCanvasEl, 'upper-canvas ' + lowerCanvasClass);\n\n      this.wrapperEl.appendChild(this.upperCanvasEl);\n\n      this._copyCanvasStyle(this.lowerCanvasEl, this.upperCanvasEl);\n      this._applyCanvasStyle(this.upperCanvasEl);\n      this.contextTop = this.upperCanvasEl.getContext('2d');\n    },\n\n    /**\n     * @private\n     */\n    _createCacheCanvas: function () {\n      this.cacheCanvasEl = this._createCanvasElement();\n      this.cacheCanvasEl.setAttribute('width', this.width);\n      this.cacheCanvasEl.setAttribute('height', this.height);\n      this.contextCache = this.cacheCanvasEl.getContext('2d');\n    },\n\n    /**\n     * @private\n     */\n    _initWrapperElement: function () {\n      this.wrapperEl = fabric.util.wrapElement(this.lowerCanvasEl, 'div', {\n        'class': this.containerClass\n      });\n      fabric.util.setStyle(this.wrapperEl, {\n        width: this.getWidth() + 'px',\n        height: this.getHeight() + 'px',\n        position: 'relative'\n      });\n      fabric.util.makeElementUnselectable(this.wrapperEl);\n    },\n\n    /**\n     * @private\n     * @param {HTMLElement} element canvas element to apply styles on\n     */\n    _applyCanvasStyle: function (element) {\n      var width = this.getWidth() || element.width,\n          height = this.getHeight() || element.height;\n\n      fabric.util.setStyle(element, {\n        position: 'absolute',\n        width: width + 'px',\n        height: height + 'px',\n        left: 0,\n        top: 0,\n        'touch-action': 'none'\n      });\n      element.width = width;\n      element.height = height;\n      fabric.util.makeElementUnselectable(element);\n    },\n\n    /**\n     * Copys the the entire inline style from one element (fromEl) to another (toEl)\n     * @private\n     * @param {Element} fromEl Element style is copied from\n     * @param {Element} toEl Element copied style is applied to\n     */\n    _copyCanvasStyle: function (fromEl, toEl) {\n      toEl.style.cssText = fromEl.style.cssText;\n    },\n\n    /**\n     * Returns context of canvas where object selection is drawn\n     * @return {CanvasRenderingContext2D}\n     */\n    getSelectionContext: function() {\n      return this.contextTop;\n    },\n\n    /**\n     * Returns &lt;canvas> element on which object selection is drawn\n     * @return {HTMLCanvasElement}\n     */\n    getSelectionElement: function () {\n      return this.upperCanvasEl;\n    },\n\n    /**\n     * @private\n     * @param {Object} object\n     */\n    _setActiveObject: function(object) {\n      var obj = this._activeObject;\n      if (obj) {\n        obj.set('active', false);\n        if (object !== obj && obj.onDeselect && typeof obj.onDeselect === 'function') {\n          obj.onDeselect();\n        }\n      }\n      this._activeObject = object;\n      object.set('active', true);\n    },\n\n    /**\n     * Sets given object as the only active object on canvas\n     * @param {fabric.Object} object Object to set as an active one\n     * @param {Event} [e] Event (passed along when firing \"object:selected\")\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    setActiveObject: function (object, e) {\n      var currentActiveObject = this.getActiveObject();\n      if (currentActiveObject && currentActiveObject !== object) {\n        currentActiveObject.fire('deselected', { e: e });\n      }\n      this._setActiveObject(object);\n      this.fire('object:selected', { target: object, e: e });\n      object.fire('selected', { e: e });\n      this.renderAll();\n      return this;\n    },\n\n    /**\n     * Returns currently active object\n     * @return {fabric.Object} active object\n     */\n    getActiveObject: function () {\n      return this._activeObject;\n    },\n\n    /**\n     * @private\n     * @param {fabric.Object} obj Object that was removed\n     */\n    _onObjectRemoved: function(obj) {\n      // removing active object should fire \"selection:cleared\" events\n      if (this.getActiveObject() === obj) {\n        this.fire('before:selection:cleared', { target: obj });\n        this._discardActiveObject();\n        this.fire('selection:cleared', { target: obj });\n        obj.fire('deselected');\n      }\n      if (this._hoveredTarget === obj) {\n        this._hoveredTarget = null;\n      }\n      this.callSuper('_onObjectRemoved', obj);\n    },\n\n    /**\n     * @private\n     */\n    _discardActiveObject: function() {\n      var obj = this._activeObject;\n      if (obj) {\n        obj.set('active', false);\n        if (obj.onDeselect && typeof obj.onDeselect === 'function') {\n          obj.onDeselect();\n        }\n      }\n      this._activeObject = null;\n    },\n\n    /**\n     * Discards currently active object and fire events. If the function is called by fabric\n     * as a consequence of a mouse event, the event is passed as a parmater and\n     * sent to the fire function for the custom events. When used as a method the\n     * e param does not have any application.\n     * @param {event} e\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    discardActiveObject: function (e) {\n      var activeObject = this._activeObject;\n      if (activeObject) {\n        this.fire('before:selection:cleared', { target: activeObject, e: e });\n        this._discardActiveObject();\n        this.fire('selection:cleared', { e: e });\n        activeObject.fire('deselected', { e: e });\n      }\n      return this;\n    },\n\n    /**\n     * @private\n     * @param {fabric.Group} group\n     */\n    _setActiveGroup: function(group) {\n      this._activeGroup = group;\n      if (group) {\n        group.set('active', true);\n      }\n    },\n\n    /**\n     * Sets active group to a specified one. If the function is called by fabric\n     * as a consequence of a mouse event, the event is passed as a parmater and\n     * sent to the fire function for the custom events. When used as a method the\n     * e param does not have any application.\n     * @param {fabric.Group} group Group to set as a current one\n     * @param {Event} e Event object\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    setActiveGroup: function (group, e) {\n      this._setActiveGroup(group);\n      if (group) {\n        this.fire('object:selected', { target: group, e: e });\n        group.fire('selected', { e: e });\n      }\n      return this;\n    },\n\n    /**\n     * Returns currently active group\n     * @return {fabric.Group} Current group\n     */\n    getActiveGroup: function () {\n      return this._activeGroup;\n    },\n\n    /**\n     * @private\n     */\n    _discardActiveGroup: function() {\n      var g = this.getActiveGroup();\n      if (g) {\n        g.destroy();\n      }\n      this.setActiveGroup(null);\n    },\n\n    /**\n     * Discards currently active group and fire events If the function is called by fabric\n     * as a consequence of a mouse event, the event is passed as a parmater and\n     * sent to the fire function for the custom events. When used as a method the\n     * e param does not have any application.\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    discardActiveGroup: function (e) {\n      var g = this.getActiveGroup();\n      if (g) {\n        this.fire('before:selection:cleared', { e: e, target: g });\n        this._discardActiveGroup();\n        this.fire('selection:cleared', { e: e });\n      }\n      return this;\n    },\n\n    /**\n     * Deactivates all objects on canvas, removing any active group or object\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    deactivateAll: function () {\n      var allObjects = this.getObjects(),\n          i = 0,\n          len = allObjects.length,\n          obj;\n      for ( ; i < len; i++) {\n        obj = allObjects[i];\n        obj && obj.set('active', false);\n      }\n      this._discardActiveGroup();\n      this._discardActiveObject();\n      return this;\n    },\n\n    /**\n     * Deactivates all objects and dispatches appropriate events If the function is called by fabric\n     * as a consequence of a mouse event, the event is passed as a parmater and\n     * sent to the fire function for the custom events. When used as a method the\n     * e param does not have any application.\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    deactivateAllWithDispatch: function (e) {\n      var allObjects = this.getObjects(),\n          i = 0,\n          len = allObjects.length,\n          obj;\n      for ( ; i < len; i++) {\n        obj = allObjects[i];\n        obj && obj.set('active', false);\n      }\n      this.discardActiveGroup(e);\n      this.discardActiveObject(e);\n      return this;\n    },\n\n    /**\n     * Clears a canvas element and removes all event listeners\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    dispose: function () {\n      fabric.StaticCanvas.prototype.dispose.call(this);\n      var wrapper = this.wrapperEl;\n      this.removeListeners();\n      wrapper.removeChild(this.upperCanvasEl);\n      wrapper.removeChild(this.lowerCanvasEl);\n      delete this.upperCanvasEl;\n      if (wrapper.parentNode) {\n        wrapper.parentNode.replaceChild(this.lowerCanvasEl, this.wrapperEl);\n      }\n      delete this.wrapperEl;\n      return this;\n    },\n\n    /**\n     * Clears all contexts (background, main, top) of an instance\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    clear: function () {\n      this.discardActiveGroup();\n      this.discardActiveObject();\n      this.clearContext(this.contextTop);\n      return this.callSuper('clear');\n    },\n\n    /**\n     * Draws objects' controls (borders/controls)\n     * @param {CanvasRenderingContext2D} ctx Context to render controls on\n     */\n    drawControls: function(ctx) {\n      var activeGroup = this.getActiveGroup();\n\n      if (activeGroup) {\n        activeGroup._renderControls(ctx);\n      }\n      else {\n        this._drawObjectsControls(ctx);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _drawObjectsControls: function(ctx) {\n      for (var i = 0, len = this._objects.length; i < len; ++i) {\n        if (!this._objects[i] || !this._objects[i].active) {\n          continue;\n        }\n        this._objects[i]._renderControls(ctx);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _toObject: function(instance, methodName, propertiesToInclude) {\n      //If the object is part of the current selection group, it should\n      //be transformed appropriately\n      //i.e. it should be serialised as it would appear if the selection group\n      //were to be destroyed.\n      var originalProperties = this._realizeGroupTransformOnObject(instance),\n          object = this.callSuper('_toObject', instance, methodName, propertiesToInclude);\n      //Undo the damage we did by changing all of its properties\n      this._unwindGroupTransformOnObject(instance, originalProperties);\n      return object;\n    },\n\n    /**\n     * Realises an object's group transformation on it\n     * @private\n     * @param {fabric.Object} [instance] the object to transform (gets mutated)\n     * @returns the original values of instance which were changed\n     */\n    _realizeGroupTransformOnObject: function(instance) {\n      if (instance.group && instance.group === this.getActiveGroup()) {\n        //Copy all the positionally relevant properties across now\n        var originalValues = {},\n            layoutProps = ['angle', 'flipX', 'flipY', 'left', 'scaleX', 'scaleY', 'skewX', 'skewY', 'top'];\n        layoutProps.forEach(function(prop) {\n          originalValues[prop] = instance[prop];\n        });\n        this.getActiveGroup().realizeTransform(instance);\n        return originalValues;\n      }\n      else {\n        return null;\n      }\n    },\n\n    /**\n     * Restores the changed properties of instance\n     * @private\n     * @param {fabric.Object} [instance] the object to un-transform (gets mutated)\n     * @param {Object} [originalValues] the original values of instance, as returned by _realizeGroupTransformOnObject\n     */\n    _unwindGroupTransformOnObject: function(instance, originalValues) {\n      if (originalValues) {\n        instance.set(originalValues);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _setSVGObject: function(markup, instance, reviver) {\n      var originalProperties;\n      //If the object is in a selection group, simulate what would happen to that\n      //object when the group is deselected\n      originalProperties = this._realizeGroupTransformOnObject(instance);\n      this.callSuper('_setSVGObject', markup, instance, reviver);\n      this._unwindGroupTransformOnObject(instance, originalProperties);\n    },\n  });\n\n  // copying static properties manually to work around Opera's bug,\n  // where \"prototype\" property is enumerable and overrides existing prototype\n  for (var prop in fabric.StaticCanvas) {\n    if (prop !== 'prototype') {\n      fabric.Canvas[prop] = fabric.StaticCanvas[prop];\n    }\n  }\n\n  if (fabric.isTouchSupported) {\n    /** @ignore */\n    fabric.Canvas.prototype._setCursorFromEvent = function() { };\n  }\n\n  /**\n   * @ignore\n   * @class fabric.Element\n   * @alias fabric.Canvas\n   * @deprecated Use {@link fabric.Canvas} instead.\n   * @constructor\n   */\n  fabric.Element = fabric.Canvas;\n})();\n\n\n(function() {\n\n  var cursorOffset = {\n        mt: 0, // n\n        tr: 1, // ne\n        mr: 2, // e\n        br: 3, // se\n        mb: 4, // s\n        bl: 5, // sw\n        ml: 6, // w\n        tl: 7 // nw\n      },\n      addListener = fabric.util.addListener,\n      removeListener = fabric.util.removeListener,\n      RIGHT_CLICK = 3, MIDDLE_CLICK = 2, LEFT_CLICK = 1;\n\n  function checkClick(e, value) {\n    return 'which' in e ? e.which === value : e.button === value - 1;\n  }\n\n  fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {\n\n    /**\n     * Map of cursor style values for each of the object controls\n     * @private\n     */\n    cursorMap: [\n      'n-resize',\n      'ne-resize',\n      'e-resize',\n      'se-resize',\n      's-resize',\n      'sw-resize',\n      'w-resize',\n      'nw-resize'\n    ],\n\n    /**\n     * Adds mouse listeners to canvas\n     * @private\n     */\n    _initEventListeners: function () {\n      // in case we initialized the class twice. This should not happen normally\n      // but in some kind of applications where the canvas element may be changed\n      // this is a workaround to having double listeners.\n      this.removeListeners();\n      this._bindEvents();\n\n      addListener(fabric.window, 'resize', this._onResize);\n\n      // mouse events\n      addListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);\n      addListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);\n      addListener(this.upperCanvasEl, 'mouseout', this._onMouseOut);\n      addListener(this.upperCanvasEl, 'mouseenter', this._onMouseEnter);\n      addListener(this.upperCanvasEl, 'wheel', this._onMouseWheel);\n      addListener(this.upperCanvasEl, 'contextmenu', this._onContextMenu);\n\n      // touch events\n      addListener(this.upperCanvasEl, 'touchstart', this._onMouseDown, { passive: false });\n      addListener(this.upperCanvasEl, 'touchmove', this._onMouseMove, { passive: false });\n\n      if (typeof eventjs !== 'undefined' && 'add' in eventjs) {\n        eventjs.add(this.upperCanvasEl, 'gesture', this._onGesture);\n        eventjs.add(this.upperCanvasEl, 'drag', this._onDrag);\n        eventjs.add(this.upperCanvasEl, 'orientation', this._onOrientationChange);\n        eventjs.add(this.upperCanvasEl, 'shake', this._onShake);\n        eventjs.add(this.upperCanvasEl, 'longpress', this._onLongPress);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _bindEvents: function() {\n      if (this.eventsBinded) {\n        // for any reason we pass here twice we do not want to bind events twice.\n        return;\n      }\n      this._onMouseDown = this._onMouseDown.bind(this);\n      this._onMouseMove = this._onMouseMove.bind(this);\n      this._onMouseUp = this._onMouseUp.bind(this);\n      this._onResize = this._onResize.bind(this);\n      this._onGesture = this._onGesture.bind(this);\n      this._onDrag = this._onDrag.bind(this);\n      this._onShake = this._onShake.bind(this);\n      this._onLongPress = this._onLongPress.bind(this);\n      this._onOrientationChange = this._onOrientationChange.bind(this);\n      this._onMouseWheel = this._onMouseWheel.bind(this);\n      this._onMouseOut = this._onMouseOut.bind(this);\n      this._onMouseEnter = this._onMouseEnter.bind(this);\n      this._onContextMenu = this._onContextMenu.bind(this);\n      this.eventsBinded = true;\n    },\n\n    /**\n     * Removes all event listeners\n     */\n    removeListeners: function() {\n      removeListener(fabric.window, 'resize', this._onResize);\n\n      removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);\n      removeListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);\n      removeListener(this.upperCanvasEl, 'mouseout', this._onMouseOut);\n      removeListener(this.upperCanvasEl, 'mouseenter', this._onMouseEnter);\n      removeListener(this.upperCanvasEl, 'wheel', this._onMouseWheel);\n      removeListener(this.upperCanvasEl, 'contextmenu', this._onContextMenu);\n\n      removeListener(this.upperCanvasEl, 'touchstart', this._onMouseDown);\n      removeListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);\n\n      if (typeof eventjs !== 'undefined' && 'remove' in eventjs) {\n        eventjs.remove(this.upperCanvasEl, 'gesture', this._onGesture);\n        eventjs.remove(this.upperCanvasEl, 'drag', this._onDrag);\n        eventjs.remove(this.upperCanvasEl, 'orientation', this._onOrientationChange);\n        eventjs.remove(this.upperCanvasEl, 'shake', this._onShake);\n        eventjs.remove(this.upperCanvasEl, 'longpress', this._onLongPress);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js gesture\n     * @param {Event} [self] Inner Event object\n     */\n    _onGesture: function(e, self) {\n      this.__onTransformGesture && this.__onTransformGesture(e, self);\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js drag\n     * @param {Event} [self] Inner Event object\n     */\n    _onDrag: function(e, self) {\n      this.__onDrag && this.__onDrag(e, self);\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on wheel event\n     */\n    _onMouseWheel: function(e) {\n      this.__onMouseWheel(e);\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onMouseOut: function(e) {\n      var target = this._hoveredTarget;\n      this.fire('mouse:out', { target: target, e: e });\n      this._hoveredTarget = null;\n      target && target.fire('mouseout', { e: e });\n      if (this._iTextInstances) {\n        this._iTextInstances.forEach(function(obj) {\n          if (obj.isEditing) {\n            obj.hiddenTextarea.focus();\n          }\n        });\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mouseenter\n     */\n    _onMouseEnter: function(e) {\n      if (!this.findTarget(e)) {\n        this.fire('mouse:over', { target: null, e: e });\n        this._hoveredTarget = null;\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js orientation change\n     * @param {Event} [self] Inner Event object\n     */\n    _onOrientationChange: function(e, self) {\n      this.__onOrientationChange && this.__onOrientationChange(e, self);\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js shake\n     * @param {Event} [self] Inner Event object\n     */\n    _onShake: function(e, self) {\n      this.__onShake && this.__onShake(e, self);\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js shake\n     * @param {Event} [self] Inner Event object\n     */\n    _onLongPress: function(e, self) {\n      this.__onLongPress && this.__onLongPress(e, self);\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onContextMenu: function (e) {\n      if (this.stopContextMenu) {\n        e.stopPropagation();\n        e.preventDefault();\n      }\n      return false;\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onMouseDown: function (e) {\n      this.__onMouseDown(e);\n\n      addListener(fabric.document, 'touchend', this._onMouseUp, { passive: false });\n      addListener(fabric.document, 'touchmove', this._onMouseMove, { passive: false });\n\n      removeListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);\n      removeListener(this.upperCanvasEl, 'touchmove', this._onMouseMove);\n\n      if (e.type === 'touchstart') {\n        // Unbind mousedown to prevent double triggers from touch devices\n        removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);\n      }\n      else {\n        addListener(fabric.document, 'mouseup', this._onMouseUp);\n        addListener(fabric.document, 'mousemove', this._onMouseMove);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mouseup\n     */\n    _onMouseUp: function (e) {\n      this.__onMouseUp(e);\n\n      removeListener(fabric.document, 'mouseup', this._onMouseUp);\n      removeListener(fabric.document, 'touchend', this._onMouseUp);\n\n      removeListener(fabric.document, 'mousemove', this._onMouseMove);\n      removeListener(fabric.document, 'touchmove', this._onMouseMove);\n\n      addListener(this.upperCanvasEl, 'mousemove', this._onMouseMove);\n      addListener(this.upperCanvasEl, 'touchmove', this._onMouseMove, { passive: false });\n\n      if (e.type === 'touchend') {\n        // Wait 400ms before rebinding mousedown to prevent double triggers\n        // from touch devices\n        var _this = this;\n        setTimeout(function() {\n          addListener(_this.upperCanvasEl, 'mousedown', _this._onMouseDown);\n        }, 400);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousemove\n     */\n    _onMouseMove: function (e) {\n      !this.allowTouchScrolling && e.preventDefault && e.preventDefault();\n      this.__onMouseMove(e);\n    },\n\n    /**\n     * @private\n     */\n    _onResize: function () {\n      this.calcOffset();\n    },\n\n    /**\n     * Decides whether the canvas should be redrawn in mouseup and mousedown events.\n     * @private\n     * @param {Object} target\n     * @param {Object} pointer\n     */\n    _shouldRender: function(target, pointer) {\n      var activeObject = this.getActiveGroup() || this.getActiveObject();\n\n      if (activeObject && activeObject.isEditing && target === activeObject) {\n        // if we mouse up/down over a editing textbox a cursor change,\n        // there is no need to re render\n        return false;\n      }\n      return !!(\n        (target && (\n          target.isMoving ||\n          target !== activeObject))\n        ||\n        (!target && !!activeObject)\n        ||\n        (!target && !activeObject && !this._groupSelector)\n        ||\n        (pointer &&\n          this._previousPointer &&\n          this.selection && (\n          pointer.x !== this._previousPointer.x ||\n          pointer.y !== this._previousPointer.y))\n      );\n    },\n\n    /**\n     * Method that defines the actions when mouse is released on canvas.\n     * The method resets the currentTransform parameters, store the image corner\n     * position in the image object and render the canvas on top.\n     * @private\n     * @param {Event} e Event object fired on mouseup\n     */\n    __onMouseUp: function (e) {\n\n      var target;\n      // if right/middle click just fire events and return\n      // target undefined will make the _handleEvent search the target\n      if (checkClick(e, RIGHT_CLICK)) {\n        if (this.fireRightClick) {\n          this._handleEvent(e, 'up', target, RIGHT_CLICK);\n        }\n        return;\n      }\n\n      if (checkClick(e, MIDDLE_CLICK)) {\n        if (this.fireMiddleClick) {\n          this._handleEvent(e, 'up', target, MIDDLE_CLICK);\n        }\n        return;\n      }\n\n      if (this.isDrawingMode && this._isCurrentlyDrawing) {\n        this._onMouseUpInDrawingMode(e);\n        return;\n      }\n\n      var searchTarget = true, transform = this._currentTransform,\n          groupSelector = this._groupSelector,\n          isClick = (!groupSelector || (groupSelector.left === 0 && groupSelector.top === 0));\n\n      if (transform) {\n        this._finalizeCurrentTransform(e);\n        searchTarget = !transform.actionPerformed;\n      }\n\n      target = searchTarget ? this.findTarget(e, true) : transform.target;\n\n      var shouldRender = this._shouldRender(target, this.getPointer(e));\n\n      if (target || !isClick) {\n        this._maybeGroupObjects(e);\n      }\n      else {\n        // those are done by default on mouse up\n        // by _maybeGroupObjects, we are skipping it in case of no target find\n        this._groupSelector = null;\n        this._currentTransform = null;\n      }\n\n      if (target) {\n        target.isMoving = false;\n      }\n      this._setCursorFromEvent(e, target);\n      this._handleEvent(e, 'up', target ? target : null, LEFT_CLICK, isClick);\n      target && (target.__corner = 0);\n      shouldRender && this.renderAll();\n    },\n\n    /**\n     * @private\n     * Handle event firing for target and subtargets\n     * @param {Event} e event from mouse\n     * @param {String} eventType event to fire (up, down or move)\n     * @param {fabric.Object} targetObj receiving event\n     * @param {Number} [button] button used in the event 1 = left, 2 = middle, 3 = right\n     * @param {Boolean} isClick for left button only, indicates that the mouse up happened without move.\n     */\n    _handleEvent: function(e, eventType, targetObj, button, isClick) {\n      var target = typeof targetObj === 'undefined' ? this.findTarget(e) : targetObj,\n          targets = this.targets || [],\n          options = {\n            e: e,\n            target: target,\n            subTargets: targets,\n            button: button || LEFT_CLICK,\n            isClick: isClick || false\n          };\n      this.fire('mouse:' + eventType, options);\n      target && target.fire('mouse' + eventType, options);\n      for (var i = 0; i < targets.length; i++) {\n        targets[i].fire('mouse' + eventType, options);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e send the mouse event that generate the finalize down, so it can be used in the event\n     */\n    _finalizeCurrentTransform: function(e) {\n\n      var transform = this._currentTransform,\n          target = transform.target;\n\n      if (target._scaling) {\n        target._scaling = false;\n      }\n\n      target.setCoords();\n      this._restoreOriginXY(target);\n\n      if (transform.actionPerformed || (this.stateful && target.hasStateChanged())) {\n        this.fire('object:modified', { target: target, e: e });\n        target.fire('modified', { e: e });\n      }\n    },\n\n    /**\n     * @private\n     * @param {Object} target Object to restore\n     */\n    _restoreOriginXY: function(target) {\n      if (this._previousOriginX && this._previousOriginY) {\n\n        var originPoint = target.translateToOriginPoint(\n          target.getCenterPoint(),\n          this._previousOriginX,\n          this._previousOriginY);\n\n        target.originX = this._previousOriginX;\n        target.originY = this._previousOriginY;\n\n        target.left = originPoint.x;\n        target.top = originPoint.y;\n\n        this._previousOriginX = null;\n        this._previousOriginY = null;\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onMouseDownInDrawingMode: function(e) {\n      this._isCurrentlyDrawing = true;\n      this.discardActiveObject(e).renderAll();\n      if (this.clipTo) {\n        fabric.util.clipContext(this, this.contextTop);\n      }\n      var pointer = this.getPointer(e);\n      this.freeDrawingBrush.onMouseDown(pointer);\n      this._handleEvent(e, 'down');\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousemove\n     */\n    _onMouseMoveInDrawingMode: function(e) {\n      if (this._isCurrentlyDrawing) {\n        var pointer = this.getPointer(e);\n        this.freeDrawingBrush.onMouseMove(pointer);\n      }\n      this.setCursor(this.freeDrawingCursor);\n      this._handleEvent(e, 'move');\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mouseup\n     */\n    _onMouseUpInDrawingMode: function(e) {\n      this._isCurrentlyDrawing = false;\n      if (this.clipTo) {\n        this.contextTop.restore();\n      }\n      this.freeDrawingBrush.onMouseUp();\n      this._handleEvent(e, 'up');\n    },\n\n    /**\n     * Method that defines the actions when mouse is clicked on canvas.\n     * The method inits the currentTransform parameters and renders all the\n     * canvas so the current image can be placed on the top canvas and the rest\n     * in on the container one.\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    __onMouseDown: function (e) {\n\n      var target = this.findTarget(e);\n\n      // if right click just fire events\n      if (checkClick(e, RIGHT_CLICK)) {\n        if (this.fireRightClick) {\n          this._handleEvent(e, 'down', target ? target : null, RIGHT_CLICK);\n        }\n        return;\n      }\n\n      if (checkClick(e, MIDDLE_CLICK)) {\n        if (this.fireMiddleClick) {\n          this._handleEvent(e, 'down', target ? target : null, MIDDLE_CLICK);\n        }\n        return;\n      }\n\n      if (this.isDrawingMode) {\n        this._onMouseDownInDrawingMode(e);\n        return;\n      }\n\n      // ignore if some object is being transformed at this moment\n      if (this._currentTransform) {\n        return;\n      }\n\n      // save pointer for check in __onMouseUp event\n      var pointer = this.getPointer(e, true);\n      this._previousPointer = pointer;\n\n      var shouldRender = this._shouldRender(target, pointer),\n          shouldGroup = this._shouldGroup(e, target);\n\n      if (this._shouldClearSelection(e, target)) {\n        this.deactivateAllWithDispatch(e);\n      }\n      else if (shouldGroup) {\n        this._handleGrouping(e, target);\n        target = this.getActiveGroup();\n      }\n\n      if (this.selection && (!target || (!target.selectable && !target.isEditing))) {\n        this._groupSelector = {\n          ex: pointer.x,\n          ey: pointer.y,\n          top: 0,\n          left: 0\n        };\n      }\n\n      if (target) {\n        if (target.selectable && (target.__corner || !shouldGroup)) {\n          this._beforeTransform(e, target);\n          this._setupCurrentTransform(e, target);\n        }\n        var activeObject = this.getActiveObject();\n        if (target !== this.getActiveGroup() && target !== activeObject) {\n          this.deactivateAll();\n          if (target.selectable) {\n            activeObject && activeObject.fire('deselected', { e: e });\n            this.setActiveObject(target, e);\n          }\n        }\n      }\n      this._handleEvent(e, 'down', target ? target : null);\n      // we must renderAll so that we update the visuals\n      shouldRender && this.renderAll();\n    },\n\n    /**\n     * @private\n     */\n    _beforeTransform: function(e, target) {\n      this.stateful && target.saveState();\n\n      // determine if it's a drag or rotate case\n      if (target._findTargetCorner(this.getPointer(e))) {\n        this.onBeforeScaleRotate(target);\n      }\n\n    },\n\n    /**\n     * @private\n     * @param {Object} target Object for that origin is set to center\n     */\n    _setOriginToCenter: function(target) {\n      this._previousOriginX = this._currentTransform.target.originX;\n      this._previousOriginY = this._currentTransform.target.originY;\n\n      var center = target.getCenterPoint();\n\n      target.originX = 'center';\n      target.originY = 'center';\n\n      target.left = center.x;\n      target.top = center.y;\n\n      this._currentTransform.left = target.left;\n      this._currentTransform.top = target.top;\n    },\n\n    /**\n     * @private\n     * @param {Object} target Object for that center is set to origin\n     */\n    _setCenterToOrigin: function(target) {\n      var originPoint = target.translateToOriginPoint(\n        target.getCenterPoint(),\n        this._previousOriginX,\n        this._previousOriginY);\n\n      target.originX = this._previousOriginX;\n      target.originY = this._previousOriginY;\n\n      target.left = originPoint.x;\n      target.top = originPoint.y;\n\n      this._previousOriginX = null;\n      this._previousOriginY = null;\n    },\n\n    /**\n     * Method that defines the actions when mouse is hovering the canvas.\n     * The currentTransform parameter will definde whether the user is rotating/scaling/translating\n     * an image or neither of them (only hovering). A group selection is also possible and would cancel\n     * all any other type of action.\n     * In case of an image transformation only the top canvas will be rendered.\n     * @private\n     * @param {Event} e Event object fired on mousemove\n     */\n    __onMouseMove: function (e) {\n\n      var target, pointer;\n\n      if (this.isDrawingMode) {\n        this._onMouseMoveInDrawingMode(e);\n        return;\n      }\n      if (typeof e.touches !== 'undefined' && e.touches.length > 1) {\n        return;\n      }\n\n      var groupSelector = this._groupSelector;\n\n      // We initially clicked in an empty area, so we draw a box for multiple selection\n      if (groupSelector) {\n        pointer = this.getPointer(e, true);\n\n        groupSelector.left = pointer.x - groupSelector.ex;\n        groupSelector.top = pointer.y - groupSelector.ey;\n\n        this.renderTop();\n      }\n      else if (!this._currentTransform) {\n        target = this.findTarget(e);\n        this._setCursorFromEvent(e, target);\n      }\n      else {\n        this._transformObject(e);\n      }\n      this._handleEvent(e, 'move', target ? target : null);\n    },\n\n    /**\n     * Method that defines actions when an Event Mouse Wheel\n     * @param {Event} e Event object fired on mouseup\n     */\n    __onMouseWheel: function(e) {\n      this._handleEvent(e, 'wheel');\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event fired on mousemove\n     */\n    _transformObject: function(e) {\n      var pointer = this.getPointer(e),\n          transform = this._currentTransform;\n\n      transform.reset = false;\n      transform.target.isMoving = true;\n      transform.shiftKey = e.shiftKey;\n      transform.altKey = e[this.centeredKey];\n\n      this._beforeScaleTransform(e, transform);\n      this._performTransformAction(e, transform, pointer);\n\n      transform.actionPerformed && this.renderAll();\n    },\n\n    /**\n     * @private\n     */\n    _performTransformAction: function(e, transform, pointer) {\n      var x = pointer.x,\n          y = pointer.y,\n          target = transform.target,\n          action = transform.action,\n          actionPerformed = false;\n\n      if (action === 'rotate') {\n        (actionPerformed = this._rotateObject(x, y)) && this._fire('rotating', target, e);\n      }\n      else if (action === 'scale') {\n        (actionPerformed = this._onScale(e, transform, x, y)) && this._fire('scaling', target, e);\n      }\n      else if (action === 'scaleX') {\n        (actionPerformed = this._scaleObject(x, y, 'x')) && this._fire('scaling', target, e);\n      }\n      else if (action === 'scaleY') {\n        (actionPerformed = this._scaleObject(x, y, 'y')) && this._fire('scaling', target, e);\n      }\n      else if (action === 'skewX') {\n        (actionPerformed = this._skewObject(x, y, 'x')) && this._fire('skewing', target, e);\n      }\n      else if (action === 'skewY') {\n        (actionPerformed = this._skewObject(x, y, 'y')) && this._fire('skewing', target, e);\n      }\n      else {\n        actionPerformed = this._translateObject(x, y);\n        if (actionPerformed) {\n          this._fire('moving', target, e);\n          this.setCursor(target.moveCursor || this.moveCursor);\n        }\n      }\n      transform.actionPerformed = transform.actionPerformed || actionPerformed;\n    },\n\n    /**\n     * @private\n     */\n    _fire: function(eventName, target, e) {\n      this.fire('object:' + eventName, { target: target, e: e });\n      target.fire(eventName, { e: e });\n    },\n\n    /**\n     * @private\n     */\n    _beforeScaleTransform: function(e, transform) {\n      if (transform.action === 'scale' || transform.action === 'scaleX' || transform.action === 'scaleY') {\n        var centerTransform = this._shouldCenterTransform(transform.target);\n\n        // Switch from a normal resize to center-based\n        if ((centerTransform && (transform.originX !== 'center' || transform.originY !== 'center')) ||\n           // Switch from center-based resize to normal one\n           (!centerTransform && transform.originX === 'center' && transform.originY === 'center')\n        ) {\n          this._resetCurrentTransform();\n          transform.reset = true;\n        }\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @param {Object} transform current tranform\n     * @param {Number} x mouse position x from origin\n     * @param {Number} y mouse poistion y from origin\n     * @return {Boolean} true if the scaling occurred\n     */\n    _onScale: function(e, transform, x, y) {\n      if ((e[this.uniScaleKey] || this.uniScaleTransform) && !transform.target.get('lockUniScaling')) {\n        transform.currentAction = 'scale';\n        return this._scaleObject(x, y);\n      }\n      else {\n        // Switch from a normal resize to proportional\n        if (!transform.reset && transform.currentAction === 'scale') {\n          this._resetCurrentTransform();\n        }\n\n        transform.currentAction = 'scaleEqually';\n        return this._scaleObject(x, y, 'equally');\n      }\n    },\n\n    /**\n     * Sets the cursor depending on where the canvas is being hovered.\n     * Note: very buggy in Opera\n     * @param {Event} e Event object\n     * @param {Object} target Object that the mouse is hovering, if so.\n     */\n    _setCursorFromEvent: function (e, target) {\n      if (!target) {\n        this.setCursor(this.defaultCursor);\n        return false;\n      }\n\n      var hoverCursor = target.hoverCursor || this.hoverCursor,\n          activeGroup = this.getActiveGroup(),\n          // only show proper corner when group selection is not active\n          corner = target._findTargetCorner\n                    && (!activeGroup || !activeGroup.contains(target))\n                    && target._findTargetCorner(this.getPointer(e, true));\n\n      if (!corner) {\n        this.setCursor(hoverCursor);\n      }\n      else {\n        this._setCornerCursor(corner, target, e);\n      }\n      //actually unclear why it should return something\n      //is never evaluated\n      return true;\n    },\n\n    /**\n     * @private\n     */\n    _setCornerCursor: function(corner, target, e) {\n      if (corner in cursorOffset) {\n        this.setCursor(this._getRotatedCornerCursor(corner, target, e));\n      }\n      else if (corner === 'mtr' && target.hasRotatingPoint) {\n        this.setCursor(this.rotationCursor);\n      }\n      else {\n        this.setCursor(this.defaultCursor);\n        return false;\n      }\n    },\n\n    /**\n     * @private\n     */\n    _getRotatedCornerCursor: function(corner, target, e) {\n      var n = Math.round((target.getAngle() % 360) / 45);\n\n      if (n < 0) {\n        n += 8; // full circle ahead\n      }\n      n += cursorOffset[corner];\n      if (e[this.altActionKey] && cursorOffset[corner] % 2 === 0) {\n        //if we are holding shift and we are on a mx corner...\n        n += 2;\n      }\n      // normalize n to be from 0 to 7\n      n %= 8;\n\n      return this.cursorMap[n];\n    }\n  });\n})();\n\n\n(function() {\n\n  var min = Math.min,\n      max = Math.max;\n\n  fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @param {fabric.Object} target\n     * @return {Boolean}\n     */\n    _shouldGroup: function(e, target) {\n      var activeObject = this.getActiveObject();\n      return e[this.selectionKey] && target && target.selectable &&\n            (this.getActiveGroup() || (activeObject && activeObject !== target))\n            && this.selection;\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @param {fabric.Object} target\n     */\n    _handleGrouping: function (e, target) {\n      var activeGroup = this.getActiveGroup();\n\n      if (target === activeGroup) {\n        // if it's a group, find target again, using activeGroup objects\n        target = this.findTarget(e, true);\n        // if even object is not found, bail out\n        if (!target) {\n          return;\n        }\n      }\n      if (activeGroup) {\n        this._updateActiveGroup(target, e);\n      }\n      else {\n        this._createActiveGroup(target, e);\n      }\n\n      if (this._activeGroup) {\n        this._activeGroup.saveCoords();\n      }\n    },\n\n    /**\n     * @private\n     */\n    _updateActiveGroup: function(target, e) {\n      var activeGroup = this.getActiveGroup();\n\n      if (activeGroup.contains(target)) {\n\n        activeGroup.removeWithUpdate(target);\n        target.set('active', false);\n\n        if (activeGroup.size() === 1) {\n          // remove group alltogether if after removal it only contains 1 object\n          this.discardActiveGroup(e);\n          // activate last remaining object\n          this.setActiveObject(activeGroup.item(0), e);\n          return;\n        }\n      }\n      else {\n        activeGroup.addWithUpdate(target);\n      }\n      this.fire('selection:created', { target: activeGroup, e: e });\n      activeGroup.set('active', true);\n    },\n\n    /**\n     * @private\n     */\n    _createActiveGroup: function(target, e) {\n\n      if (this._activeObject && target !== this._activeObject) {\n\n        var group = this._createGroup(target);\n        group.addWithUpdate();\n\n        this.setActiveGroup(group, e);\n        this._activeObject = null;\n\n        this.fire('selection:created', { target: group, e: e });\n      }\n\n      target.set('active', true);\n    },\n\n    /**\n     * @private\n     * @param {Object} target\n     */\n    _createGroup: function(target) {\n\n      var objects = this.getObjects(),\n          isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target),\n          groupObjects = isActiveLower\n            ? [this._activeObject, target]\n            : [target, this._activeObject];\n      this._activeObject.isEditing && this._activeObject.exitEditing();\n      return new fabric.Group(groupObjects, {\n        canvas: this\n      });\n    },\n\n    /**\n     * @private\n     * @param {Event} e mouse event\n     */\n    _groupSelectedObjects: function (e) {\n\n      var group = this._collectObjects();\n\n      // do not create group for 1 element only\n      if (group.length === 1) {\n        this.setActiveObject(group[0], e);\n      }\n      else if (group.length > 1) {\n        group = new fabric.Group(group.reverse(), {\n          canvas: this\n        });\n        group.addWithUpdate();\n        this.setActiveGroup(group, e);\n        group.saveCoords();\n        this.fire('selection:created', { target: group, e: e });\n        this.renderAll();\n      }\n    },\n\n    /**\n     * @private\n     */\n    _collectObjects: function() {\n      var group = [],\n          currentObject,\n          x1 = this._groupSelector.ex,\n          y1 = this._groupSelector.ey,\n          x2 = x1 + this._groupSelector.left,\n          y2 = y1 + this._groupSelector.top,\n          selectionX1Y1 = new fabric.Point(min(x1, x2), min(y1, y2)),\n          selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2)),\n          isClick = x1 === x2 && y1 === y2;\n\n      for (var i = this._objects.length; i--; ) {\n        currentObject = this._objects[i];\n\n        if (!currentObject || !currentObject.selectable || !currentObject.visible) {\n          continue;\n        }\n\n        if (currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2) ||\n            currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2) ||\n            currentObject.containsPoint(selectionX1Y1) ||\n            currentObject.containsPoint(selectionX2Y2)\n        ) {\n          currentObject.set('active', true);\n          group.push(currentObject);\n\n          // only add one object if it's a click\n          if (isClick) {\n            break;\n          }\n        }\n      }\n\n      return group;\n    },\n\n    /**\n     * @private\n     */\n    _maybeGroupObjects: function(e) {\n      if (this.selection && this._groupSelector) {\n        this._groupSelectedObjects(e);\n      }\n\n      var activeGroup = this.getActiveGroup();\n      if (activeGroup) {\n        activeGroup.setObjectsCoords().setCoords();\n        activeGroup.isMoving = false;\n        this.setCursor(this.defaultCursor);\n      }\n\n      // clear selection and current transformation\n      this._groupSelector = null;\n      this._currentTransform = null;\n    }\n  });\n\n})();\n\n\n(function () {\n\n  var supportQuality = fabric.StaticCanvas.supports('toDataURLWithQuality');\n\n  fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n    /**\n     * Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately\n     * @param {Object} [options] Options object\n     * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\n     * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\n     * @param {Number} [options.multiplier=1] Multiplier to scale by\n     * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n     * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n     * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n     * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n     * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format\n     * @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo}\n     * @example <caption>Generate jpeg dataURL with lower quality</caption>\n     * var dataURL = canvas.toDataURL({\n     *   format: 'jpeg',\n     *   quality: 0.8\n     * });\n     * @example <caption>Generate cropped png dataURL (clipping of canvas)</caption>\n     * var dataURL = canvas.toDataURL({\n     *   format: 'png',\n     *   left: 100,\n     *   top: 100,\n     *   width: 200,\n     *   height: 200\n     * });\n     * @example <caption>Generate double scaled png dataURL</caption>\n     * var dataURL = canvas.toDataURL({\n     *   format: 'png',\n     *   multiplier: 2\n     * });\n     */\n    toDataURL: function (options) {\n      options || (options = { });\n\n      var format = options.format || 'png',\n          quality = options.quality || 1,\n          multiplier = options.multiplier || 1,\n          cropping = {\n            left: options.left || 0,\n            top: options.top || 0,\n            width: options.width || 0,\n            height: options.height || 0,\n          };\n      return this.__toDataURLWithMultiplier(format, quality, cropping, multiplier);\n    },\n\n    /**\n     * @private\n     */\n    __toDataURLWithMultiplier: function(format, quality, cropping, multiplier) {\n\n      var origWidth = this.getWidth(),\n          origHeight = this.getHeight(),\n          scaledWidth = (cropping.width || this.getWidth()) * multiplier,\n          scaledHeight = (cropping.height || this.getHeight()) * multiplier,\n          zoom = this.getZoom(),\n          newZoom = zoom * multiplier,\n          vp = this.viewportTransform,\n          translateX = (vp[4] - cropping.left) * multiplier,\n          translateY = (vp[5] - cropping.top) * multiplier,\n          newVp = [newZoom, 0, 0, newZoom, translateX, translateY],\n          originalInteractive = this.interactive;\n\n      this.viewportTransform = newVp;\n      // setting interactive to false avoid exporting controls\n      this.interactive && (this.interactive = false);\n      if (origWidth !== scaledWidth || origHeight !== scaledHeight) {\n        // this.setDimensions is going to renderAll also;\n        this.setDimensions({ width: scaledWidth, height: scaledHeight }, { backstoreOnly: true });\n      }\n      else {\n        this.renderAll();\n      }\n      var data = this.__toDataURL(format, quality, cropping);\n      originalInteractive && (this.interactive = originalInteractive);\n      this.viewportTransform = vp;\n      //setDimensions with no option object is taking care of:\n      //this.width, this.height, this.renderAll()\n      this.setDimensions({ width: origWidth, height: origHeight }, { backstoreOnly: true });\n      return data;\n    },\n\n    /**\n     * @private\n     */\n    __toDataURL: function(format, quality) {\n\n      var canvasEl = this.contextContainer.canvas;\n      // to avoid common confusion https://github.com/kangax/fabric.js/issues/806\n      if (format === 'jpg') {\n        format = 'jpeg';\n      }\n\n      var data = supportQuality\n                ? canvasEl.toDataURL('image/' + format, quality)\n                : canvasEl.toDataURL('image/' + format);\n\n      return data;\n    },\n\n    /**\n     * Exports canvas element to a dataurl image (allowing to change image size via multiplier).\n     * @deprecated since 1.0.13\n     * @param {String} format (png|jpeg)\n     * @param {Number} multiplier\n     * @param {Number} quality (0..1)\n     * @return {String}\n     */\n    toDataURLWithMultiplier: function (format, multiplier, quality) {\n      return this.toDataURL({\n        format: format,\n        multiplier: multiplier,\n        quality: quality\n      });\n    },\n  });\n\n})();\n\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n  /**\n   * Populates canvas with data from the specified dataless JSON.\n   * JSON format must conform to the one of {@link fabric.Canvas#toDatalessJSON}\n   * @deprecated since 1.2.2\n   * @param {String|Object} json JSON string or object\n   * @param {Function} callback Callback, invoked when json is parsed\n   *                            and corresponding objects (e.g: {@link fabric.Image})\n   *                            are initialized\n   * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created.\n   * @return {fabric.Canvas} instance\n   * @chainable\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#deserialization}\n   */\n  loadFromDatalessJSON: function (json, callback, reviver) {\n    return this.loadFromJSON(json, callback, reviver);\n  },\n\n  /**\n   * Populates canvas with data from the specified JSON.\n   * JSON format must conform to the one of {@link fabric.Canvas#toJSON}\n   * @param {String|Object} json JSON string or object\n   * @param {Function} callback Callback, invoked when json is parsed\n   *                            and corresponding objects (e.g: {@link fabric.Image})\n   *                            are initialized\n   * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created.\n   * @return {fabric.Canvas} instance\n   * @chainable\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#deserialization}\n   * @see {@link http://jsfiddle.net/fabricjs/fmgXt/|jsFiddle demo}\n   * @example <caption>loadFromJSON</caption>\n   * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas));\n   * @example <caption>loadFromJSON with reviver</caption>\n   * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(o, object) {\n   *   // `o` = json object\n   *   // `object` = fabric.Object instance\n   *   // ... do some stuff ...\n   * });\n   */\n  loadFromJSON: function (json, callback, reviver) {\n    if (!json) {\n      return;\n    }\n\n    // serialize if it wasn't already\n    var serialized = (typeof json === 'string')\n      ? JSON.parse(json)\n      : fabric.util.object.clone(json);\n\n    var _this = this,\n        renderOnAddRemove = this.renderOnAddRemove;\n    this.renderOnAddRemove = false;\n\n    this._enlivenObjects(serialized.objects, function (enlivenedObjects) {\n      _this.clear();\n      _this._setBgOverlay(serialized, function () {\n        enlivenedObjects.forEach(function(obj, index) {\n          // we splice the array just in case some custom classes restored from JSON\n          // will add more object to canvas at canvas init.\n          _this.insertAt(obj, index);\n        });\n        _this.renderOnAddRemove = renderOnAddRemove;\n        // remove parts i cannot set as options\n        delete serialized.objects;\n        delete serialized.backgroundImage;\n        delete serialized.overlayImage;\n        delete serialized.background;\n        delete serialized.overlay;\n        // this._initOptions does too many things to just\n        // call it. Normally loading an Object from JSON\n        // create the Object instance. Here the Canvas is\n        // already an instance and we are just loading things over it\n        _this._setOptions(serialized);\n        _this.renderAll();\n        callback && callback();\n      });\n    }, reviver);\n    return this;\n  },\n\n  /**\n   * @private\n   * @param {Object} serialized Object with background and overlay information\n   * @param {Function} callback Invoked after all background and overlay images/patterns loaded\n   */\n  _setBgOverlay: function(serialized, callback) {\n    var loaded = {\n      backgroundColor: false,\n      overlayColor: false,\n      backgroundImage: false,\n      overlayImage: false\n    };\n\n    if (!serialized.backgroundImage && !serialized.overlayImage && !serialized.background && !serialized.overlay) {\n      callback && callback();\n      return;\n    }\n\n    var cbIfLoaded = function () {\n      if (loaded.backgroundImage && loaded.overlayImage && loaded.backgroundColor && loaded.overlayColor) {\n        callback && callback();\n      }\n    };\n\n    this.__setBgOverlay('backgroundImage', serialized.backgroundImage, loaded, cbIfLoaded);\n    this.__setBgOverlay('overlayImage', serialized.overlayImage, loaded, cbIfLoaded);\n    this.__setBgOverlay('backgroundColor', serialized.background, loaded, cbIfLoaded);\n    this.__setBgOverlay('overlayColor', serialized.overlay, loaded, cbIfLoaded);\n  },\n\n  /**\n   * @private\n   * @param {String} property Property to set (backgroundImage, overlayImage, backgroundColor, overlayColor)\n   * @param {(Object|String)} value Value to set\n   * @param {Object} loaded Set loaded property to true if property is set\n   * @param {Object} callback Callback function to invoke after property is set\n   */\n  __setBgOverlay: function(property, value, loaded, callback) {\n    var _this = this;\n\n    if (!value) {\n      loaded[property] = true;\n      callback && callback();\n      return;\n    }\n\n    if (property === 'backgroundImage' || property === 'overlayImage') {\n      fabric.util.enlivenObjects([value], function(enlivedObject){\n        _this[property] = enlivedObject[0];\n        loaded[property] = true;\n        callback && callback();\n      });\n    }\n    else {\n      this['set' + fabric.util.string.capitalize(property, true)](value, function() {\n        loaded[property] = true;\n        callback && callback();\n      });\n    }\n  },\n\n  /**\n   * @private\n   * @param {Array} objects\n   * @param {Function} callback\n   * @param {Function} [reviver]\n   */\n  _enlivenObjects: function (objects, callback, reviver) {\n    if (!objects || objects.length === 0) {\n      callback && callback([]);\n      return;\n    }\n\n    fabric.util.enlivenObjects(objects, function(enlivenedObjects) {\n      callback && callback(enlivenedObjects);\n    }, null, reviver);\n  },\n\n  /**\n   * @private\n   * @param {String} format\n   * @param {Function} callback\n   */\n  _toDataURL: function (format, callback) {\n    this.clone(function (clone) {\n      callback(clone.toDataURL(format));\n    });\n  },\n\n  /**\n   * @private\n   * @param {String} format\n   * @param {Number} multiplier\n   * @param {Function} callback\n   */\n  _toDataURLWithMultiplier: function (format, multiplier, callback) {\n    this.clone(function (clone) {\n      callback(clone.toDataURLWithMultiplier(format, multiplier));\n    });\n  },\n\n  /**\n   * Clones canvas instance\n   * @param {Object} [callback] Receives cloned instance as a first argument\n   * @param {Array} [properties] Array of properties to include in the cloned canvas and children\n   */\n  clone: function (callback, properties) {\n    var data = JSON.stringify(this.toJSON(properties));\n    this.cloneWithoutData(function(clone) {\n      clone.loadFromJSON(data, function() {\n        callback && callback(clone);\n      });\n    });\n  },\n\n  /**\n   * Clones canvas instance without cloning existing data.\n   * This essentially copies canvas dimensions, clipping properties, etc.\n   * but leaves data empty (so that you can populate it with your own)\n   * @param {Object} [callback] Receives cloned instance as a first argument\n   */\n  cloneWithoutData: function(callback) {\n    var el = fabric.document.createElement('canvas');\n\n    el.width = this.getWidth();\n    el.height = this.getHeight();\n\n    var clone = new fabric.Canvas(el);\n    clone.clipTo = this.clipTo;\n    if (this.backgroundImage) {\n      clone.setBackgroundImage(this.backgroundImage.src, function() {\n        clone.renderAll();\n        callback && callback(clone);\n      });\n      clone.backgroundImageOpacity = this.backgroundImageOpacity;\n      clone.backgroundImageStretch = this.backgroundImageStretch;\n    }\n    else {\n      callback && callback(clone);\n    }\n  }\n});\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      clone = fabric.util.object.clone,\n      toFixed = fabric.util.toFixed,\n      capitalize = fabric.util.string.capitalize,\n      degreesToRadians = fabric.util.degreesToRadians,\n      supportsLineDash = fabric.StaticCanvas.supports('setLineDash'),\n      objectCaching = !fabric.isLikelyNode,\n      ALIASING_LIMIT = 2;\n\n  if (fabric.Object) {\n    return;\n  }\n\n  /**\n   * Root object class from which all 2d shape classes inherit from\n   * @class fabric.Object\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#objects}\n   * @see {@link fabric.Object#initialize} for constructor definition\n   *\n   * @fires added\n   * @fires removed\n   *\n   * @fires selected\n   * @fires deselected\n   * @fires modified\n   * @fires rotating\n   * @fires scaling\n   * @fires moving\n   * @fires skewing\n   *\n   * @fires mousedown\n   * @fires mouseup\n   * @fires mouseover\n   * @fires mouseout\n   * @fires mousewheel\n   */\n  fabric.Object = fabric.util.createClass(fabric.CommonMethods, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Retrieves object's {@link fabric.Object#clipTo|clipping function}\n     * @method getClipTo\n     * @memberOf fabric.Object.prototype\n     * @return {Function}\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#clipTo|clipping function}\n     * @method setClipTo\n     * @memberOf fabric.Object.prototype\n     * @param {Function} clipTo Clipping function\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#transformMatrix|transformMatrix}\n     * @method getTransformMatrix\n     * @memberOf fabric.Object.prototype\n     * @return {Array} transformMatrix\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#transformMatrix|transformMatrix}\n     * @method setTransformMatrix\n     * @memberOf fabric.Object.prototype\n     * @param {Array} transformMatrix\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#visible|visible} state\n     * @method getVisible\n     * @memberOf fabric.Object.prototype\n     * @return {Boolean} True if visible\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#visible|visible} state\n     * @method setVisible\n     * @memberOf fabric.Object.prototype\n     * @param {Boolean} value visible value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#shadow|shadow}\n     * @method getShadow\n     * @memberOf fabric.Object.prototype\n     * @return {Object} Shadow instance\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#stroke|stroke}\n     * @method getStroke\n     * @memberOf fabric.Object.prototype\n     * @return {String} stroke value\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#stroke|stroke}\n     * @method setStroke\n     * @memberOf fabric.Object.prototype\n     * @param {String} value stroke value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#strokeWidth|strokeWidth}\n     * @method getStrokeWidth\n     * @memberOf fabric.Object.prototype\n     * @return {Number} strokeWidth value\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#strokeWidth|strokeWidth}\n     * @method setStrokeWidth\n     * @memberOf fabric.Object.prototype\n     * @param {Number} value strokeWidth value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#originX|originX}\n     * @method getOriginX\n     * @memberOf fabric.Object.prototype\n     * @return {String} originX value\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#originX|originX}\n     * @method setOriginX\n     * @memberOf fabric.Object.prototype\n     * @param {String} value originX value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#originY|originY}\n     * @method getOriginY\n     * @memberOf fabric.Object.prototype\n     * @return {String} originY value\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#originY|originY}\n     * @method setOriginY\n     * @memberOf fabric.Object.prototype\n     * @param {String} value originY value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#fill|fill}\n     * @method getFill\n     * @memberOf fabric.Object.prototype\n     * @return {String} Fill value\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#fill|fill}\n     * @method setFill\n     * @memberOf fabric.Object.prototype\n     * @param {String} value Fill value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#opacity|opacity}\n     * @method getOpacity\n     * @memberOf fabric.Object.prototype\n     * @return {Number} Opacity value (0-1)\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#opacity|opacity}\n     * @method setOpacity\n     * @memberOf fabric.Object.prototype\n     * @param {Number} value Opacity value (0-1)\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#angle|angle} (in degrees)\n     * @method getAngle\n     * @memberOf fabric.Object.prototype\n     * @return {Number}\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#top|top position}\n     * @method getTop\n     * @memberOf fabric.Object.prototype\n     * @return {Number} Top value (in pixels)\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#top|top position}\n     * @method setTop\n     * @memberOf fabric.Object.prototype\n     * @param {Number} value Top value (in pixels)\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#left|left position}\n     * @method getLeft\n     * @memberOf fabric.Object.prototype\n     * @return {Number} Left value (in pixels)\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#left|left position}\n     * @method setLeft\n     * @memberOf fabric.Object.prototype\n     * @param {Number} value Left value (in pixels)\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#scaleX|scaleX} value\n     * @method getScaleX\n     * @memberOf fabric.Object.prototype\n     * @return {Number} scaleX value\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#scaleX|scaleX} value\n     * @method setScaleX\n     * @memberOf fabric.Object.prototype\n     * @param {Number} value scaleX value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#scaleY|scaleY} value\n     * @method getScaleY\n     * @memberOf fabric.Object.prototype\n     * @return {Number} scaleY value\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#scaleY|scaleY} value\n     * @method setScaleY\n     * @memberOf fabric.Object.prototype\n     * @param {Number} value scaleY value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#flipX|flipX} value\n     * @method getFlipX\n     * @memberOf fabric.Object.prototype\n     * @return {Boolean} flipX value\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#flipX|flipX} value\n     * @method setFlipX\n     * @memberOf fabric.Object.prototype\n     * @param {Boolean} value flipX value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's {@link fabric.Object#flipY|flipY} value\n     * @method getFlipY\n     * @memberOf fabric.Object.prototype\n     * @return {Boolean} flipY value\n     */\n\n    /**\n     * Sets object's {@link fabric.Object#flipY|flipY} value\n     * @method setFlipY\n     * @memberOf fabric.Object.prototype\n     * @param {Boolean} value flipY value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n\n    /**\n     * Type of an object (rect, circle, path, etc.).\n     * Note that this property is meant to be read-only and not meant to be modified.\n     * If you modify, certain parts of Fabric (such as JSON loading) won't work correctly.\n     * @type String\n     * @default\n     */\n    type:                     'object',\n\n    /**\n     * Horizontal origin of transformation of an object (one of \"left\", \"right\", \"center\")\n     * See http://jsfiddle.net/1ow02gea/40/ on how originX/originY affect objects in groups\n     * @type String\n     * @default\n     */\n    originX:                  'left',\n\n    /**\n     * Vertical origin of transformation of an object (one of \"top\", \"bottom\", \"center\")\n     * See http://jsfiddle.net/1ow02gea/40/ on how originX/originY affect objects in groups\n     * @type String\n     * @default\n     */\n    originY:                  'top',\n\n    /**\n     * Top position of an object. Note that by default it's relative to object top. You can change this by setting originY={top/center/bottom}\n     * @type Number\n     * @default\n     */\n    top:                      0,\n\n    /**\n     * Left position of an object. Note that by default it's relative to object left. You can change this by setting originX={left/center/right}\n     * @type Number\n     * @default\n     */\n    left:                     0,\n\n    /**\n     * Object width\n     * @type Number\n     * @default\n     */\n    width:                    0,\n\n    /**\n     * Object height\n     * @type Number\n     * @default\n     */\n    height:                   0,\n\n    /**\n     * Object scale factor (horizontal)\n     * @type Number\n     * @default\n     */\n    scaleX:                   1,\n\n    /**\n     * Object scale factor (vertical)\n     * @type Number\n     * @default\n     */\n    scaleY:                   1,\n\n    /**\n     * When true, an object is rendered as flipped horizontally\n     * @type Boolean\n     * @default\n     */\n    flipX:                    false,\n\n    /**\n     * When true, an object is rendered as flipped vertically\n     * @type Boolean\n     * @default\n     */\n    flipY:                    false,\n\n    /**\n     * Opacity of an object\n     * @type Number\n     * @default\n     */\n    opacity:                  1,\n\n    /**\n     * Angle of rotation of an object (in degrees)\n     * @type Number\n     * @default\n     */\n    angle:                    0,\n\n    /**\n     * Angle of skew on x axes of an object (in degrees)\n     * @type Number\n     * @default\n     */\n    skewX:                    0,\n\n    /**\n     * Angle of skew on y axes of an object (in degrees)\n     * @type Number\n     * @default\n     */\n    skewY:                    0,\n\n    /**\n     * Size of object's controlling corners (in pixels)\n     * @type Number\n     * @default\n     */\n    cornerSize:               13,\n\n    /**\n     * When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill)\n     * @type Boolean\n     * @default\n     */\n    transparentCorners:       true,\n\n    /**\n     * Default cursor value used when hovering over this object on canvas\n     * @type String\n     * @default\n     */\n    hoverCursor:              null,\n\n    /**\n     * Default cursor value used when moving this object on canvas\n     * @type String\n     * @default\n     */\n    moveCursor:               null,\n\n    /**\n     * Padding between object and its controlling borders (in pixels)\n     * @type Number\n     * @default\n     */\n    padding:                  0,\n\n    /**\n     * Color of controlling borders of an object (when it's active)\n     * @type String\n     * @default\n     */\n    borderColor:              'rgba(102,153,255,0.75)',\n\n    /**\n     * Array specifying dash pattern of an object's borders (hasBorder must be true)\n     * @since 1.6.2\n     * @type Array\n     */\n    borderDashArray:          null,\n\n    /**\n     * Color of controlling corners of an object (when it's active)\n     * @type String\n     * @default\n     */\n    cornerColor:              'rgba(102,153,255,0.5)',\n\n    /**\n     * Color of controlling corners of an object (when it's active and transparentCorners false)\n     * @since 1.6.2\n     * @type String\n     * @default\n     */\n    cornerStrokeColor:        null,\n\n    /**\n     * Specify style of control, 'rect' or 'circle'\n     * @since 1.6.2\n     * @type String\n     */\n    cornerStyle:          'rect',\n\n    /**\n     * Array specifying dash pattern of an object's control (hasBorder must be true)\n     * @since 1.6.2\n     * @type Array\n     */\n    cornerDashArray:          null,\n\n    /**\n     * When true, this object will use center point as the origin of transformation\n     * when being scaled via the controls.\n     * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n     * @since 1.3.4\n     * @type Boolean\n     * @default\n     */\n    centeredScaling:          false,\n\n    /**\n     * When true, this object will use center point as the origin of transformation\n     * when being rotated via the controls.\n     * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n     * @since 1.3.4\n     * @type Boolean\n     * @default\n     */\n    centeredRotation:         true,\n\n    /**\n     * Color of object's fill\n     * @type String\n     * @default\n     */\n    fill:                     'rgb(0,0,0)',\n\n    /**\n     * Fill rule used to fill an object\n     * accepted values are nonzero, evenodd\n     * <b>Backwards incompatibility note:</b> This property was used for setting globalCompositeOperation until v1.4.12 (use `fabric.Object#globalCompositeOperation` instead)\n     * @type String\n     * @default\n     */\n    fillRule:                 'nonzero',\n\n    /**\n     * Composite rule used for canvas globalCompositeOperation\n     * @type String\n     * @default\n     */\n    globalCompositeOperation: 'source-over',\n\n    /**\n     * Background color of an object.\n     * @type String\n     * @default\n     */\n    backgroundColor:          '',\n\n    /**\n     * Selection Background color of an object. colored layer behind the object when it is active.\n     * does not mix good with globalCompositeOperation methods.\n     * @type String\n     * @default\n     */\n    selectionBackgroundColor:          '',\n\n    /**\n     * When defined, an object is rendered via stroke and this property specifies its color\n     * @type String\n     * @default\n     */\n    stroke:                   null,\n\n    /**\n     * Width of a stroke used to render this object\n     * @type Number\n     * @default\n     */\n    strokeWidth:              1,\n\n    /**\n     * Array specifying dash pattern of an object's stroke (stroke must be defined)\n     * @type Array\n     */\n    strokeDashArray:          null,\n\n    /**\n     * Line endings style of an object's stroke (one of \"butt\", \"round\", \"square\")\n     * @type String\n     * @default\n     */\n    strokeLineCap:            'butt',\n\n    /**\n     * Corner style of an object's stroke (one of \"bevil\", \"round\", \"miter\")\n     * @type String\n     * @default\n     */\n    strokeLineJoin:           'miter',\n\n    /**\n     * Maximum miter length (used for strokeLineJoin = \"miter\") of an object's stroke\n     * @type Number\n     * @default\n     */\n    strokeMiterLimit:         10,\n\n    /**\n     * Shadow object representing shadow of this shape\n     * @type fabric.Shadow\n     * @default\n     */\n    shadow:                   null,\n\n    /**\n     * Opacity of object's controlling borders when object is active and moving\n     * @type Number\n     * @default\n     */\n    borderOpacityWhenMoving:  0.4,\n\n    /**\n     * Scale factor of object's controlling borders\n     * @type Number\n     * @default\n     */\n    borderScaleFactor:        1,\n\n    /**\n     * Transform matrix (similar to SVG's transform matrix)\n     * @type Array\n     */\n    transformMatrix:          null,\n\n    /**\n     * Minimum allowed scale value of an object\n     * @type Number\n     * @default\n     */\n    minScaleLimit:            0.01,\n\n    /**\n     * When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection).\n     * But events still fire on it.\n     * @type Boolean\n     * @default\n     */\n    selectable:               true,\n\n    /**\n     * When set to `false`, an object can not be a target of events. All events propagate through it. Introduced in v1.3.4\n     * @type Boolean\n     * @default\n     */\n    evented:                  true,\n\n    /**\n     * When set to `false`, an object is not rendered on canvas\n     * @type Boolean\n     * @default\n     */\n    visible:                  true,\n\n    /**\n     * When set to `false`, object's controls are not displayed and can not be used to manipulate object\n     * @type Boolean\n     * @default\n     */\n    hasControls:              true,\n\n    /**\n     * When set to `false`, object's controlling borders are not rendered\n     * @type Boolean\n     * @default\n     */\n    hasBorders:               true,\n\n    /**\n     * When set to `false`, object's controlling rotating point will not be visible or selectable\n     * @type Boolean\n     * @default\n     */\n    hasRotatingPoint:         true,\n\n    /**\n     * Offset for object's controlling rotating point (when enabled via `hasRotatingPoint`)\n     * @type Number\n     * @default\n     */\n    rotatingPointOffset:      40,\n\n    /**\n     * When set to `true`, objects are \"found\" on canvas on per-pixel basis rather than according to bounding box\n     * @type Boolean\n     * @default\n     */\n    perPixelTargetFind:       false,\n\n    /**\n     * When `false`, default object's values are not included in its serialization\n     * @type Boolean\n     * @default\n     */\n    includeDefaultValues:     true,\n\n    /**\n     * Function that determines clipping of an object (context is passed as a first argument)\n     * Note that context origin is at the object's center point (not left/top corner)\n     * @type Function\n     */\n    clipTo:                   null,\n\n    /**\n     * When `true`, object horizontal movement is locked\n     * @type Boolean\n     * @default\n     */\n    lockMovementX:            false,\n\n    /**\n     * When `true`, object vertical movement is locked\n     * @type Boolean\n     * @default\n     */\n    lockMovementY:            false,\n\n    /**\n     * When `true`, object rotation is locked\n     * @type Boolean\n     * @default\n     */\n    lockRotation:             false,\n\n    /**\n     * When `true`, object horizontal scaling is locked\n     * @type Boolean\n     * @default\n     */\n    lockScalingX:             false,\n\n    /**\n     * When `true`, object vertical scaling is locked\n     * @type Boolean\n     * @default\n     */\n    lockScalingY:             false,\n\n    /**\n     * When `true`, object non-uniform scaling is locked\n     * @type Boolean\n     * @default\n     */\n    lockUniScaling:           false,\n\n    /**\n     * When `true`, object horizontal skewing is locked\n     * @type Boolean\n     * @default\n     */\n    lockSkewingX:             false,\n\n    /**\n     * When `true`, object vertical skewing is locked\n     * @type Boolean\n     * @default\n     */\n    lockSkewingY:             false,\n\n    /**\n     * When `true`, object cannot be flipped by scaling into negative values\n     * @type Boolean\n     * @default\n     */\n    lockScalingFlip:          false,\n\n    /**\n     * When `true`, object is not exported in SVG or OBJECT/JSON\n     * since 1.6.3\n     * @type Boolean\n     * @default\n     */\n    excludeFromExport:        false,\n\n    /**\n     * When `true`, object is cached on an additional canvas.\n     * default to true\n     * since 1.7.0\n     * @type Boolean\n     * @default true\n     */\n    objectCaching:            objectCaching,\n\n    /**\n     * When `true`, object properties are checked for cache invalidation. In some particular\n     * situation you may want this to be disabled ( spray brush, very big pathgroups, groups)\n     * or if your application does not allow you to modify properties for groups child you want\n     * to disable it for groups.\n     * default to false\n     * since 1.7.0\n     * @type Boolean\n     * @default false\n     */\n    statefullCache:            false,\n\n    /**\n     * When `true`, cache does not get updated during scaling. The picture will get blocky if scaled\n     * too much and will be redrawn with correct details at the end of scaling.\n     * this setting is performance and application dependant.\n     * default to true\n     * since 1.7.0\n     * @type Boolean\n     * @default true\n     */\n    noScaleCache:              true,\n\n    /**\n     * When set to `true`, object's cache will be rerendered next render call.\n     * since 1.7.0\n     * @type Boolean\n     * @default true\n     */\n    dirty:                true,\n\n    /**\n     * List of properties to consider when checking if state\n     * of an object is changed (fabric.Object#hasStateChanged)\n     * as well as for history (undo/redo) purposes\n     * @type Array\n     */\n    stateProperties: (\n      'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' +\n      'stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit ' +\n      'angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor ' +\n      'skewX skewY fillRule'\n    ).split(' '),\n\n    /**\n     * List of properties to consider when checking if cache needs refresh\n     * @type Array\n     */\n    cacheProperties: (\n      'fill stroke strokeWidth strokeDashArray width height' +\n      ' strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor'\n    ).split(' '),\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     */\n    initialize: function(options) {\n      options = options || { };\n      if (options) {\n        this.setOptions(options);\n      }\n    },\n\n    /**\n     * Create a the canvas used to keep the cached copy of the object\n     * @private\n     */\n    _createCacheCanvas: function() {\n      this._cacheProperties = {};\n      this._cacheCanvas = fabric.document.createElement('canvas');\n      this._cacheContext = this._cacheCanvas.getContext('2d');\n      this._updateCacheCanvas();\n    },\n\n    /**\n     * Limit the cache dimensions so that X * Y do not cross fabric.perfLimitSizeTotal\n     * and each side do not cross fabric.cacheSideLimit\n     * those numbers are configurable so that you can get as much detail as you want\n     * making bargain with performances.\n     * @param {Object} dims\n     * @param {Object} dims.width width of canvas\n     * @param {Object} dims.height height of canvas\n     * @param {Object} dims.zoomX zoomX zoom value to unscale the canvas before drawing cache\n     * @param {Object} dims.zoomY zoomY zoom value to unscale the canvas before drawing cache\n     * @return {Object}.width width of canvas\n     * @return {Object}.height height of canvas\n     * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n     * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n     */\n    _limitCacheSize: function(dims) {\n      var perfLimitSizeTotal = fabric.perfLimitSizeTotal,\n          width = dims.width, height = dims.height,\n          max = fabric.maxCacheSideLimit, min = fabric.minCacheSideLimit;\n      if (width <= max && height <= max && width * height <= perfLimitSizeTotal) {\n        if (width < min) {\n          dims.width = min;\n        }\n        if (height < min) {\n          dims.height = min;\n        }\n        return dims;\n      }\n      var ar = width / height, limitedDims = fabric.util.limitDimsByArea(ar, perfLimitSizeTotal),\n          capValue = fabric.util.capValue,\n          x = capValue(min, limitedDims.x, max),\n          y = capValue(min, limitedDims.y, max);\n      if (width > x) {\n        dims.zoomX /= width / x;\n        dims.width = x;\n        dims.capped = true;\n      }\n      if (height > y) {\n        dims.zoomY /= height / y;\n        dims.height = y;\n        dims.capped = true;\n      }\n      return dims;\n    },\n\n    /**\n     * Return the dimension and the zoom level needed to create a cache canvas\n     * big enough to host the object to be cached.\n     * @private\n     * @param {Object} dim.x width of object to be cached\n     * @param {Object} dim.y height of object to be cached\n     * @return {Object}.width width of canvas\n     * @return {Object}.height height of canvas\n     * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n     * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n     */\n    _getCacheCanvasDimensions: function() {\n      var zoom = this.canvas && this.canvas.getZoom() || 1,\n          objectScale = this.getObjectScaling(),\n          retina = this.canvas && this.canvas._isRetinaScaling() ? fabric.devicePixelRatio : 1,\n          dim = this._getNonTransformedDimensions(),\n          zoomX = objectScale.scaleX * zoom * retina,\n          zoomY = objectScale.scaleY * zoom * retina,\n          width = dim.x * zoomX,\n          height = dim.y * zoomY;\n      return {\n        width: width + ALIASING_LIMIT,\n        height: height + ALIASING_LIMIT,\n        zoomX: zoomX,\n        zoomY: zoomY,\n        x: dim.x,\n        y: dim.y\n      };\n    },\n\n    /**\n     * Update width and height of the canvas for cache\n     * returns true or false if canvas needed resize.\n     * @private\n     * @return {Boolean} true if the canvas has been resized\n     */\n    _updateCacheCanvas: function() {\n      if (this.noScaleCache && this.canvas && this.canvas._currentTransform) {\n        var target = this.canvas._currentTransform.target,\n            action = this.canvas._currentTransform.action;\n        if (this === target && action.slice && action.slice(0, 5) === 'scale') {\n          return false;\n        }\n      }\n      var canvas = this._cacheCanvas,\n          dims = this._limitCacheSize(this._getCacheCanvasDimensions()),\n          minCacheSize = fabric.minCacheSideLimit,\n          width = dims.width, height = dims.height, drawingWidth, drawingHeight,\n          zoomX = dims.zoomX, zoomY = dims.zoomY,\n          dimensionsChanged = width !== this.cacheWidth || height !== this.cacheHeight,\n          zoomChanged = this.zoomX !== zoomX || this.zoomY !== zoomY,\n          shouldRedraw = dimensionsChanged || zoomChanged,\n          additionalWidth = 0, additionalHeight = 0, shouldResizeCanvas = false;\n      if (dimensionsChanged) {\n        var canvasWidth = this._cacheCanvas.width,\n            canvasHeight = this._cacheCanvas.height,\n            sizeGrowing = width > canvasWidth || height > canvasHeight,\n            sizeShrinking = (width < canvasWidth * 0.9 || height < canvasHeight * 0.9) &&\n              canvasWidth > minCacheSize && canvasHeight > minCacheSize;\n        shouldResizeCanvas = sizeGrowing || sizeShrinking;\n        if (sizeGrowing && !dims.capped && (width > minCacheSize || height > minCacheSize)) {\n          additionalWidth = width * 0.1;\n          additionalHeight = height * 0.1;\n        }\n      }\n      if (shouldRedraw) {\n        if (shouldResizeCanvas) {\n          canvas.width = Math.ceil(width + additionalWidth);\n          canvas.height = Math.ceil(height + additionalHeight);\n        }\n        else {\n          this._cacheContext.setTransform(1, 0, 0, 1, 0, 0);\n          this._cacheContext.clearRect(0, 0, canvas.width, canvas.height);\n        }\n        drawingWidth = dims.x * zoomX / 2;\n        drawingHeight = dims.y * zoomY / 2;\n        this.cacheTranslationX = Math.round(canvas.width / 2 - drawingWidth) + drawingWidth;\n        this.cacheTranslationY = Math.round(canvas.height / 2 - drawingHeight) + drawingHeight;\n        this.cacheWidth = width;\n        this.cacheHeight = height;\n        this._cacheContext.translate(this.cacheTranslationX, this.cacheTranslationY);\n        this._cacheContext.scale(zoomX, zoomY);\n        this.zoomX = zoomX;\n        this.zoomY = zoomY;\n        return true;\n      }\n      return false;\n    },\n\n    /**\n     * Sets object's properties from options\n     * @param {Object} [options] Options object\n     */\n    setOptions: function(options) {\n      this._setOptions(options);\n      this._initGradient(options.fill, 'fill');\n      this._initGradient(options.stroke, 'stroke');\n      this._initClipping(options);\n      this._initPattern(options.fill, 'fill');\n      this._initPattern(options.stroke, 'stroke');\n    },\n\n    /**\n     * Transforms context when rendering an object\n     * @param {CanvasRenderingContext2D} ctx Context\n     * @param {Boolean} fromLeft When true, context is transformed to object's top/left corner. This is used when rendering text on Node\n     */\n    transform: function(ctx, fromLeft) {\n      if (this.group && !this.group._transformDone && this.group === this.canvas._activeGroup) {\n        this.group.transform(ctx);\n      }\n      var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();\n      ctx.translate(center.x, center.y);\n      this.angle && ctx.rotate(degreesToRadians(this.angle));\n      ctx.scale(\n        this.scaleX * (this.flipX ? -1 : 1),\n        this.scaleY * (this.flipY ? -1 : 1)\n      );\n      this.skewX && ctx.transform(1, 0, Math.tan(degreesToRadians(this.skewX)), 1, 0, 0);\n      this.skewY && ctx.transform(1, Math.tan(degreesToRadians(this.skewY)), 0, 1, 0, 0);\n    },\n\n    /**\n     * Returns an object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n\n          object = {\n            type:                     this.type,\n            originX:                  this.originX,\n            originY:                  this.originY,\n            left:                     toFixed(this.left, NUM_FRACTION_DIGITS),\n            top:                      toFixed(this.top, NUM_FRACTION_DIGITS),\n            width:                    toFixed(this.width, NUM_FRACTION_DIGITS),\n            height:                   toFixed(this.height, NUM_FRACTION_DIGITS),\n            fill:                     (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill,\n            stroke:                   (this.stroke && this.stroke.toObject) ? this.stroke.toObject() : this.stroke,\n            strokeWidth:              toFixed(this.strokeWidth, NUM_FRACTION_DIGITS),\n            strokeDashArray:          this.strokeDashArray ? this.strokeDashArray.concat() : this.strokeDashArray,\n            strokeLineCap:            this.strokeLineCap,\n            strokeLineJoin:           this.strokeLineJoin,\n            strokeMiterLimit:         toFixed(this.strokeMiterLimit, NUM_FRACTION_DIGITS),\n            scaleX:                   toFixed(this.scaleX, NUM_FRACTION_DIGITS),\n            scaleY:                   toFixed(this.scaleY, NUM_FRACTION_DIGITS),\n            angle:                    toFixed(this.getAngle(), NUM_FRACTION_DIGITS),\n            flipX:                    this.flipX,\n            flipY:                    this.flipY,\n            opacity:                  toFixed(this.opacity, NUM_FRACTION_DIGITS),\n            shadow:                   (this.shadow && this.shadow.toObject) ? this.shadow.toObject() : this.shadow,\n            visible:                  this.visible,\n            clipTo:                   this.clipTo && String(this.clipTo),\n            backgroundColor:          this.backgroundColor,\n            fillRule:                 this.fillRule,\n            globalCompositeOperation: this.globalCompositeOperation,\n            transformMatrix:          this.transformMatrix ? this.transformMatrix.concat() : null,\n            skewX:                    toFixed(this.skewX, NUM_FRACTION_DIGITS),\n            skewY:                    toFixed(this.skewY, NUM_FRACTION_DIGITS)\n          };\n\n      fabric.util.populateWithProperties(this, object, propertiesToInclude);\n\n      if (!this.includeDefaultValues) {\n        object = this._removeDefaultValues(object);\n      }\n\n      return object;\n    },\n\n    /**\n     * Returns (dataless) object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toDatalessObject: function(propertiesToInclude) {\n      // will be overwritten by subclasses\n      return this.toObject(propertiesToInclude);\n    },\n\n    /**\n     * @private\n     * @param {Object} object\n     */\n    _removeDefaultValues: function(object) {\n      var prototype = fabric.util.getKlass(object.type).prototype,\n          stateProperties = prototype.stateProperties;\n      stateProperties.forEach(function(prop) {\n        if (object[prop] === prototype[prop]) {\n          delete object[prop];\n        }\n        var isArray = Object.prototype.toString.call(object[prop]) === '[object Array]' &&\n                      Object.prototype.toString.call(prototype[prop]) === '[object Array]';\n\n        // basically a check for [] === []\n        if (isArray && object[prop].length === 0 && prototype[prop].length === 0) {\n          delete object[prop];\n        }\n      });\n\n      return object;\n    },\n\n    /**\n     * Returns a string representation of an instance\n     * @return {String}\n     */\n    toString: function() {\n      return '#<fabric.' + capitalize(this.type) + '>';\n    },\n\n    /**\n     * Return the object scale factor counting also the group scaling\n     * @return {Object} object with scaleX and scaleY properties\n     */\n    getObjectScaling: function() {\n      var scaleX = this.scaleX, scaleY = this.scaleY;\n      if (this.group) {\n        var scaling = this.group.getObjectScaling();\n        scaleX *= scaling.scaleX;\n        scaleY *= scaling.scaleY;\n      }\n      return { scaleX: scaleX, scaleY: scaleY };\n    },\n\n    /**\n     * @private\n     * @param {String} key\n     * @param {*} value\n     * @return {fabric.Object} thisArg\n     */\n    _set: function(key, value) {\n      var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY'),\n          isChanged = this[key] !== value;\n\n      if (shouldConstrainValue) {\n        value = this._constrainScale(value);\n      }\n      if (key === 'scaleX' && value < 0) {\n        this.flipX = !this.flipX;\n        value *= -1;\n      }\n      else if (key === 'scaleY' && value < 0) {\n        this.flipY = !this.flipY;\n        value *= -1;\n      }\n      else if (key === 'shadow' && value && !(value instanceof fabric.Shadow)) {\n        value = new fabric.Shadow(value);\n      }\n      else if (key === 'dirty' && this.group) {\n        this.group.set('dirty', value);\n      }\n\n      this[key] = value;\n\n      if (isChanged && this.cacheProperties.indexOf(key) > -1) {\n        if (this.group) {\n          this.group.set('dirty', true);\n        }\n        this.dirty = true;\n      }\n\n      if (isChanged && this.group && this.stateProperties.indexOf(key) > -1) {\n        this.group.set('dirty', true);\n      }\n\n      if (key === 'width' || key === 'height') {\n        this.minScaleLimit = Math.min(0.1, 1 / Math.max(this.width, this.height));\n      }\n\n      return this;\n    },\n\n    /**\n     * This callback function is called by the parent group of an object every\n     * time a non-delegated property changes on the group. It is passed the key\n     * and value as parameters. Not adding in this function's signature to avoid\n     * Travis build error about unused variables.\n     */\n    setOnGroup: function() {\n      // implemented by sub-classes, as needed.\n    },\n\n    /**\n     * Sets sourcePath of an object\n     * @param {String} value Value to set sourcePath to\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setSourcePath: function(value) {\n      this.sourcePath = value;\n      return this;\n    },\n\n    /**\n     * Retrieves viewportTransform from Object's canvas if possible\n     * @method getViewportTransform\n     * @memberOf fabric.Object.prototype\n     * @return {Boolean}\n     */\n    getViewportTransform: function() {\n      if (this.canvas && this.canvas.viewportTransform) {\n        return this.canvas.viewportTransform;\n      }\n      return fabric.iMatrix.concat();\n    },\n\n    /*\n     * @private\n     * return if the object would be visible in rendering\n     * @memberOf fabric.Object.prototype\n     * @return {Boolean}\n     */\n    isNotVisible: function() {\n      return this.opacity === 0 || (this.width === 0 && this.height === 0) || !this.visible;\n    },\n\n    /**\n     * Renders an object on a specified context\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} [noTransform] When true, context is not transformed\n     */\n    render: function(ctx, noTransform) {\n      // do not render if width/height are zeros or object is not visible\n      if (this.isNotVisible()) {\n        return;\n      }\n      if (this.canvas && this.canvas.skipOffscreen && !this.group && !this.isOnScreen()) {\n        return;\n      }\n      ctx.save();\n      //setup fill rule for current object\n      this._setupCompositeOperation(ctx);\n      this.drawSelectionBackground(ctx);\n      if (!noTransform) {\n        this.transform(ctx);\n      }\n      this._setOpacity(ctx);\n      this._setShadow(ctx);\n      if (this.transformMatrix) {\n        ctx.transform.apply(ctx, this.transformMatrix);\n      }\n      this.clipTo && fabric.util.clipContext(this, ctx);\n      if (this.shouldCache(noTransform)) {\n        if (!this._cacheCanvas) {\n          this._createCacheCanvas();\n        }\n        if (this.isCacheDirty(noTransform)) {\n          this.statefullCache && this.saveState({ propertySet: 'cacheProperties' });\n          this.drawObject(this._cacheContext, noTransform);\n          this.dirty = false;\n        }\n        this.drawCacheOnCanvas(ctx);\n      }\n      else {\n        this._removeCacheCanvas();\n        this.dirty = false;\n        this.drawObject(ctx, noTransform);\n        if (noTransform && this.objectCaching && this.statefullCache) {\n          this.saveState({ propertySet: 'cacheProperties' });\n        }\n      }\n      this.clipTo && ctx.restore();\n      ctx.restore();\n    },\n\n    /**\n     * Remove cacheCanvas and its dimensions from the objects\n     */\n    _removeCacheCanvas: function() {\n      this._cacheCanvas = null;\n      this.cacheWidth = 0;\n      this.cacheHeight = 0;\n    },\n\n    /**\n     * When set to `true`, force the object to have its own cache, even if it is inside a group\n     * it may be needed when your object behave in a particular way on the cache and always needs\n     * its own isolated canvas to render correctly.\n     * This function is created to be subclassed by custom classes.\n     * since 1.7.12\n     * @type function\n     * @return false\n     */\n    needsItsOwnCache: function() {\n      return false;\n    },\n\n    /**\n     * Decide if the object should cache or not.\n     * objectCaching is a global flag, wins over everything\n     * needsItsOwnCache should be used when the object drawing method requires\n     * a cache step. None of the fabric classes requires it.\n     * Generally you do not cache objects in groups because the group outside is cached.\n     * @param {Boolean} noTransform if rendereing in pathGroup, caching is not supported at object level\n     * @return {Boolean}\n     */\n    shouldCache: function(noTransform) {\n      return !noTransform && this.objectCaching &&\n      (!this.group || this.needsItsOwnCache() || !this.group.isCaching());\n    },\n\n    /**\n     * Check if this object or a child object will cast a shadow\n     * used by Group.shouldCache to know if child has a shadow recursively\n     * @return {Boolean}\n     */\n    willDrawShadow: function() {\n      return !!this.shadow && (this.shadow.offsetX !== 0 || this.shadow.offsetY !== 0);\n    },\n\n    /**\n     * Execute the drawing operation for an object on a specified context\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} [noTransform] When true, context is not transformed\n     */\n    drawObject: function(ctx, noTransform) {\n      this._renderBackground(ctx);\n      this._setStrokeStyles(ctx);\n      this._setFillStyles(ctx);\n      this._render(ctx, noTransform);\n    },\n\n    /**\n     * Paint the cached copy of the object on the target context.\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    drawCacheOnCanvas: function(ctx) {\n      ctx.scale(1 / this.zoomX, 1 / this.zoomY);\n      ctx.drawImage(this._cacheCanvas, -this.cacheTranslationX, -this.cacheTranslationY);\n    },\n\n    /**\n     * Check if cache is dirty\n     * @param {Boolean} skipCanvas skip canvas checks because this object is painted\n     * on parent canvas.\n     */\n    isCacheDirty: function(skipCanvas) {\n      if (this.isNotVisible()) {\n        return false;\n      }\n      if (this._cacheCanvas && !skipCanvas && this._updateCacheCanvas()) {\n        // in this case the context is already cleared.\n        return true;\n      }\n      else {\n        if (this.dirty || (this.statefullCache && this.hasStateChanged('cacheProperties'))) {\n          if (this._cacheCanvas && !skipCanvas) {\n            var width = this.cacheWidth / this.zoomX;\n            var height = this.cacheHeight / this.zoomY;\n            this._cacheContext.clearRect(-width / 2, -height / 2, width, height);\n          }\n          return true;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Draws a background for the object big as its untrasformed dimensions\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderBackground: function(ctx) {\n      if (!this.backgroundColor) {\n        return;\n      }\n      var dim = this._getNonTransformedDimensions();\n      ctx.fillStyle = this.backgroundColor;\n\n      ctx.fillRect(\n        -dim.x / 2,\n        -dim.y / 2,\n        dim.x,\n        dim.y\n      );\n      // if there is background color no other shadows\n      // should be casted\n      this._removeShadow(ctx);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _setOpacity: function(ctx) {\n      ctx.globalAlpha *= this.opacity;\n    },\n\n    _setStrokeStyles: function(ctx) {\n      if (this.stroke) {\n        ctx.lineWidth = this.strokeWidth;\n        ctx.lineCap = this.strokeLineCap;\n        ctx.lineJoin = this.strokeLineJoin;\n        ctx.miterLimit = this.strokeMiterLimit;\n        ctx.strokeStyle = this.stroke.toLive\n          ? this.stroke.toLive(ctx, this)\n          : this.stroke;\n      }\n    },\n\n    _setFillStyles: function(ctx) {\n      if (this.fill) {\n        ctx.fillStyle = this.fill.toLive\n          ? this.fill.toLive(ctx, this)\n          : this.fill;\n      }\n    },\n\n    /**\n     * @private\n     * Sets line dash\n     * @param {CanvasRenderingContext2D} ctx Context to set the dash line on\n     * @param {Array} dashArray array representing dashes\n     * @param {Function} alternative function to call if browaser does not support lineDash\n     */\n    _setLineDash: function(ctx, dashArray, alternative) {\n      if (!dashArray) {\n        return;\n      }\n      // Spec requires the concatenation of two copies the dash list when the number of elements is odd\n      if (1 & dashArray.length) {\n        dashArray.push.apply(dashArray, dashArray);\n      }\n      if (supportsLineDash) {\n        ctx.setLineDash(dashArray);\n      }\n      else {\n        alternative && alternative(ctx);\n      }\n    },\n\n    /**\n     * Renders controls and borders for the object\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderControls: function(ctx) {\n      if (!this.active || (this.group && this.group !== this.canvas.getActiveGroup())) {\n        return;\n      }\n\n      var vpt = this.getViewportTransform(),\n          matrix = this.calcTransformMatrix(),\n          options;\n      matrix = fabric.util.multiplyTransformMatrices(vpt, matrix);\n      options = fabric.util.qrDecompose(matrix);\n\n      ctx.save();\n      ctx.translate(options.translateX, options.translateY);\n      ctx.lineWidth = 1 * this.borderScaleFactor;\n      if (!this.group) {\n        ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;\n      }\n      if (this.group && this.group === this.canvas.getActiveGroup()) {\n        ctx.rotate(degreesToRadians(options.angle));\n        this.drawBordersInGroup(ctx, options);\n      }\n      else {\n        ctx.rotate(degreesToRadians(this.angle));\n        this.drawBorders(ctx);\n      }\n      this.drawControls(ctx);\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _setShadow: function(ctx) {\n      if (!this.shadow) {\n        return;\n      }\n\n      var multX = (this.canvas && this.canvas.viewportTransform[0]) || 1,\n          multY = (this.canvas && this.canvas.viewportTransform[3]) || 1,\n          scaling = this.getObjectScaling();\n      if (this.canvas && this.canvas._isRetinaScaling()) {\n        multX *= fabric.devicePixelRatio;\n        multY *= fabric.devicePixelRatio;\n      }\n      ctx.shadowColor = this.shadow.color;\n      ctx.shadowBlur = this.shadow.blur * (multX + multY) * (scaling.scaleX + scaling.scaleY) / 4;\n      ctx.shadowOffsetX = this.shadow.offsetX * multX * scaling.scaleX;\n      ctx.shadowOffsetY = this.shadow.offsetY * multY * scaling.scaleY;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _removeShadow: function(ctx) {\n      if (!this.shadow) {\n        return;\n      }\n\n      ctx.shadowColor = '';\n      ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Object} filler fabric.Pattern or fabric.Gradient\n     */\n    _applyPatternGradientTransform: function(ctx, filler) {\n      if (!filler.toLive) {\n        return;\n      }\n      var transform = filler.gradientTransform || filler.patternTransform;\n      if (transform) {\n        ctx.transform.apply(ctx, transform);\n      }\n      var offsetX = -this.width / 2 + filler.offsetX || 0,\n          offsetY = -this.height / 2 + filler.offsetY || 0;\n      ctx.translate(offsetX, offsetY);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderFill: function(ctx) {\n      if (!this.fill) {\n        return;\n      }\n\n      ctx.save();\n      this._applyPatternGradientTransform(ctx, this.fill);\n      if (this.fillRule === 'evenodd') {\n        ctx.fill('evenodd');\n      }\n      else {\n        ctx.fill();\n      }\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderStroke: function(ctx) {\n      if (!this.stroke || this.strokeWidth === 0) {\n        return;\n      }\n\n      if (this.shadow && !this.shadow.affectStroke) {\n        this._removeShadow(ctx);\n      }\n\n      ctx.save();\n      this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke);\n      this._applyPatternGradientTransform(ctx, this.stroke);\n      ctx.stroke();\n      ctx.restore();\n    },\n\n    /**\n     * Clones an instance, some objects are async, so using callback method will work for every object.\n     * Using the direct return does not work for images and groups.\n     * @param {Function} callback Callback is invoked with a clone as a first argument\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {fabric.Object} clone of an instance\n     */\n    clone: function(callback, propertiesToInclude) {\n      if (this.constructor.fromObject) {\n        return this.constructor.fromObject(this.toObject(propertiesToInclude), callback);\n      }\n      return new fabric.Object(this.toObject(propertiesToInclude));\n    },\n\n    /**\n     * Creates an instance of fabric.Image out of an object\n     * @param {Function} callback callback, invoked with an instance as a first argument\n     * @param {Object} [options] for clone as image, passed to toDataURL\n     * @param {Boolean} [options.enableRetinaScaling] enable retina scaling for the cloned image\n     * @return {fabric.Object} thisArg\n     */\n    cloneAsImage: function(callback, options) {\n      var dataUrl = this.toDataURL(options);\n      fabric.util.loadImage(dataUrl, function(img) {\n        if (callback) {\n          callback(new fabric.Image(img));\n        }\n      });\n      return this;\n    },\n\n    /**\n     * Converts an object into a data-url-like string\n     * @param {Object} options Options object\n     * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\n     * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\n     * @param {Number} [options.multiplier=1] Multiplier to scale by\n     * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n     * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n     * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n     * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n     * @param {Boolean} [options.enableRetina] Enable retina scaling for clone image. Introduce in 1.6.4\n     * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format\n     */\n    toDataURL: function(options) {\n      options || (options = { });\n\n      var el = fabric.util.createCanvasElement(),\n          boundingRect = this.getBoundingRect();\n\n      el.width = boundingRect.width;\n      el.height = boundingRect.height;\n      fabric.util.wrapElement(el, 'div');\n      var canvas = new fabric.StaticCanvas(el, { enableRetinaScaling: options.enableRetinaScaling });\n      // to avoid common confusion https://github.com/kangax/fabric.js/issues/806\n      if (options.format === 'jpg') {\n        options.format = 'jpeg';\n      }\n\n      if (options.format === 'jpeg') {\n        canvas.backgroundColor = '#fff';\n      }\n\n      var origParams = {\n        active: this.get('active'),\n        left: this.getLeft(),\n        top: this.getTop()\n      };\n\n      this.set('active', false);\n      this.setPositionByOrigin(new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2), 'center', 'center');\n\n      var originalCanvas = this.canvas;\n      canvas.add(this);\n      var data = canvas.toDataURL(options);\n\n      this.set(origParams).setCoords();\n      this.canvas = originalCanvas;\n\n      canvas.dispose();\n      canvas = null;\n\n      return data;\n    },\n\n    /**\n     * Returns true if specified type is identical to the type of an instance\n     * @param {String} type Type to check against\n     * @return {Boolean}\n     */\n    isType: function(type) {\n      return this.type === type;\n    },\n\n    /**\n     * Returns complexity of an instance\n     * @return {Number} complexity of this instance (is 1 unless subclassed)\n     */\n    complexity: function() {\n      return 1;\n    },\n\n    /**\n     * Returns a JSON representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} JSON\n     */\n    toJSON: function(propertiesToInclude) {\n      // delegate, not alias\n      return this.toObject(propertiesToInclude);\n    },\n\n    /**\n     * Sets gradient (fill or stroke) of an object\n     * <b>Backwards incompatibility note:</b> This method was named \"setGradientFill\" until v1.1.0\n     * @param {String} property Property name 'stroke' or 'fill'\n     * @param {Object} [options] Options object\n     * @param {String} [options.type] Type of gradient 'radial' or 'linear'\n     * @param {Number} [options.x1=0] x-coordinate of start point\n     * @param {Number} [options.y1=0] y-coordinate of start point\n     * @param {Number} [options.x2=0] x-coordinate of end point\n     * @param {Number} [options.y2=0] y-coordinate of end point\n     * @param {Number} [options.r1=0] Radius of start point (only for radial gradients)\n     * @param {Number} [options.r2=0] Radius of end point (only for radial gradients)\n     * @param {Object} [options.colorStops] Color stops object eg. {0: 'ff0000', 1: '000000'}\n     * @param {Object} [options.gradientTransform] transforMatrix for gradient\n     * @return {fabric.Object} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/58y8b/|jsFiddle demo}\n     * @example <caption>Set linear gradient</caption>\n     * object.setGradient('fill', {\n     *   type: 'linear',\n     *   x1: -object.width / 2,\n     *   y1: 0,\n     *   x2: object.width / 2,\n     *   y2: 0,\n     *   colorStops: {\n     *     0: 'red',\n     *     0.5: '#005555',\n     *     1: 'rgba(0,0,255,0.5)'\n     *   }\n     * });\n     * canvas.renderAll();\n     * @example <caption>Set radial gradient</caption>\n     * object.setGradient('fill', {\n     *   type: 'radial',\n     *   x1: 0,\n     *   y1: 0,\n     *   x2: 0,\n     *   y2: 0,\n     *   r1: object.width / 2,\n     *   r2: 10,\n     *   colorStops: {\n     *     0: 'red',\n     *     0.5: '#005555',\n     *     1: 'rgba(0,0,255,0.5)'\n     *   }\n     * });\n     * canvas.renderAll();\n     */\n    setGradient: function(property, options) {\n      options || (options = { });\n\n      var gradient = { colorStops: [] };\n\n      gradient.type = options.type || (options.r1 || options.r2 ? 'radial' : 'linear');\n      gradient.coords = {\n        x1: options.x1,\n        y1: options.y1,\n        x2: options.x2,\n        y2: options.y2\n      };\n\n      if (options.r1 || options.r2) {\n        gradient.coords.r1 = options.r1;\n        gradient.coords.r2 = options.r2;\n      }\n\n      gradient.gradientTransform = options.gradientTransform;\n      fabric.Gradient.prototype.addColorStop.call(gradient, options.colorStops);\n\n      return this.set(property, fabric.Gradient.forObject(this, gradient));\n    },\n\n    /**\n     * Sets pattern fill of an object\n     * @param {Object} options Options object\n     * @param {(String|HTMLImageElement)} options.source Pattern source\n     * @param {String} [options.repeat=repeat] Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)\n     * @param {Number} [options.offsetX=0] Pattern horizontal offset from object's left/top corner\n     * @param {Number} [options.offsetY=0] Pattern vertical offset from object's left/top corner\n     * @return {fabric.Object} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/QT3pa/|jsFiddle demo}\n     * @example <caption>Set pattern</caption>\n     * fabric.util.loadImage('http://fabricjs.com/assets/escheresque_ste.png', function(img) {\n     *   object.setPatternFill({\n     *     source: img,\n     *     repeat: 'repeat'\n     *   });\n     *   canvas.renderAll();\n     * });\n     */\n    setPatternFill: function(options) {\n      return this.set('fill', new fabric.Pattern(options));\n    },\n\n    /**\n     * Sets {@link fabric.Object#shadow|shadow} of an object\n     * @param {Object|String} [options] Options object or string (e.g. \"2px 2px 10px rgba(0,0,0,0.2)\")\n     * @param {String} [options.color=rgb(0,0,0)] Shadow color\n     * @param {Number} [options.blur=0] Shadow blur\n     * @param {Number} [options.offsetX=0] Shadow horizontal offset\n     * @param {Number} [options.offsetY=0] Shadow vertical offset\n     * @return {fabric.Object} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/7gvJG/|jsFiddle demo}\n     * @example <caption>Set shadow with string notation</caption>\n     * object.setShadow('2px 2px 10px rgba(0,0,0,0.2)');\n     * canvas.renderAll();\n     * @example <caption>Set shadow with object notation</caption>\n     * object.setShadow({\n     *   color: 'red',\n     *   blur: 10,\n     *   offsetX: 20,\n     *   offsetY: 20\n     * });\n     * canvas.renderAll();\n     */\n    setShadow: function(options) {\n      return this.set('shadow', options ? new fabric.Shadow(options) : null);\n    },\n\n    /**\n     * Sets \"color\" of an instance (alias of `set('fill', &hellip;)`)\n     * @param {String} color Color value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setColor: function(color) {\n      this.set('fill', color);\n      return this;\n    },\n\n    /**\n     * Sets \"angle\" of an instance\n     * @param {Number} angle Angle value (in degrees)\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setAngle: function(angle) {\n      var shouldCenterOrigin = (this.originX !== 'center' || this.originY !== 'center') && this.centeredRotation;\n\n      if (shouldCenterOrigin) {\n        this._setOriginToCenter();\n      }\n\n      this.set('angle', angle);\n\n      if (shouldCenterOrigin) {\n        this._resetOrigin();\n      }\n\n      return this;\n    },\n\n    /**\n     * Centers object horizontally on canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    centerH: function () {\n      this.canvas && this.canvas.centerObjectH(this);\n      return this;\n    },\n\n    /**\n     * Centers object horizontally on current viewport of canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    viewportCenterH: function () {\n      this.canvas && this.canvas.viewportCenterObjectH(this);\n      return this;\n    },\n\n    /**\n     * Centers object vertically on canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    centerV: function () {\n      this.canvas && this.canvas.centerObjectV(this);\n      return this;\n    },\n\n    /**\n     * Centers object vertically on current viewport of canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    viewportCenterV: function () {\n      this.canvas && this.canvas.viewportCenterObjectV(this);\n      return this;\n    },\n\n    /**\n     * Centers object vertically and horizontally on canvas to which is was added last\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    center: function () {\n      this.canvas && this.canvas.centerObject(this);\n      return this;\n    },\n\n    /**\n     * Centers object on current viewport of canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    viewportCenter: function () {\n      this.canvas && this.canvas.viewportCenterObject(this);\n      return this;\n    },\n\n    /**\n     * Removes object from canvas to which it was added last\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    remove: function() {\n      if (this.canvas) {\n        if (this.group && this.group === this.canvas._activeGroup) {\n          this.group.remove(this);\n        }\n        this.canvas.remove(this);\n      }\n      return this;\n    },\n\n    /**\n     * Returns coordinates of a pointer relative to an object\n     * @param {Event} e Event to operate upon\n     * @param {Object} [pointer] Pointer to operate upon (instead of event)\n     * @return {Object} Coordinates of a pointer (x, y)\n     */\n    getLocalPointer: function(e, pointer) {\n      pointer = pointer || this.canvas.getPointer(e);\n      var pClicked = new fabric.Point(pointer.x, pointer.y),\n          objectLeftTop = this._getLeftTopCoords();\n      if (this.angle) {\n        pClicked = fabric.util.rotatePoint(\n          pClicked, objectLeftTop, degreesToRadians(-this.angle));\n      }\n      return {\n        x: pClicked.x - objectLeftTop.x,\n        y: pClicked.y - objectLeftTop.y\n      };\n    },\n\n    /**\n     * Sets canvas globalCompositeOperation for specific object\n     * custom composition operation for the particular object can be specifed using globalCompositeOperation property\n     * @param {CanvasRenderingContext2D} ctx Rendering canvas context\n     */\n    _setupCompositeOperation: function (ctx) {\n      if (this.globalCompositeOperation) {\n        ctx.globalCompositeOperation = this.globalCompositeOperation;\n      }\n    }\n  });\n\n  fabric.util.createAccessors(fabric.Object);\n\n  /**\n   * Alias for {@link fabric.Object.prototype.setAngle}\n   * @alias rotate -> setAngle\n   * @memberOf fabric.Object\n   */\n  fabric.Object.prototype.rotate = fabric.Object.prototype.setAngle;\n\n  extend(fabric.Object.prototype, fabric.Observable);\n\n  /**\n   * Defines the number of fraction digits to use when serializing object values.\n   * You can use it to increase/decrease precision of such values like left, top, scaleX, scaleY, etc.\n   * @static\n   * @memberOf fabric.Object\n   * @constant\n   * @type Number\n   */\n  fabric.Object.NUM_FRACTION_DIGITS = 2;\n\n  fabric.Object._fromObject = function(className, object, callback, forceAsync, extraParam) {\n    var klass = fabric[className];\n    object = clone(object, true);\n    if (forceAsync) {\n      fabric.util.enlivenPatterns([object.fill, object.stroke], function(patterns) {\n        if (typeof patterns[0] !== 'undefined') {\n          object.fill = patterns[0];\n        }\n        if (typeof patterns[1] !== 'undefined') {\n          object.stroke = patterns[1];\n        }\n        var instance = extraParam ? new klass(object[extraParam], object) : new klass(object);\n        callback && callback(instance);\n      });\n    }\n    else {\n      var instance = extraParam ? new klass(object[extraParam], object) : new klass(object);\n      callback && callback(instance);\n      return instance;\n    }\n  };\n\n  /**\n   * Unique id used internally when creating SVG elements\n   * @static\n   * @memberOf fabric.Object\n   * @type Number\n   */\n  fabric.Object.__uid = 0;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n  var degreesToRadians = fabric.util.degreesToRadians,\n      originXOffset = {\n        left: -0.5,\n        center: 0,\n        right: 0.5\n      },\n      originYOffset = {\n        top: -0.5,\n        center: 0,\n        bottom: 0.5\n      };\n\n  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Translates the coordinates from origin to center coordinates (based on the object's dimensions)\n     * @param {fabric.Point} point The point which corresponds to the originX and originY params\n     * @param {String} fromOriginX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} fromOriginY Vertical origin: 'top', 'center' or 'bottom'\n     * @param {String} toOriginX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} toOriginY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    translateToGivenOrigin: function(point, fromOriginX, fromOriginY, toOriginX, toOriginY) {\n      var x = point.x,\n          y = point.y,\n          offsetX, offsetY, dim;\n\n      if (typeof fromOriginX === 'string') {\n        fromOriginX = originXOffset[fromOriginX];\n      }\n      else {\n        fromOriginX -= 0.5;\n      }\n\n      if (typeof toOriginX === 'string') {\n        toOriginX = originXOffset[toOriginX];\n      }\n      else {\n        toOriginX -= 0.5;\n      }\n\n      offsetX = toOriginX - fromOriginX;\n\n      if (typeof fromOriginY === 'string') {\n        fromOriginY = originYOffset[fromOriginY];\n      }\n      else {\n        fromOriginY -= 0.5;\n      }\n\n      if (typeof toOriginY === 'string') {\n        toOriginY = originYOffset[toOriginY];\n      }\n      else {\n        toOriginY -= 0.5;\n      }\n\n      offsetY = toOriginY - fromOriginY;\n\n      if (offsetX || offsetY) {\n        dim = this._getTransformedDimensions();\n        x = point.x + offsetX * dim.x;\n        y = point.y + offsetY * dim.y;\n      }\n\n      return new fabric.Point(x, y);\n    },\n\n    /**\n     * Translates the coordinates from origin to center coordinates (based on the object's dimensions)\n     * @param {fabric.Point} point The point which corresponds to the originX and originY params\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    translateToCenterPoint: function(point, originX, originY) {\n      var p = this.translateToGivenOrigin(point, originX, originY, 'center', 'center');\n      if (this.angle) {\n        return fabric.util.rotatePoint(p, point, degreesToRadians(this.angle));\n      }\n      return p;\n    },\n\n    /**\n     * Translates the coordinates from center to origin coordinates (based on the object's dimensions)\n     * @param {fabric.Point} center The point which corresponds to center of the object\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    translateToOriginPoint: function(center, originX, originY) {\n      var p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY);\n      if (this.angle) {\n        return fabric.util.rotatePoint(p, center, degreesToRadians(this.angle));\n      }\n      return p;\n    },\n\n    /**\n     * Returns the real center coordinates of the object\n     * @return {fabric.Point}\n     */\n    getCenterPoint: function() {\n      var leftTop = new fabric.Point(this.left, this.top);\n      return this.translateToCenterPoint(leftTop, this.originX, this.originY);\n    },\n\n    /**\n     * Returns the coordinates of the object based on center coordinates\n     * @param {fabric.Point} point The point which corresponds to the originX and originY params\n     * @return {fabric.Point}\n     */\n    // getOriginPoint: function(center) {\n    //   return this.translateToOriginPoint(center, this.originX, this.originY);\n    // },\n\n    /**\n     * Returns the coordinates of the object as if it has a different origin\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    getPointByOrigin: function(originX, originY) {\n      var center = this.getCenterPoint();\n      return this.translateToOriginPoint(center, originX, originY);\n    },\n\n    /**\n     * Returns the point in local coordinates\n     * @param {fabric.Point} point The point relative to the global coordinate system\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    toLocalPoint: function(point, originX, originY) {\n      var center = this.getCenterPoint(),\n          p, p2;\n\n      if (typeof originX !== 'undefined' && typeof originY !== 'undefined' ) {\n        p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY);\n      }\n      else {\n        p = new fabric.Point(this.left, this.top);\n      }\n\n      p2 = new fabric.Point(point.x, point.y);\n      if (this.angle) {\n        p2 = fabric.util.rotatePoint(p2, center, -degreesToRadians(this.angle));\n      }\n      return p2.subtractEquals(p);\n    },\n\n    /**\n     * Returns the point in global coordinates\n     * @param {fabric.Point} The point relative to the local coordinate system\n     * @return {fabric.Point}\n     */\n    // toGlobalPoint: function(point) {\n    //   return fabric.util.rotatePoint(point, this.getCenterPoint(), degreesToRadians(this.angle)).addEquals(new fabric.Point(this.left, this.top));\n    // },\n\n    /**\n     * Sets the position of the object taking into consideration the object's origin\n     * @param {fabric.Point} pos The new position of the object\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {void}\n     */\n    setPositionByOrigin: function(pos, originX, originY) {\n      var center = this.translateToCenterPoint(pos, originX, originY),\n          position = this.translateToOriginPoint(center, this.originX, this.originY);\n\n      this.set('left', position.x);\n      this.set('top', position.y);\n    },\n\n    /**\n     * @param {String} to One of 'left', 'center', 'right'\n     */\n    adjustPosition: function(to) {\n      var angle = degreesToRadians(this.angle),\n          hypotFull = this.getWidth(),\n          xFull = Math.cos(angle) * hypotFull,\n          yFull = Math.sin(angle) * hypotFull,\n          offsetFrom, offsetTo;\n\n      //TODO: this function does not consider mixed situation like top, center.\n      if (typeof this.originX === 'string') {\n        offsetFrom = originXOffset[this.originX];\n      }\n      else {\n        offsetFrom = this.originX - 0.5;\n      }\n      if (typeof to === 'string') {\n        offsetTo = originXOffset[to];\n      }\n      else {\n        offsetTo = to - 0.5;\n      }\n      this.left += xFull * (offsetTo - offsetFrom);\n      this.top += yFull * (offsetTo - offsetFrom);\n      this.setCoords();\n      this.originX = to;\n    },\n\n    /**\n     * Sets the origin/position of the object to it's center point\n     * @private\n     * @return {void}\n     */\n    _setOriginToCenter: function() {\n      this._originalOriginX = this.originX;\n      this._originalOriginY = this.originY;\n\n      var center = this.getCenterPoint();\n\n      this.originX = 'center';\n      this.originY = 'center';\n\n      this.left = center.x;\n      this.top = center.y;\n    },\n\n    /**\n     * Resets the origin/position of the object to it's original origin\n     * @private\n     * @return {void}\n     */\n    _resetOrigin: function() {\n      var originPoint = this.translateToOriginPoint(\n        this.getCenterPoint(),\n        this._originalOriginX,\n        this._originalOriginY);\n\n      this.originX = this._originalOriginX;\n      this.originY = this._originalOriginY;\n\n      this.left = originPoint.x;\n      this.top = originPoint.y;\n\n      this._originalOriginX = null;\n      this._originalOriginY = null;\n    },\n\n    /**\n     * @private\n     */\n    _getLeftTopCoords: function() {\n      return this.translateToOriginPoint(this.getCenterPoint(), 'left', 'top');\n    },\n\n    /**\n    * Callback; invoked right before object is about to go from active to inactive\n    */\n    onDeselect: function() {\n      /* NOOP */\n    }\n  });\n\n})();\n\n\n(function() {\n\n  function getCoords(coords) {\n    return [\n      new fabric.Point(coords.tl.x, coords.tl.y),\n      new fabric.Point(coords.tr.x, coords.tr.y),\n      new fabric.Point(coords.br.x, coords.br.y),\n      new fabric.Point(coords.bl.x, coords.bl.y)\n    ];\n  }\n\n  var degreesToRadians = fabric.util.degreesToRadians,\n      multiplyMatrices = fabric.util.multiplyTransformMatrices;\n\n  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Describe object's corner position in canvas element coordinates.\n     * properties are tl,mt,tr,ml,mr,bl,mb,br,mtr for the main controls.\n     * each property is an object with x, y and corner.\n     * The `corner` property contains in a similar manner the 4 points of the\n     * interactive area of the corner.\n     * The coordinates depends from this properties: width, height, scaleX, scaleY\n     * skewX, skewY, angle, strokeWidth, viewportTransform, top, left, padding.\n     * The coordinates get updated with @method setCoords.\n     * You can calculate them without updating with @method calcCoords;\n     * @memberOf fabric.Object.prototype\n     */\n    oCoords: null,\n\n    /**\n     * Describe object's corner position in canvas object absolute coordinates\n     * properties are tl,tr,bl,br and describe the four main corner.\n     * each property is an object with x, y, instance of Fabric.Point.\n     * The coordinates depends from this properties: width, height, scaleX, scaleY\n     * skewX, skewY, angle, strokeWidth, top, left.\n     * Those coordinates are usefull to understand where an object is. They get updated\n     * with oCoords but they do not need to be updated when zoom or panning change.\n     * The coordinates get updated with @method setCoords.\n     * You can calculate them without updating with @method calcCoords(true);\n     * @memberOf fabric.Object.prototype\n     */\n    aCoords: null,\n\n    /**\n     * return correct set of coordinates for intersection\n     */\n    getCoords: function(absolute, calculate) {\n      if (!this.oCoords) {\n        this.setCoords();\n      }\n      var coords = absolute ? this.aCoords : this.oCoords;\n      return getCoords(calculate ? this.calcCoords(absolute) : coords);\n    },\n\n    /**\n     * Checks if object intersects with an area formed by 2 points\n     * @param {Object} pointTL top-left point of area\n     * @param {Object} pointBR bottom-right point of area\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object intersects with an area formed by 2 points\n     */\n    intersectsWithRect: function(pointTL, pointBR, absolute, calculate) {\n      var coords = this.getCoords(absolute, calculate),\n          intersection = fabric.Intersection.intersectPolygonRectangle(\n            coords,\n            pointTL,\n            pointBR\n          );\n      return intersection.status === 'Intersection';\n    },\n\n    /**\n     * Checks if object intersects with another object\n     * @param {Object} other Object to test\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object intersects with another object\n     */\n    intersectsWithObject: function(other, absolute, calculate) {\n      var intersection = fabric.Intersection.intersectPolygonPolygon(\n            this.getCoords(absolute, calculate),\n            other.getCoords(absolute, calculate)\n          );\n\n      return intersection.status === 'Intersection'\n        || other.isContainedWithinObject(this, absolute, calculate)\n        || this.isContainedWithinObject(other, absolute, calculate);\n    },\n\n    /**\n     * Checks if object is fully contained within area of another object\n     * @param {Object} other Object to test\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object is fully contained within area of another object\n     */\n    isContainedWithinObject: function(other, absolute, calculate) {\n      var points = this.getCoords(absolute, calculate),\n          i = 0, lines = other._getImageLines(\n            calculate ? other.calcCoords(absolute) : absolute ? other.aCoords : other.oCoords\n          );\n      for (; i < 4; i++) {\n        if (!other.containsPoint(points[i], lines)) {\n          return false;\n        }\n      }\n      return true;\n    },\n\n    /**\n     * Checks if object is fully contained within area formed by 2 points\n     * @param {Object} pointTL top-left point of area\n     * @param {Object} pointBR bottom-right point of area\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object is fully contained within area formed by 2 points\n     */\n    isContainedWithinRect: function(pointTL, pointBR, absolute, calculate) {\n      var boundingRect = this.getBoundingRect(absolute, calculate);\n\n      return (\n        boundingRect.left >= pointTL.x &&\n        boundingRect.left + boundingRect.width <= pointBR.x &&\n        boundingRect.top >= pointTL.y &&\n        boundingRect.top + boundingRect.height <= pointBR.y\n      );\n    },\n\n    /**\n     * Checks if point is inside the object\n     * @param {fabric.Point} point Point to check against\n     * @param {Object} [lines] object returned from @method _getImageLines\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if point is inside the object\n     */\n    containsPoint: function(point, lines, absolute, calculate) {\n      var lines = lines || this._getImageLines(\n        calculate ? this.calcCoords(absolute) : absolute ? this.aCoords : this.oCoords\n      ),\n          xPoints = this._findCrossPoints(point, lines);\n\n      // if xPoints is odd then point is inside the object\n      return (xPoints !== 0 && xPoints % 2 === 1);\n    },\n\n    /**\n     * Checks if object is contained within the canvas with current viewportTransform\n     * the check is done stopping at first point that appear on screen\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object is fully contained within canvas\n     */\n    isOnScreen: function(calculate) {\n      if (!this.canvas) {\n        return false;\n      }\n      var pointTL = this.canvas.vptCoords.tl, pointBR = this.canvas.vptCoords.br;\n      var points = this.getCoords(true, calculate), point;\n      for (var i = 0; i < 4; i++) {\n        point = points[i];\n        if (point.x <= pointBR.x && point.x >= pointTL.x && point.y <= pointBR.y && point.y >= pointTL.y) {\n          return true;\n        }\n      }\n      // no points on screen, check intersection with absolute coordinates\n      if (this.intersectsWithRect(pointTL, pointBR, true)) {\n        return true;\n      }\n      // worst case scenario the object is so big that contanins the screen\n      var centerPoint = { x: (pointTL.x + pointBR.x) / 2, y: (pointTL.y + pointBR.y) / 2 };\n      if (this.containsPoint(centerPoint, null, true)) {\n        return true;\n      }\n      return false;\n    },\n\n    /**\n     * Method that returns an object with the object edges in it, given the coordinates of the corners\n     * @private\n     * @param {Object} oCoords Coordinates of the object corners\n     */\n    _getImageLines: function(oCoords) {\n      return {\n        topline: {\n          o: oCoords.tl,\n          d: oCoords.tr\n        },\n        rightline: {\n          o: oCoords.tr,\n          d: oCoords.br\n        },\n        bottomline: {\n          o: oCoords.br,\n          d: oCoords.bl\n        },\n        leftline: {\n          o: oCoords.bl,\n          d: oCoords.tl\n        }\n      };\n    },\n\n    /**\n     * Helper method to determine how many cross points are between the 4 object edges\n     * and the horizontal line determined by a point on canvas\n     * @private\n     * @param {fabric.Point} point Point to check\n     * @param {Object} lines Coordinates of the object being evaluated\n     */\n     // remove yi, not used but left code here just in case.\n    _findCrossPoints: function(point, lines) {\n      var b1, b2, a1, a2, xi, // yi,\n          xcount = 0,\n          iLine;\n\n      for (var lineKey in lines) {\n        iLine = lines[lineKey];\n        // optimisation 1: line below point. no cross\n        if ((iLine.o.y < point.y) && (iLine.d.y < point.y)) {\n          continue;\n        }\n        // optimisation 2: line above point. no cross\n        if ((iLine.o.y >= point.y) && (iLine.d.y >= point.y)) {\n          continue;\n        }\n        // optimisation 3: vertical line case\n        if ((iLine.o.x === iLine.d.x) && (iLine.o.x >= point.x)) {\n          xi = iLine.o.x;\n          // yi = point.y;\n        }\n        // calculate the intersection point\n        else {\n          b1 = 0;\n          b2 = (iLine.d.y - iLine.o.y) / (iLine.d.x - iLine.o.x);\n          a1 = point.y - b1 * point.x;\n          a2 = iLine.o.y - b2 * iLine.o.x;\n\n          xi = -(a1 - a2) / (b1 - b2);\n          // yi = a1 + b1 * xi;\n        }\n        // dont count xi < point.x cases\n        if (xi >= point.x) {\n          xcount += 1;\n        }\n        // optimisation 4: specific for square images\n        if (xcount === 2) {\n          break;\n        }\n      }\n      return xcount;\n    },\n\n    /**\n     * Returns width of an object's bounding rectangle\n     * @deprecated since 1.0.4\n     * @return {Number} width value\n     */\n    getBoundingRectWidth: function() {\n      return this.getBoundingRect().width;\n    },\n\n    /**\n     * Returns height of an object's bounding rectangle\n     * @deprecated since 1.0.4\n     * @return {Number} height value\n     */\n    getBoundingRectHeight: function() {\n      return this.getBoundingRect().height;\n    },\n\n    /**\n     * Returns coordinates of object's bounding rectangle (left, top, width, height)\n     * the box is intented as aligned to axis of canvas.\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Object} Object with left, top, width, height properties\n     */\n    getBoundingRect: function(absolute, calculate) {\n      var coords = this.getCoords(absolute, calculate);\n      return fabric.util.makeBoundingBoxFromPoints(coords);\n    },\n\n    /**\n     * Returns width of an object bounding box counting transformations\n     * @return {Number} width value\n     */\n    getWidth: function() {\n      return this._getTransformedDimensions().x;\n    },\n\n    /**\n     * Returns height of an object bounding box counting transformations\n     * to be renamed in 2.0\n     * @return {Number} height value\n     */\n    getHeight: function() {\n      return this._getTransformedDimensions().y;\n    },\n\n    /**\n     * Makes sure the scale is valid and modifies it if necessary\n     * @private\n     * @param {Number} value\n     * @return {Number}\n     */\n    _constrainScale: function(value) {\n      if (Math.abs(value) < this.minScaleLimit) {\n        if (value < 0) {\n          return -this.minScaleLimit;\n        }\n        else {\n          return this.minScaleLimit;\n        }\n      }\n      return value;\n    },\n\n    /**\n     * Scales an object (equally by x and y)\n     * @param {Number} value Scale factor\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    scale: function(value) {\n      value = this._constrainScale(value);\n\n      if (value < 0) {\n        this.flipX = !this.flipX;\n        this.flipY = !this.flipY;\n        value *= -1;\n      }\n\n      this.scaleX = value;\n      this.scaleY = value;\n      return this.setCoords();\n    },\n\n    /**\n     * Scales an object to a given width, with respect to bounding box (scaling by x/y equally)\n     * @param {Number} value New width value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    scaleToWidth: function(value) {\n      // adjust to bounding rect factor so that rotated shapes would fit as well\n      var boundingRectFactor = this.getBoundingRect().width / this.getWidth();\n      return this.scale(value / this.width / boundingRectFactor);\n    },\n\n    /**\n     * Scales an object to a given height, with respect to bounding box (scaling by x/y equally)\n     * @param {Number} value New height value\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    scaleToHeight: function(value) {\n      // adjust to bounding rect factor so that rotated shapes would fit as well\n      var boundingRectFactor = this.getBoundingRect().height / this.getHeight();\n      return this.scale(value / this.height / boundingRectFactor);\n    },\n\n    /**\n     * Calculate and returns the .coords of an object.\n     * @return {Object} Object with tl, tr, br, bl ....\n     * @chainable\n     */\n    calcCoords: function(absolute) {\n      var theta = degreesToRadians(this.angle),\n          vpt = this.getViewportTransform(),\n          dim = absolute ? this._getTransformedDimensions() : this._calculateCurrentDimensions(),\n          currentWidth = dim.x, currentHeight = dim.y,\n          sinTh = Math.sin(theta),\n          cosTh = Math.cos(theta),\n          _angle = currentWidth > 0 ? Math.atan(currentHeight / currentWidth) : 0,\n          _hypotenuse = (currentWidth / Math.cos(_angle)) / 2,\n          offsetX = Math.cos(_angle + theta) * _hypotenuse,\n          offsetY = Math.sin(_angle + theta) * _hypotenuse,\n          center = this.getCenterPoint(),\n          // offset added for rotate and scale actions\n          coords = absolute ? center : fabric.util.transformPoint(center, vpt),\n          tl  = new fabric.Point(coords.x - offsetX, coords.y - offsetY),\n          tr  = new fabric.Point(tl.x + (currentWidth * cosTh), tl.y + (currentWidth * sinTh)),\n          bl  = new fabric.Point(tl.x - (currentHeight * sinTh), tl.y + (currentHeight * cosTh)),\n          br  = new fabric.Point(coords.x + offsetX, coords.y + offsetY);\n      if (!absolute) {\n        var ml  = new fabric.Point((tl.x + bl.x) / 2, (tl.y + bl.y) / 2),\n            mt  = new fabric.Point((tr.x + tl.x) / 2, (tr.y + tl.y) / 2),\n            mr  = new fabric.Point((br.x + tr.x) / 2, (br.y + tr.y) / 2),\n            mb  = new fabric.Point((br.x + bl.x) / 2, (br.y + bl.y) / 2),\n            mtr = new fabric.Point(mt.x + sinTh * this.rotatingPointOffset, mt.y - cosTh * this.rotatingPointOffset);\n      }\n\n      // debugging\n\n      /* setTimeout(function() {\n         canvas.contextTop.fillStyle = 'green';\n         canvas.contextTop.fillRect(mb.x, mb.y, 3, 3);\n         canvas.contextTop.fillRect(bl.x, bl.y, 3, 3);\n         canvas.contextTop.fillRect(br.x, br.y, 3, 3);\n         canvas.contextTop.fillRect(tl.x, tl.y, 3, 3);\n         canvas.contextTop.fillRect(tr.x, tr.y, 3, 3);\n         canvas.contextTop.fillRect(ml.x, ml.y, 3, 3);\n         canvas.contextTop.fillRect(mr.x, mr.y, 3, 3);\n         canvas.contextTop.fillRect(mt.x, mt.y, 3, 3);\n         canvas.contextTop.fillRect(mtr.x, mtr.y, 3, 3);\n       }, 50); */\n\n      var coords = {\n        // corners\n        tl: tl, tr: tr, br: br, bl: bl,\n      };\n      if (!absolute) {\n        // middle\n        coords.ml = ml;\n        coords.mt = mt;\n        coords.mr = mr;\n        coords.mb = mb;\n        // rotating point\n        coords.mtr = mtr;\n      }\n      return coords;\n    },\n\n    /**\n     * Sets corner position coordinates based on current angle, width and height\n     * See https://github.com/kangax/fabric.js/wiki/When-to-call-setCoords\n     * @param {Boolean} [ignoreZoom] set oCoords with or without the viewport transform.\n     * @param {Boolean} [skipAbsolute] skip calculation of aCoords, usefull in setViewportTransform\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setCoords: function(ignoreZoom, skipAbsolute) {\n      this.oCoords = this.calcCoords(ignoreZoom);\n      if (!skipAbsolute) {\n        this.aCoords = this.calcCoords(true);\n      }\n\n      // set coordinates of the draggable boxes in the corners used to scale/rotate the image\n      ignoreZoom || (this._setCornerCoords && this._setCornerCoords());\n\n      return this;\n    },\n\n    /**\n     * calculate rotation matrix of an object\n     * @return {Array} rotation matrix for the object\n     */\n    _calcRotateMatrix: function() {\n      if (this.angle) {\n        var theta = degreesToRadians(this.angle), cos = Math.cos(theta), sin = Math.sin(theta);\n        // trying to keep rounding error small, ugly but it works.\n        if (cos === 6.123233995736766e-17 || cos === -1.8369701987210297e-16) {\n          cos = 0;\n        }\n        return [cos, sin, -sin, cos, 0, 0];\n      }\n      return fabric.iMatrix.concat();\n    },\n\n    /**\n     * calculate trasform Matrix that represent current transformation from\n     * object properties.\n     * @param {Boolean} [skipGroup] return transformMatrix for object and not go upward with parents\n     * @return {Array} matrix Transform Matrix for the object\n     */\n    calcTransformMatrix: function(skipGroup) {\n      var center = this.getCenterPoint(),\n          translateMatrix = [1, 0, 0, 1, center.x, center.y],\n          rotateMatrix,\n          dimensionMatrix = this._calcDimensionsTransformMatrix(this.skewX, this.skewY, true),\n          matrix;\n      if (this.group && !skipGroup) {\n        matrix = multiplyMatrices(this.group.calcTransformMatrix(), translateMatrix);\n      }\n      else {\n        matrix = translateMatrix;\n      }\n      if (this.angle) {\n        rotateMatrix = this._calcRotateMatrix();\n        matrix = multiplyMatrices(matrix, rotateMatrix);\n      }\n      matrix = multiplyMatrices(matrix, dimensionMatrix);\n      return matrix;\n    },\n\n    _calcDimensionsTransformMatrix: function(skewX, skewY, flipping) {\n      var skewMatrix,\n          scaleX = this.scaleX * (flipping && this.flipX ? -1 : 1),\n          scaleY = this.scaleY * (flipping && this.flipY ? -1 : 1),\n          scaleMatrix = [scaleX, 0, 0, scaleY, 0, 0];\n      if (skewX) {\n        skewMatrix = [1, 0, Math.tan(degreesToRadians(skewX)), 1];\n        scaleMatrix = multiplyMatrices(scaleMatrix, skewMatrix, true);\n      }\n      if (skewY) {\n        skewMatrix = [1, Math.tan(degreesToRadians(skewY)), 0, 1];\n        scaleMatrix = multiplyMatrices(scaleMatrix, skewMatrix, true);\n      }\n      return scaleMatrix;\n    },\n\n    /*\n     * Calculate object dimensions from its properties\n     * @private\n     * @return {Object} .x width dimension\n     * @return {Object} .y height dimension\n     */\n    _getNonTransformedDimensions: function() {\n      var strokeWidth = this.strokeWidth,\n          w = this.width + strokeWidth,\n          h = this.height + strokeWidth;\n      return { x: w, y: h };\n    },\n\n    /*\n     * Calculate object bounding boxdimensions from its properties scale, skew.\n     * @private\n     * @return {Object} .x width dimension\n     * @return {Object} .y height dimension\n     */\n    _getTransformedDimensions: function(skewX, skewY) {\n      if (typeof skewX === 'undefined') {\n        skewX = this.skewX;\n      }\n      if (typeof skewY === 'undefined') {\n        skewY = this.skewY;\n      }\n      var dimensions = this._getNonTransformedDimensions(),\n          dimX = dimensions.x / 2, dimY = dimensions.y / 2,\n          points = [\n            {\n              x: -dimX,\n              y: -dimY\n            },\n            {\n              x: dimX,\n              y: -dimY\n            },\n            {\n              x: -dimX,\n              y: dimY\n            },\n            {\n              x: dimX,\n              y: dimY\n            }],\n          i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY, false),\n          bbox;\n      for (i = 0; i < points.length; i++) {\n        points[i] = fabric.util.transformPoint(points[i], transformMatrix);\n      }\n      bbox = fabric.util.makeBoundingBoxFromPoints(points);\n      return { x: bbox.width, y: bbox.height };\n    },\n\n    /*\n     * Calculate object dimensions for controls. include padding and canvas zoom\n     * private\n     */\n    _calculateCurrentDimensions: function()  {\n      var vpt = this.getViewportTransform(),\n          dim = this._getTransformedDimensions(),\n          p = fabric.util.transformPoint(dim, vpt, true);\n\n      return p.scalarAdd(2 * this.padding);\n    },\n  });\n})();\n\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n  /**\n   * Moves an object to the bottom of the stack of drawn objects\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  sendToBack: function() {\n    if (this.group) {\n      fabric.StaticCanvas.prototype.sendToBack.call(this.group, this);\n    }\n    else {\n      this.canvas.sendToBack(this);\n    }\n    return this;\n  },\n\n  /**\n   * Moves an object to the top of the stack of drawn objects\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  bringToFront: function() {\n    if (this.group) {\n      fabric.StaticCanvas.prototype.bringToFront.call(this.group, this);\n    }\n    else {\n      this.canvas.bringToFront(this);\n    }\n    return this;\n  },\n\n  /**\n   * Moves an object down in stack of drawn objects\n   * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  sendBackwards: function(intersecting) {\n    if (this.group) {\n      fabric.StaticCanvas.prototype.sendBackwards.call(this.group, this, intersecting);\n    }\n    else {\n      this.canvas.sendBackwards(this, intersecting);\n    }\n    return this;\n  },\n\n  /**\n   * Moves an object up in stack of drawn objects\n   * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  bringForward: function(intersecting) {\n    if (this.group) {\n      fabric.StaticCanvas.prototype.bringForward.call(this.group, this, intersecting);\n    }\n    else {\n      this.canvas.bringForward(this, intersecting);\n    }\n    return this;\n  },\n\n  /**\n   * Moves an object to specified level in stack of drawn objects\n   * @param {Number} index New position of object\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  moveTo: function(index) {\n    if (this.group) {\n      fabric.StaticCanvas.prototype.moveTo.call(this.group, this, index);\n    }\n    else {\n      this.canvas.moveTo(this, index);\n    }\n    return this;\n  }\n});\n\n\n/* _TO_SVG_START_ */\n(function() {\n\n  function getSvgColorString(prop, value) {\n    if (!value) {\n      return prop + ': none; ';\n    }\n    else if (value.toLive) {\n      return prop + ': url(#SVGID_' + value.id + '); ';\n    }\n    else {\n      var color = new fabric.Color(value),\n          str = prop + ': ' + color.toRgb() + '; ',\n          opacity = color.getAlpha();\n      if (opacity !== 1) {\n        //change the color in rgb + opacity\n        str += prop + '-opacity: ' + opacity.toString() + '; ';\n      }\n      return str;\n    }\n  }\n\n  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n    /**\n     * Returns styles-string for svg-export\n     * @param {Boolean} skipShadow a boolean to skip shadow filter output\n     * @return {String}\n     */\n    getSvgStyles: function(skipShadow) {\n\n      var fillRule = this.fillRule,\n          strokeWidth = this.strokeWidth ? this.strokeWidth : '0',\n          strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none',\n          strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',\n          strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter',\n          strokeMiterLimit = this.strokeMiterLimit ? this.strokeMiterLimit : '4',\n          opacity = typeof this.opacity !== 'undefined' ? this.opacity : '1',\n          visibility = this.visible ? '' : ' visibility: hidden;',\n          filter = skipShadow ? '' : this.getSvgFilter(),\n          fill = getSvgColorString('fill', this.fill),\n          stroke = getSvgColorString('stroke', this.stroke);\n\n      return [\n        stroke,\n        'stroke-width: ', strokeWidth, '; ',\n        'stroke-dasharray: ', strokeDashArray, '; ',\n        'stroke-linecap: ', strokeLineCap, '; ',\n        'stroke-linejoin: ', strokeLineJoin, '; ',\n        'stroke-miterlimit: ', strokeMiterLimit, '; ',\n        fill,\n        'fill-rule: ', fillRule, '; ',\n        'opacity: ', opacity, ';',\n        filter,\n        visibility\n      ].join('');\n    },\n\n    /**\n     * Returns filter for svg shadow\n     * @return {String}\n     */\n    getSvgFilter: function() {\n      return this.shadow ? 'filter: url(#SVGID_' + this.shadow.id + ');' : '';\n    },\n\n    /**\n     * Returns id attribute for svg output\n     * @return {String}\n     */\n    getSvgId: function() {\n      return this.id ? 'id=\"' + this.id + '\" ' : '';\n    },\n\n    /**\n     * Returns transform-string for svg-export\n     * @return {String}\n     */\n    getSvgTransform: function() {\n      if (this.group && this.group.type === 'path-group') {\n        return '';\n      }\n      var toFixed = fabric.util.toFixed,\n          angle = this.getAngle(),\n          skewX = (this.getSkewX() % 360),\n          skewY = (this.getSkewY() % 360),\n          center = this.getCenterPoint(),\n\n          NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n\n          translatePart = this.type === 'path-group' ? '' : 'translate(' +\n                            toFixed(center.x, NUM_FRACTION_DIGITS) +\n                            ' ' +\n                            toFixed(center.y, NUM_FRACTION_DIGITS) +\n                          ')',\n\n          anglePart = angle !== 0\n            ? (' rotate(' + toFixed(angle, NUM_FRACTION_DIGITS) + ')')\n            : '',\n\n          scalePart = (this.scaleX === 1 && this.scaleY === 1)\n            ? '' :\n            (' scale(' +\n              toFixed(this.scaleX, NUM_FRACTION_DIGITS) +\n              ' ' +\n              toFixed(this.scaleY, NUM_FRACTION_DIGITS) +\n            ')'),\n\n          skewXPart = skewX !== 0 ? ' skewX(' + toFixed(skewX, NUM_FRACTION_DIGITS) + ')' : '',\n\n          skewYPart = skewY !== 0 ? ' skewY(' + toFixed(skewY, NUM_FRACTION_DIGITS) + ')' : '',\n\n          addTranslateX = this.type === 'path-group' ? this.width : 0,\n\n          flipXPart = this.flipX ? ' matrix(-1 0 0 1 ' + addTranslateX + ' 0) ' : '',\n\n          addTranslateY = this.type === 'path-group' ? this.height : 0,\n\n          flipYPart = this.flipY ? ' matrix(1 0 0 -1 0 ' + addTranslateY + ')' : '';\n\n      return [\n        translatePart, anglePart, scalePart, flipXPart, flipYPart, skewXPart, skewYPart\n      ].join('');\n    },\n\n    /**\n     * Returns transform-string for svg-export from the transform matrix of single elements\n     * @return {String}\n     */\n    getSvgTransformMatrix: function() {\n      return this.transformMatrix ? ' matrix(' + this.transformMatrix.join(' ') + ') ' : '';\n    },\n\n    /**\n     * @private\n     */\n    _createBaseSVGMarkup: function() {\n      var markup = [];\n\n      if (this.fill && this.fill.toLive) {\n        markup.push(this.fill.toSVG(this, false));\n      }\n      if (this.stroke && this.stroke.toLive) {\n        markup.push(this.stroke.toSVG(this, false));\n      }\n      if (this.shadow) {\n        markup.push(this.shadow.toSVG(this));\n      }\n      return markup;\n    }\n  });\n})();\n/* _TO_SVG_END_ */\n\n\n(function() {\n\n  var extend = fabric.util.object.extend,\n      originalSet = 'stateProperties';\n\n  /*\n    Depends on `stateProperties`\n  */\n  function saveProps(origin, destination, props) {\n    var tmpObj = { }, deep = true;\n    props.forEach(function(prop) {\n      tmpObj[prop] = origin[prop];\n    });\n    extend(origin[destination], tmpObj, deep);\n  }\n\n  function _isEqual(origValue, currentValue, firstPass) {\n    if (origValue === currentValue) {\n      // if the objects are identical, return\n      return true;\n    }\n    else if (Array.isArray(origValue)) {\n      if (origValue.length !== currentValue.length) {\n        return false;\n      }\n      for (var i = 0, len = origValue.length; i < len; i++) {\n        if (!_isEqual(origValue[i], currentValue[i])) {\n          return false;\n        }\n      }\n      return true;\n    }\n    else if (origValue && typeof origValue === 'object') {\n      var keys = Object.keys(origValue), key;\n      if (!firstPass && keys.length !== Object.keys(currentValue).length) {\n        return false;\n      }\n      for (var i = 0, len = keys.length; i < len; i++) {\n        key = keys[i];\n        if (!_isEqual(origValue[key], currentValue[key])) {\n          return false;\n        }\n      }\n      return true;\n    }\n  }\n\n\n  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Returns true if object state (one of its state properties) was changed\n     * @param {String} [propertySet] optional name for the set of property we want to save\n     * @return {Boolean} true if instance' state has changed since `{@link fabric.Object#saveState}` was called\n     */\n    hasStateChanged: function(propertySet) {\n      propertySet = propertySet || originalSet;\n      var dashedPropertySet = '_' + propertySet;\n      if (Object.keys(this[dashedPropertySet]).length < this[propertySet].length) {\n        return true;\n      }\n      return !_isEqual(this[dashedPropertySet], this, true);\n    },\n\n    /**\n     * Saves state of an object\n     * @param {Object} [options] Object with additional `stateProperties` array to include when saving state\n     * @return {fabric.Object} thisArg\n     */\n    saveState: function(options) {\n      var propertySet = options && options.propertySet || originalSet,\n          destination = '_' + propertySet;\n      if (!this[destination]) {\n        return this.setupState(options);\n      }\n      saveProps(this, destination, this[propertySet]);\n      if (options && options.stateProperties) {\n        saveProps(this, destination, options.stateProperties);\n      }\n      return this;\n    },\n\n    /**\n     * Setups state of an object\n     * @param {Object} [options] Object with additional `stateProperties` array to include when saving state\n     * @return {fabric.Object} thisArg\n     */\n    setupState: function(options) {\n      options = options || { };\n      var propertySet = options.propertySet || originalSet;\n      options.propertySet = propertySet;\n      this['_' + propertySet] = { };\n      this.saveState(options);\n      return this;\n    }\n  });\n})();\n\n\n(function() {\n\n  var degreesToRadians = fabric.util.degreesToRadians,\n      /* eslint-disable camelcase */\n      isVML = function() { return typeof G_vmlCanvasManager !== 'undefined'; };\n      /* eslint-enable camelcase */\n  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * The object interactivity controls.\n     * @private\n     */\n    _controlsVisibility: null,\n\n    /**\n     * Determines which corner has been clicked\n     * @private\n     * @param {Object} pointer The pointer indicating the mouse position\n     * @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found\n     */\n    _findTargetCorner: function(pointer) {\n      if (!this.hasControls || !this.active) {\n        return false;\n      }\n\n      var ex = pointer.x,\n          ey = pointer.y,\n          xPoints,\n          lines;\n      this.__corner = 0;\n      for (var i in this.oCoords) {\n\n        if (!this.isControlVisible(i)) {\n          continue;\n        }\n\n        if (i === 'mtr' && !this.hasRotatingPoint) {\n          continue;\n        }\n\n        if (this.get('lockUniScaling') &&\n           (i === 'mt' || i === 'mr' || i === 'mb' || i === 'ml')) {\n          continue;\n        }\n\n        lines = this._getImageLines(this.oCoords[i].corner);\n\n        // debugging\n\n        // canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);\n        // canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);\n\n        // canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);\n        // canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);\n\n        // canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);\n        // canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);\n\n        // canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);\n        // canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);\n\n        xPoints = this._findCrossPoints({ x: ex, y: ey }, lines);\n        if (xPoints !== 0 && xPoints % 2 === 1) {\n          this.__corner = i;\n          return i;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Sets the coordinates of the draggable boxes in the corners of\n     * the image used to scale/rotate it.\n     * @private\n     */\n    _setCornerCoords: function() {\n      var coords = this.oCoords,\n          newTheta = degreesToRadians(45 - this.angle),\n          /* Math.sqrt(2 * Math.pow(this.cornerSize, 2)) / 2, */\n          /* 0.707106 stands for sqrt(2)/2 */\n          cornerHypotenuse = this.cornerSize * 0.707106,\n          cosHalfOffset = cornerHypotenuse * Math.cos(newTheta),\n          sinHalfOffset = cornerHypotenuse * Math.sin(newTheta),\n          x, y;\n\n      for (var point in coords) {\n        x = coords[point].x;\n        y = coords[point].y;\n        coords[point].corner = {\n          tl: {\n            x: x - sinHalfOffset,\n            y: y - cosHalfOffset\n          },\n          tr: {\n            x: x + cosHalfOffset,\n            y: y - sinHalfOffset\n          },\n          bl: {\n            x: x - cosHalfOffset,\n            y: y + sinHalfOffset\n          },\n          br: {\n            x: x + sinHalfOffset,\n            y: y + cosHalfOffset\n          }\n        };\n      }\n    },\n\n    /**\n     * Draws a colored layer behind the object, inside its selection borders.\n     * Requires public options: padding, selectionBackgroundColor\n     * this function is called when the context is transformed\n     * has checks to be skipped when the object is on a staticCanvas\n     * @param {CanvasRenderingContext2D} ctx Context to draw on\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    drawSelectionBackground: function(ctx) {\n      if (!this.selectionBackgroundColor || this.group || !this.active ||\n        (this.canvas && !this.canvas.interactive)) {\n        return this;\n      }\n      ctx.save();\n      var center = this.getCenterPoint(), wh = this._calculateCurrentDimensions(),\n          vpt = this.canvas.viewportTransform;\n      ctx.translate(center.x, center.y);\n      ctx.scale(1 / vpt[0], 1 / vpt[3]);\n      ctx.rotate(degreesToRadians(this.angle));\n      ctx.fillStyle = this.selectionBackgroundColor;\n      ctx.fillRect(-wh.x / 2, -wh.y / 2, wh.x, wh.y);\n      ctx.restore();\n      return this;\n    },\n\n    /**\n     * Draws borders of an object's bounding box.\n     * Requires public properties: width, height\n     * Requires public options: padding, borderColor\n     * @param {CanvasRenderingContext2D} ctx Context to draw on\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    drawBorders: function(ctx) {\n      if (!this.hasBorders) {\n        return this;\n      }\n\n      var wh = this._calculateCurrentDimensions(),\n          strokeWidth = 1 / this.borderScaleFactor,\n          width = wh.x + strokeWidth,\n          height = wh.y + strokeWidth;\n\n      ctx.save();\n      ctx.strokeStyle = this.borderColor;\n      this._setLineDash(ctx, this.borderDashArray, null);\n\n      ctx.strokeRect(\n        -width / 2,\n        -height / 2,\n        width,\n        height\n      );\n\n      if (this.hasRotatingPoint && this.isControlVisible('mtr') && !this.get('lockRotation') && this.hasControls) {\n\n        var rotateHeight = -height / 2;\n\n        ctx.beginPath();\n        ctx.moveTo(0, rotateHeight);\n        ctx.lineTo(0, rotateHeight - this.rotatingPointOffset);\n        ctx.closePath();\n        ctx.stroke();\n      }\n\n      ctx.restore();\n      return this;\n    },\n\n    /**\n     * Draws borders of an object's bounding box when it is inside a group.\n     * Requires public properties: width, height\n     * Requires public options: padding, borderColor\n     * @param {CanvasRenderingContext2D} ctx Context to draw on\n     * @param {object} options object representing current object parameters\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    drawBordersInGroup: function(ctx, options) {\n      if (!this.hasBorders) {\n        return this;\n      }\n\n      var p = this._getNonTransformedDimensions(),\n          matrix = fabric.util.customTransformMatrix(options.scaleX, options.scaleY, options.skewX),\n          wh = fabric.util.transformPoint(p, matrix),\n          strokeWidth = 1 / this.borderScaleFactor,\n          width = wh.x + strokeWidth,\n          height = wh.y + strokeWidth;\n\n      ctx.save();\n      this._setLineDash(ctx, this.borderDashArray, null);\n      ctx.strokeStyle = this.borderColor;\n\n      ctx.strokeRect(\n        -width / 2,\n        -height / 2,\n        width,\n        height\n      );\n\n      ctx.restore();\n      return this;\n    },\n\n    /**\n     * Draws corners of an object's bounding box.\n     * Requires public properties: width, height\n     * Requires public options: cornerSize, padding\n     * @param {CanvasRenderingContext2D} ctx Context to draw on\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    drawControls: function(ctx) {\n      if (!this.hasControls) {\n        return this;\n      }\n\n      var wh = this._calculateCurrentDimensions(),\n          width = wh.x,\n          height = wh.y,\n          scaleOffset = this.cornerSize,\n          left = -(width + scaleOffset) / 2,\n          top = -(height + scaleOffset) / 2,\n          methodName = this.transparentCorners ? 'stroke' : 'fill';\n\n      ctx.save();\n      ctx.strokeStyle = ctx.fillStyle = this.cornerColor;\n      if (!this.transparentCorners) {\n        ctx.strokeStyle = this.cornerStrokeColor;\n      }\n      this._setLineDash(ctx, this.cornerDashArray, null);\n\n      // top-left\n      this._drawControl('tl', ctx, methodName,\n        left,\n        top);\n\n      // top-right\n      this._drawControl('tr', ctx, methodName,\n        left + width,\n        top);\n\n      // bottom-left\n      this._drawControl('bl', ctx, methodName,\n        left,\n        top + height);\n\n      // bottom-right\n      this._drawControl('br', ctx, methodName,\n        left + width,\n        top + height);\n\n      if (!this.get('lockUniScaling')) {\n\n        // middle-top\n        this._drawControl('mt', ctx, methodName,\n          left + width / 2,\n          top);\n\n        // middle-bottom\n        this._drawControl('mb', ctx, methodName,\n          left + width / 2,\n          top + height);\n\n        // middle-right\n        this._drawControl('mr', ctx, methodName,\n          left + width,\n          top + height / 2);\n\n        // middle-left\n        this._drawControl('ml', ctx, methodName,\n          left,\n          top + height / 2);\n      }\n\n      // middle-top-rotate\n      if (this.hasRotatingPoint) {\n        this._drawControl('mtr', ctx, methodName,\n          left + width / 2,\n          top - this.rotatingPointOffset);\n      }\n\n      ctx.restore();\n\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _drawControl: function(control, ctx, methodName, left, top) {\n      if (!this.isControlVisible(control)) {\n        return;\n      }\n      var size = this.cornerSize, stroke = !this.transparentCorners && this.cornerStrokeColor;\n      switch (this.cornerStyle) {\n        case 'circle':\n          ctx.beginPath();\n          ctx.arc(left + size / 2, top + size / 2, size / 2, 0, 2 * Math.PI, false);\n          ctx[methodName]();\n          if (stroke) {\n            ctx.stroke();\n          }\n          break;\n        default:\n          isVML() || this.transparentCorners || ctx.clearRect(left, top, size, size);\n          ctx[methodName + 'Rect'](left, top, size, size);\n          if (stroke) {\n            ctx.strokeRect(left, top, size, size);\n          }\n      }\n    },\n\n    /**\n     * Returns true if the specified control is visible, false otherwise.\n     * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n     * @returns {Boolean} true if the specified control is visible, false otherwise\n     */\n    isControlVisible: function(controlName) {\n      return this._getControlsVisibility()[controlName];\n    },\n\n    /**\n     * Sets the visibility of the specified control.\n     * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n     * @param {Boolean} visible true to set the specified control visible, false otherwise\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setControlVisible: function(controlName, visible) {\n      this._getControlsVisibility()[controlName] = visible;\n      return this;\n    },\n\n    /**\n     * Sets the visibility state of object controls.\n     * @param {Object} [options] Options object\n     * @param {Boolean} [options.bl] true to enable the bottom-left control, false to disable it\n     * @param {Boolean} [options.br] true to enable the bottom-right control, false to disable it\n     * @param {Boolean} [options.mb] true to enable the middle-bottom control, false to disable it\n     * @param {Boolean} [options.ml] true to enable the middle-left control, false to disable it\n     * @param {Boolean} [options.mr] true to enable the middle-right control, false to disable it\n     * @param {Boolean} [options.mt] true to enable the middle-top control, false to disable it\n     * @param {Boolean} [options.tl] true to enable the top-left control, false to disable it\n     * @param {Boolean} [options.tr] true to enable the top-right control, false to disable it\n     * @param {Boolean} [options.mtr] true to enable the middle-top-rotate control, false to disable it\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setControlsVisibility: function(options) {\n      options || (options = { });\n\n      for (var p in options) {\n        this.setControlVisible(p, options[p]);\n      }\n      return this;\n    },\n\n    /**\n     * Returns the instance of the control visibility set for this object.\n     * @private\n     * @returns {Object}\n     */\n    _getControlsVisibility: function() {\n      if (!this._controlsVisibility) {\n        this._controlsVisibility = {\n          tl: true,\n          tr: true,\n          br: true,\n          bl: true,\n          ml: true,\n          mt: true,\n          mr: true,\n          mb: true,\n          mtr: true\n        };\n      }\n      return this._controlsVisibility;\n    }\n  });\n})();\n\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n  /**\n   * Animation duration (in ms) for fx* methods\n   * @type Number\n   * @default\n   */\n  FX_DURATION: 500,\n\n  /**\n   * Centers object horizontally with animation.\n   * @param {fabric.Object} object Object to center\n   * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n   * @param {Function} [callbacks.onComplete] Invoked on completion\n   * @param {Function} [callbacks.onChange] Invoked on every step of animation\n   * @return {fabric.Canvas} thisArg\n   * @chainable\n   */\n  fxCenterObjectH: function (object, callbacks) {\n    callbacks = callbacks || { };\n\n    var empty = function() { },\n        onComplete = callbacks.onComplete || empty,\n        onChange = callbacks.onChange || empty,\n        _this = this;\n\n    fabric.util.animate({\n      startValue: object.get('left'),\n      endValue: this.getCenter().left,\n      duration: this.FX_DURATION,\n      onChange: function(value) {\n        object.set('left', value);\n        _this.renderAll();\n        onChange();\n      },\n      onComplete: function() {\n        object.setCoords();\n        onComplete();\n      }\n    });\n\n    return this;\n  },\n\n  /**\n   * Centers object vertically with animation.\n   * @param {fabric.Object} object Object to center\n   * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n   * @param {Function} [callbacks.onComplete] Invoked on completion\n   * @param {Function} [callbacks.onChange] Invoked on every step of animation\n   * @return {fabric.Canvas} thisArg\n   * @chainable\n   */\n  fxCenterObjectV: function (object, callbacks) {\n    callbacks = callbacks || { };\n\n    var empty = function() { },\n        onComplete = callbacks.onComplete || empty,\n        onChange = callbacks.onChange || empty,\n        _this = this;\n\n    fabric.util.animate({\n      startValue: object.get('top'),\n      endValue: this.getCenter().top,\n      duration: this.FX_DURATION,\n      onChange: function(value) {\n        object.set('top', value);\n        _this.renderAll();\n        onChange();\n      },\n      onComplete: function() {\n        object.setCoords();\n        onComplete();\n      }\n    });\n\n    return this;\n  },\n\n  /**\n   * Same as `fabric.Canvas#remove` but animated\n   * @param {fabric.Object} object Object to remove\n   * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n   * @param {Function} [callbacks.onComplete] Invoked on completion\n   * @param {Function} [callbacks.onChange] Invoked on every step of animation\n   * @return {fabric.Canvas} thisArg\n   * @chainable\n   */\n  fxRemove: function (object, callbacks) {\n    callbacks = callbacks || { };\n\n    var empty = function() { },\n        onComplete = callbacks.onComplete || empty,\n        onChange = callbacks.onChange || empty,\n        _this = this;\n\n    fabric.util.animate({\n      startValue: object.get('opacity'),\n      endValue: 0,\n      duration: this.FX_DURATION,\n      onStart: function() {\n        object.set('active', false);\n      },\n      onChange: function(value) {\n        object.set('opacity', value);\n        _this.renderAll();\n        onChange();\n      },\n      onComplete: function () {\n        _this.remove(object);\n        onComplete();\n      }\n    });\n\n    return this;\n  }\n});\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n  /**\n   * Animates object's properties\n   * @param {String|Object} property Property to animate (if string) or properties to animate (if object)\n   * @param {Number|Object} value Value to animate property to (if string was given first) or options object\n   * @return {fabric.Object} thisArg\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#animation}\n   * @chainable\n   *\n   * As object — multiple properties\n   *\n   * object.animate({ left: ..., top: ... });\n   * object.animate({ left: ..., top: ... }, { duration: ... });\n   *\n   * As string — one property\n   *\n   * object.animate('left', ...);\n   * object.animate('left', { duration: ... });\n   *\n   */\n  animate: function() {\n    if (arguments[0] && typeof arguments[0] === 'object') {\n      var propsToAnimate = [], prop, skipCallbacks;\n      for (prop in arguments[0]) {\n        propsToAnimate.push(prop);\n      }\n      for (var i = 0, len = propsToAnimate.length; i < len; i++) {\n        prop = propsToAnimate[i];\n        skipCallbacks = i !== len - 1;\n        this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks);\n      }\n    }\n    else {\n      this._animate.apply(this, arguments);\n    }\n    return this;\n  },\n\n  /**\n   * @private\n   * @param {String} property Property to animate\n   * @param {String} to Value to animate to\n   * @param {Object} [options] Options object\n   * @param {Boolean} [skipCallbacks] When true, callbacks like onchange and oncomplete are not invoked\n   */\n  _animate: function(property, to, options, skipCallbacks) {\n    var _this = this, propPair;\n\n    to = to.toString();\n\n    if (!options) {\n      options = { };\n    }\n    else {\n      options = fabric.util.object.clone(options);\n    }\n\n    if (~property.indexOf('.')) {\n      propPair = property.split('.');\n    }\n\n    var currentValue = propPair\n      ? this.get(propPair[0])[propPair[1]]\n      : this.get(property);\n\n    if (!('from' in options)) {\n      options.from = currentValue;\n    }\n\n    if (~to.indexOf('=')) {\n      to = currentValue + parseFloat(to.replace('=', ''));\n    }\n    else {\n      to = parseFloat(to);\n    }\n\n    fabric.util.animate({\n      startValue: options.from,\n      endValue: to,\n      byValue: options.by,\n      easing: options.easing,\n      duration: options.duration,\n      abort: options.abort && function() {\n        return options.abort.call(_this);\n      },\n      onChange: function(value, valueProgress, timeProgress) {\n        if (propPair) {\n          _this[propPair[0]][propPair[1]] = value;\n        }\n        else {\n          _this.set(property, value);\n        }\n        if (skipCallbacks) {\n          return;\n        }\n        options.onChange && options.onChange(value, valueProgress, timeProgress);\n      },\n      onComplete: function(value, valueProgress, timeProgress) {\n        if (skipCallbacks) {\n          return;\n        }\n\n        _this.setCoords();\n        options.onComplete && options.onComplete(value, valueProgress, timeProgress);\n      }\n    });\n  }\n});\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      clone = fabric.util.object.clone,\n      coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 },\n      supportsLineDash = fabric.StaticCanvas.supports('setLineDash');\n\n  if (fabric.Line) {\n    fabric.warn('fabric.Line is already defined');\n    return;\n  }\n\n  /**\n   * Line class\n   * @class fabric.Line\n   * @extends fabric.Object\n   * @see {@link fabric.Line#initialize} for constructor definition\n   */\n  fabric.Line = fabric.util.createClass(fabric.Object, /** @lends fabric.Line.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'line',\n\n    /**\n     * x value or first line edge\n     * @type Number\n     * @default\n     */\n    x1: 0,\n\n    /**\n     * y value or first line edge\n     * @type Number\n     * @default\n     */\n    y1: 0,\n\n    /**\n     * x value or second line edge\n     * @type Number\n     * @default\n     */\n    x2: 0,\n\n    /**\n     * y value or second line edge\n     * @type Number\n     * @default\n     */\n    y2: 0,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('x1', 'x2', 'y1', 'y2'),\n\n    /**\n     * Constructor\n     * @param {Array} [points] Array of points\n     * @param {Object} [options] Options object\n     * @return {fabric.Line} thisArg\n     */\n    initialize: function(points, options) {\n      if (!points) {\n        points = [0, 0, 0, 0];\n      }\n\n      this.callSuper('initialize', options);\n\n      this.set('x1', points[0]);\n      this.set('y1', points[1]);\n      this.set('x2', points[2]);\n      this.set('y2', points[3]);\n\n      this._setWidthHeight(options);\n    },\n\n    /**\n     * @private\n     * @param {Object} [options] Options\n     */\n    _setWidthHeight: function(options) {\n      options || (options = { });\n\n      this.width = Math.abs(this.x2 - this.x1);\n      this.height = Math.abs(this.y2 - this.y1);\n\n      this.left = 'left' in options\n        ? options.left\n        : this._getLeftToOriginX();\n\n      this.top = 'top' in options\n        ? options.top\n        : this._getTopToOriginY();\n    },\n\n    /**\n     * @private\n     * @param {String} key\n     * @param {*} value\n     */\n    _set: function(key, value) {\n      this.callSuper('_set', key, value);\n      if (typeof coordProps[key] !== 'undefined') {\n        this._setWidthHeight();\n      }\n      return this;\n    },\n\n    /**\n     * @private\n     * @return {Number} leftToOriginX Distance from left edge of canvas to originX of Line.\n     */\n    _getLeftToOriginX: makeEdgeToOriginGetter(\n      { // property names\n        origin: 'originX',\n        axis1: 'x1',\n        axis2: 'x2',\n        dimension: 'width'\n      },\n      { // possible values of origin\n        nearest: 'left',\n        center: 'center',\n        farthest: 'right'\n      }\n    ),\n\n    /**\n     * @private\n     * @return {Number} topToOriginY Distance from top edge of canvas to originY of Line.\n     */\n    _getTopToOriginY: makeEdgeToOriginGetter(\n      { // property names\n        origin: 'originY',\n        axis1: 'y1',\n        axis2: 'y2',\n        dimension: 'height'\n      },\n      { // possible values of origin\n        nearest: 'top',\n        center: 'center',\n        farthest: 'bottom'\n      }\n    ),\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} noTransform\n     */\n    _render: function(ctx, noTransform) {\n      ctx.beginPath();\n\n      if (noTransform) {\n        //  Line coords are distances from left-top of canvas to origin of line.\n        //  To render line in a path-group, we need to translate them to\n        //  distances from center of path-group to center of line.\n        var cp = this.getCenterPoint(),\n            offset = this.strokeWidth / 2;\n        ctx.translate(\n          cp.x - (this.strokeLineCap === 'butt' && this.height === 0 ? 0 : offset),\n          cp.y - (this.strokeLineCap === 'butt' && this.width === 0 ? 0 : offset)\n        );\n      }\n\n      if (!this.strokeDashArray || this.strokeDashArray && supportsLineDash) {\n        // move from center (of virtual box) to its left/top corner\n        // we can't assume x1, y1 is top left and x2, y2 is bottom right\n        var p = this.calcLinePoints();\n        ctx.moveTo(p.x1, p.y1);\n        ctx.lineTo(p.x2, p.y2);\n      }\n\n      ctx.lineWidth = this.strokeWidth;\n\n      // TODO: test this\n      // make sure setting \"fill\" changes color of a line\n      // (by copying fillStyle to strokeStyle, since line is stroked, not filled)\n      var origStrokeStyle = ctx.strokeStyle;\n      ctx.strokeStyle = this.stroke || ctx.fillStyle;\n      this.stroke && this._renderStroke(ctx);\n      ctx.strokeStyle = origStrokeStyle;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderDashedStroke: function(ctx) {\n      var p = this.calcLinePoints();\n\n      ctx.beginPath();\n      fabric.util.drawDashedLine(ctx, p.x1, p.y1, p.x2, p.y2, this.strokeDashArray);\n      ctx.closePath();\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @methd toObject\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return extend(this.callSuper('toObject', propertiesToInclude), this.calcLinePoints());\n    },\n\n    /*\n     * Calculate object dimensions from its properties\n     * @private\n     */\n    _getNonTransformedDimensions: function() {\n      var dim = this.callSuper('_getNonTransformedDimensions');\n      if (this.strokeLineCap === 'butt') {\n        if (this.width === 0) {\n          dim.y -= this.strokeWidth;\n        }\n        if (this.height === 0) {\n          dim.x -= this.strokeWidth;\n        }\n      }\n      return dim;\n    },\n\n    /**\n     * Recalculates line points given width and height\n     * @private\n     */\n    calcLinePoints: function() {\n      var xMult = this.x1 <= this.x2 ? -1 : 1,\n          yMult = this.y1 <= this.y2 ? -1 : 1,\n          x1 = (xMult * this.width * 0.5),\n          y1 = (yMult * this.height * 0.5),\n          x2 = (xMult * this.width * -0.5),\n          y2 = (yMult * this.height * -0.5);\n\n      return {\n        x1: x1,\n        x2: x2,\n        y1: y1,\n        y2: y2\n      };\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var markup = this._createBaseSVGMarkup(),\n          p = { x1: this.x1, x2: this.x2, y1: this.y1, y2: this.y2 };\n\n      if (!(this.group && this.group.type === 'path-group')) {\n        p = this.calcLinePoints();\n      }\n      markup.push(\n        '<line ', this.getSvgId(),\n          'x1=\"', p.x1,\n          '\" y1=\"', p.y1,\n          '\" x2=\"', p.x2,\n          '\" y2=\"', p.y2,\n          '\" style=\"', this.getSvgStyles(),\n          '\" transform=\"', this.getSvgTransform(),\n          this.getSvgTransformMatrix(),\n        '\"/>\\n'\n      );\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Line.fromElement})\n   * @static\n   * @memberOf fabric.Line\n   * @see http://www.w3.org/TR/SVG/shapes.html#LineElement\n   */\n  fabric.Line.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x1 y1 x2 y2'.split(' '));\n\n  /**\n   * Returns fabric.Line instance from an SVG element\n   * @static\n   * @memberOf fabric.Line\n   * @param {SVGElement} element Element to parse\n   * @param {Object} [options] Options object\n   * @return {fabric.Line} instance of fabric.Line\n   */\n  fabric.Line.fromElement = function(element, options) {\n    options = options || { };\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Line.ATTRIBUTE_NAMES),\n        points = [\n          parsedAttributes.x1 || 0,\n          parsedAttributes.y1 || 0,\n          parsedAttributes.x2 || 0,\n          parsedAttributes.y2 || 0\n        ];\n    options.originX = 'left';\n    options.originY = 'top';\n    return new fabric.Line(points, extend(parsedAttributes, options));\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns fabric.Line instance from an object representation\n   * @static\n   * @memberOf fabric.Line\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as first argument\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {fabric.Line} instance of fabric.Line\n   */\n  fabric.Line.fromObject = function(object, callback, forceAsync) {\n    function _callback(instance) {\n      delete instance.points;\n      callback && callback(instance);\n    };\n    var options = clone(object, true);\n    options.points = [object.x1, object.y1, object.x2, object.y2];\n    var line = fabric.Object._fromObject('Line', options, _callback, forceAsync, 'points');\n    if (line) {\n      delete line.points;\n    }\n    return line;\n  };\n\n  /**\n   * Produces a function that calculates distance from canvas edge to Line origin.\n   */\n  function makeEdgeToOriginGetter(propertyNames, originValues) {\n    var origin = propertyNames.origin,\n        axis1 = propertyNames.axis1,\n        axis2 = propertyNames.axis2,\n        dimension = propertyNames.dimension,\n        nearest = originValues.nearest,\n        center = originValues.center,\n        farthest = originValues.farthest;\n\n    return function() {\n      switch (this.get(origin)) {\n        case nearest:\n          return Math.min(this.get(axis1), this.get(axis2));\n        case center:\n          return Math.min(this.get(axis1), this.get(axis2)) + (0.5 * this.get(dimension));\n        case farthest:\n          return Math.max(this.get(axis1), this.get(axis2));\n      }\n    };\n\n  }\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      pi = Math.PI,\n      extend = fabric.util.object.extend;\n\n  if (fabric.Circle) {\n    fabric.warn('fabric.Circle is already defined.');\n    return;\n  }\n\n  /**\n   * Circle class\n   * @class fabric.Circle\n   * @extends fabric.Object\n   * @see {@link fabric.Circle#initialize} for constructor definition\n   */\n  fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'circle',\n\n    /**\n     * Radius of this circle\n     * @type Number\n     * @default\n     */\n    radius: 0,\n\n    /**\n     * Start angle of the circle, moving clockwise\n     * @type Number\n     * @default 0\n     */\n    startAngle: 0,\n\n    /**\n     * End angle of the circle\n     * @type Number\n     * @default 2Pi\n     */\n    endAngle: pi * 2,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('radius'),\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     * @return {fabric.Circle} thisArg\n     */\n    initialize: function(options) {\n      this.callSuper('initialize', options);\n      this.set('radius', options && options.radius || 0);\n    },\n\n    /**\n     * @private\n     * @param {String} key\n     * @param {*} value\n     * @return {fabric.Circle} thisArg\n     */\n    _set: function(key, value) {\n      this.callSuper('_set', key, value);\n\n      if (key === 'radius') {\n        this.setRadius(value);\n      }\n\n      return this;\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return this.callSuper('toObject', ['radius', 'startAngle', 'endAngle'].concat(propertiesToInclude));\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var markup = this._createBaseSVGMarkup(), x = 0, y = 0,\n          angle = (this.endAngle - this.startAngle) % ( 2 * pi);\n\n      if (angle === 0) {\n        if (this.group && this.group.type === 'path-group') {\n          x = this.left + this.radius;\n          y = this.top + this.radius;\n        }\n        markup.push(\n          '<circle ', this.getSvgId(),\n            'cx=\"' + x + '\" cy=\"' + y + '\" ',\n            'r=\"', this.radius,\n            '\" style=\"', this.getSvgStyles(),\n            '\" transform=\"', this.getSvgTransform(),\n            ' ', this.getSvgTransformMatrix(),\n          '\"/>\\n'\n        );\n      }\n      else {\n        var startX = Math.cos(this.startAngle) * this.radius,\n            startY = Math.sin(this.startAngle) * this.radius,\n            endX = Math.cos(this.endAngle) * this.radius,\n            endY = Math.sin(this.endAngle) * this.radius,\n            largeFlag = angle > pi ? '1' : '0';\n\n        markup.push(\n          '<path d=\"M ' + startX + ' ' + startY,\n          ' A ' + this.radius + ' ' + this.radius,\n          ' 0 ', +largeFlag + ' 1', ' ' + endX + ' ' + endY,\n          '\" style=\"', this.getSvgStyles(),\n          '\" transform=\"', this.getSvgTransform(),\n          ' ', this.getSvgTransformMatrix(),\n          '\"/>\\n'\n        );\n      }\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx context to render on\n     * @param {Boolean} [noTransform] When true, context is not transformed\n     */\n    _render: function(ctx, noTransform) {\n      ctx.beginPath();\n      ctx.arc(noTransform ? this.left + this.radius : 0,\n              noTransform ? this.top + this.radius : 0,\n              this.radius,\n              this.startAngle,\n              this.endAngle, false);\n      this._renderFill(ctx);\n      this._renderStroke(ctx);\n    },\n\n    /**\n     * Returns horizontal radius of an object (according to how an object is scaled)\n     * @return {Number}\n     */\n    getRadiusX: function() {\n      return this.get('radius') * this.get('scaleX');\n    },\n\n    /**\n     * Returns vertical radius of an object (according to how an object is scaled)\n     * @return {Number}\n     */\n    getRadiusY: function() {\n      return this.get('radius') * this.get('scaleY');\n    },\n\n    /**\n     * Sets radius of an object (and updates width accordingly)\n     * @return {fabric.Circle} thisArg\n     */\n    setRadius: function(value) {\n      this.radius = value;\n      return this.set('width', value * 2).set('height', value * 2);\n    },\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement})\n   * @static\n   * @memberOf fabric.Circle\n   * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement\n   */\n  fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy r'.split(' '));\n\n  /**\n   * Returns {@link fabric.Circle} instance from an SVG element\n   * @static\n   * @memberOf fabric.Circle\n   * @param {SVGElement} element Element to parse\n   * @param {Object} [options] Options object\n   * @throws {Error} If value of `r` attribute is missing or invalid\n   * @return {fabric.Circle} Instance of fabric.Circle\n   */\n  fabric.Circle.fromElement = function(element, options) {\n    options || (options = { });\n\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);\n\n    if (!isValidRadius(parsedAttributes)) {\n      throw new Error('value of `r` attribute is required and can not be negative');\n    }\n\n    parsedAttributes.left = parsedAttributes.left || 0;\n    parsedAttributes.top = parsedAttributes.top || 0;\n\n    var obj = new fabric.Circle(extend(parsedAttributes, options));\n\n    obj.left -= obj.radius;\n    obj.top -= obj.radius;\n    return obj;\n  };\n\n  /**\n   * @private\n   */\n  function isValidRadius(attributes) {\n    return (('radius' in attributes) && (attributes.radius >= 0));\n  }\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns {@link fabric.Circle} instance from an object representation\n   * @static\n   * @memberOf fabric.Circle\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as first argument\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {Object} Instance of fabric.Circle\n   */\n  fabric.Circle.fromObject = function(object, callback, forceAsync) {\n    return fabric.Object._fromObject('Circle', object, callback, forceAsync);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { });\n\n  if (fabric.Triangle) {\n    fabric.warn('fabric.Triangle is already defined');\n    return;\n  }\n\n  /**\n   * Triangle class\n   * @class fabric.Triangle\n   * @extends fabric.Object\n   * @return {fabric.Triangle} thisArg\n   * @see {@link fabric.Triangle#initialize} for constructor definition\n   */\n  fabric.Triangle = fabric.util.createClass(fabric.Object, /** @lends fabric.Triangle.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'triangle',\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     * @return {Object} thisArg\n     */\n    initialize: function(options) {\n      this.callSuper('initialize', options);\n      this.set('width', options && options.width || 100)\n          .set('height', options && options.height || 100);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      var widthBy2 = this.width / 2,\n          heightBy2 = this.height / 2;\n\n      ctx.beginPath();\n      ctx.moveTo(-widthBy2, heightBy2);\n      ctx.lineTo(0, -heightBy2);\n      ctx.lineTo(widthBy2, heightBy2);\n      ctx.closePath();\n\n      this._renderFill(ctx);\n      this._renderStroke(ctx);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderDashedStroke: function(ctx) {\n      var widthBy2 = this.width / 2,\n          heightBy2 = this.height / 2;\n\n      ctx.beginPath();\n      fabric.util.drawDashedLine(ctx, -widthBy2, heightBy2, 0, -heightBy2, this.strokeDashArray);\n      fabric.util.drawDashedLine(ctx, 0, -heightBy2, widthBy2, heightBy2, this.strokeDashArray);\n      fabric.util.drawDashedLine(ctx, widthBy2, heightBy2, -widthBy2, heightBy2, this.strokeDashArray);\n      ctx.closePath();\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var markup = this._createBaseSVGMarkup(),\n          widthBy2 = this.width / 2,\n          heightBy2 = this.height / 2,\n          points = [\n            -widthBy2 + ' ' + heightBy2,\n            '0 ' + -heightBy2,\n            widthBy2 + ' ' + heightBy2\n          ]\n          .join(',');\n\n      markup.push(\n        '<polygon ', this.getSvgId(),\n          'points=\"', points,\n          '\" style=\"', this.getSvgStyles(),\n          '\" transform=\"', this.getSvgTransform(),\n        '\"/>'\n      );\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n  });\n\n  /**\n   * Returns {@link fabric.Triangle} instance from an object representation\n   * @static\n   * @memberOf fabric.Triangle\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as first argument\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {fabric.Triangle}\n   */\n  fabric.Triangle.fromObject = function(object, callback, forceAsync) {\n    return fabric.Object._fromObject('Triangle', object, callback, forceAsync);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      piBy2   = Math.PI * 2,\n      extend = fabric.util.object.extend;\n\n  if (fabric.Ellipse) {\n    fabric.warn('fabric.Ellipse is already defined.');\n    return;\n  }\n\n  /**\n   * Ellipse class\n   * @class fabric.Ellipse\n   * @extends fabric.Object\n   * @return {fabric.Ellipse} thisArg\n   * @see {@link fabric.Ellipse#initialize} for constructor definition\n   */\n  fabric.Ellipse = fabric.util.createClass(fabric.Object, /** @lends fabric.Ellipse.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'ellipse',\n\n    /**\n     * Horizontal radius\n     * @type Number\n     * @default\n     */\n    rx:   0,\n\n    /**\n     * Vertical radius\n     * @type Number\n     * @default\n     */\n    ry:   0,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('rx', 'ry'),\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     * @return {fabric.Ellipse} thisArg\n     */\n    initialize: function(options) {\n      this.callSuper('initialize', options);\n      this.set('rx', options && options.rx || 0);\n      this.set('ry', options && options.ry || 0);\n    },\n\n    /**\n     * @private\n     * @param {String} key\n     * @param {*} value\n     * @return {fabric.Ellipse} thisArg\n     */\n    _set: function(key, value) {\n      this.callSuper('_set', key, value);\n      switch (key) {\n\n        case 'rx':\n          this.rx = value;\n          this.set('width', value * 2);\n          break;\n\n        case 'ry':\n          this.ry = value;\n          this.set('height', value * 2);\n          break;\n\n      }\n      return this;\n    },\n\n    /**\n     * Returns horizontal radius of an object (according to how an object is scaled)\n     * @return {Number}\n     */\n    getRx: function() {\n      return this.get('rx') * this.get('scaleX');\n    },\n\n    /**\n     * Returns Vertical radius of an object (according to how an object is scaled)\n     * @return {Number}\n     */\n    getRy: function() {\n      return this.get('ry') * this.get('scaleY');\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude));\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var markup = this._createBaseSVGMarkup(), x = 0, y = 0;\n      if (this.group && this.group.type === 'path-group') {\n        x = this.left + this.rx;\n        y = this.top + this.ry;\n      }\n      markup.push(\n        '<ellipse ', this.getSvgId(),\n          'cx=\"', x, '\" cy=\"', y, '\" ',\n          'rx=\"', this.rx,\n          '\" ry=\"', this.ry,\n          '\" style=\"', this.getSvgStyles(),\n          '\" transform=\"', this.getSvgTransform(),\n          this.getSvgTransformMatrix(),\n        '\"/>\\n'\n      );\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx context to render on\n     * @param {Boolean} [noTransform] When true, context is not transformed\n     */\n    _render: function(ctx, noTransform) {\n      ctx.beginPath();\n      ctx.save();\n      ctx.transform(1, 0, 0, this.ry / this.rx, 0, 0);\n      ctx.arc(\n        noTransform ? this.left + this.rx : 0,\n        noTransform ? (this.top + this.ry) * this.rx / this.ry : 0,\n        this.rx,\n        0,\n        piBy2,\n        false);\n      ctx.restore();\n      this._renderFill(ctx);\n      this._renderStroke(ctx);\n    },\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Ellipse.fromElement})\n   * @static\n   * @memberOf fabric.Ellipse\n   * @see http://www.w3.org/TR/SVG/shapes.html#EllipseElement\n   */\n  fabric.Ellipse.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy rx ry'.split(' '));\n\n  /**\n   * Returns {@link fabric.Ellipse} instance from an SVG element\n   * @static\n   * @memberOf fabric.Ellipse\n   * @param {SVGElement} element Element to parse\n   * @param {Object} [options] Options object\n   * @return {fabric.Ellipse}\n   */\n  fabric.Ellipse.fromElement = function(element, options) {\n    options || (options = { });\n\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);\n\n    parsedAttributes.left = parsedAttributes.left || 0;\n    parsedAttributes.top = parsedAttributes.top || 0;\n\n    var ellipse = new fabric.Ellipse(extend(parsedAttributes, options));\n\n    ellipse.top -= ellipse.ry;\n    ellipse.left -= ellipse.rx;\n    return ellipse;\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns {@link fabric.Ellipse} instance from an object representation\n   * @static\n   * @memberOf fabric.Ellipse\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as first argument\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {fabric.Ellipse}\n   */\n  fabric.Ellipse.fromObject = function(object, callback, forceAsync) {\n    return fabric.Object._fromObject('Ellipse', object, callback, forceAsync);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend;\n\n  if (fabric.Rect) {\n    fabric.warn('fabric.Rect is already defined');\n    return;\n  }\n\n  /**\n   * Rectangle class\n   * @class fabric.Rect\n   * @extends fabric.Object\n   * @return {fabric.Rect} thisArg\n   * @see {@link fabric.Rect#initialize} for constructor definition\n   */\n  fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ {\n\n    /**\n     * List of properties to consider when checking if state of an object is changed ({@link fabric.Object#hasStateChanged})\n     * as well as for history (undo/redo) purposes\n     * @type Array\n     */\n    stateProperties: fabric.Object.prototype.stateProperties.concat('rx', 'ry'),\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'rect',\n\n    /**\n     * Horizontal border radius\n     * @type Number\n     * @default\n     */\n    rx:   0,\n\n    /**\n     * Vertical border radius\n     * @type Number\n     * @default\n     */\n    ry:   0,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('rx', 'ry'),\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     * @return {Object} thisArg\n     */\n    initialize: function(options) {\n      this.callSuper('initialize', options);\n      this._initRxRy();\n    },\n\n    /**\n     * Initializes rx/ry attributes\n     * @private\n     */\n    _initRxRy: function() {\n      if (this.rx && !this.ry) {\n        this.ry = this.rx;\n      }\n      else if (this.ry && !this.rx) {\n        this.rx = this.ry;\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} noTransform\n     */\n    _render: function(ctx, noTransform) {\n\n      // optimize 1x1 case (used in spray brush)\n      if (this.width === 1 && this.height === 1) {\n        ctx.fillRect(-0.5, -0.5, 1, 1);\n        return;\n      }\n\n      var rx = this.rx ? Math.min(this.rx, this.width / 2) : 0,\n          ry = this.ry ? Math.min(this.ry, this.height / 2) : 0,\n          w = this.width,\n          h = this.height,\n          x = noTransform ? this.left : -this.width / 2,\n          y = noTransform ? this.top : -this.height / 2,\n          isRounded = rx !== 0 || ry !== 0,\n          /* \"magic number\" for bezier approximations of arcs (http://itc.ktu.lt/itc354/Riskus354.pdf) */\n          k = 1 - 0.5522847498;\n      ctx.beginPath();\n\n      ctx.moveTo(x + rx, y);\n\n      ctx.lineTo(x + w - rx, y);\n      isRounded && ctx.bezierCurveTo(x + w - k * rx, y, x + w, y + k * ry, x + w, y + ry);\n\n      ctx.lineTo(x + w, y + h - ry);\n      isRounded && ctx.bezierCurveTo(x + w, y + h - k * ry, x + w - k * rx, y + h, x + w - rx, y + h);\n\n      ctx.lineTo(x + rx, y + h);\n      isRounded && ctx.bezierCurveTo(x + k * rx, y + h, x, y + h - k * ry, x, y + h - ry);\n\n      ctx.lineTo(x, y + ry);\n      isRounded && ctx.bezierCurveTo(x, y + k * ry, x + k * rx, y, x + rx, y);\n\n      ctx.closePath();\n\n      this._renderFill(ctx);\n      this._renderStroke(ctx);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderDashedStroke: function(ctx) {\n      var x = -this.width / 2,\n          y = -this.height / 2,\n          w = this.width,\n          h = this.height;\n\n      ctx.beginPath();\n      fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray);\n      fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray);\n      fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray);\n      fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray);\n      ctx.closePath();\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude));\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var markup = this._createBaseSVGMarkup(), x = this.left, y = this.top;\n      if (!(this.group && this.group.type === 'path-group')) {\n        x = -this.width / 2;\n        y = -this.height / 2;\n      }\n      markup.push(\n        '<rect ', this.getSvgId(),\n          'x=\"', x, '\" y=\"', y,\n          '\" rx=\"', this.get('rx'), '\" ry=\"', this.get('ry'),\n          '\" width=\"', this.width, '\" height=\"', this.height,\n          '\" style=\"', this.getSvgStyles(),\n          '\" transform=\"', this.getSvgTransform(),\n          this.getSvgTransformMatrix(),\n        '\"/>\\n');\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`)\n   * @static\n   * @memberOf fabric.Rect\n   * @see: http://www.w3.org/TR/SVG/shapes.html#RectElement\n   */\n  fabric.Rect.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y rx ry width height'.split(' '));\n\n  /**\n   * Returns {@link fabric.Rect} instance from an SVG element\n   * @static\n   * @memberOf fabric.Rect\n   * @param {SVGElement} element Element to parse\n   * @param {Object} [options] Options object\n   * @return {fabric.Rect} Instance of fabric.Rect\n   */\n  fabric.Rect.fromElement = function(element, options) {\n    if (!element) {\n      return null;\n    }\n    options = options || { };\n\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES);\n\n    parsedAttributes.left = parsedAttributes.left || 0;\n    parsedAttributes.top  = parsedAttributes.top  || 0;\n    var rect = new fabric.Rect(extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));\n    rect.visible = rect.visible && rect.width > 0 && rect.height > 0;\n    return rect;\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns {@link fabric.Rect} instance from an object representation\n   * @static\n   * @memberOf fabric.Rect\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Rect instance is created\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {Object} instance of fabric.Rect\n   */\n  fabric.Rect.fromObject = function(object, callback, forceAsync) {\n    return fabric.Object._fromObject('Rect', object, callback, forceAsync);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      min = fabric.util.array.min,\n      max = fabric.util.array.max,\n      toFixed = fabric.util.toFixed,\n      NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n\n  if (fabric.Polyline) {\n    fabric.warn('fabric.Polyline is already defined');\n    return;\n  }\n\n  /**\n   * Polyline class\n   * @class fabric.Polyline\n   * @extends fabric.Object\n   * @see {@link fabric.Polyline#initialize} for constructor definition\n   */\n  fabric.Polyline = fabric.util.createClass(fabric.Object, /** @lends fabric.Polyline.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'polyline',\n\n    /**\n     * Points array\n     * @type Array\n     * @default\n     */\n    points: null,\n\n    /**\n     * Minimum X from points values, necessary to offset points\n     * @type Number\n     * @default\n     */\n    minX: 0,\n\n    /**\n     * Minimum Y from points values, necessary to offset points\n     * @type Number\n     * @default\n     */\n    minY: 0,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('points'),\n\n    /**\n     * Constructor\n     * @param {Array} points Array of points (where each point is an object with x and y)\n     * @param {Object} [options] Options object\n     * @return {fabric.Polyline} thisArg\n     * @example\n     * var poly = new fabric.Polyline([\n     *     { x: 10, y: 10 },\n     *     { x: 50, y: 30 },\n     *     { x: 40, y: 70 },\n     *     { x: 60, y: 50 },\n     *     { x: 100, y: 150 },\n     *     { x: 40, y: 100 }\n     *   ], {\n     *   stroke: 'red',\n     *   left: 100,\n     *   top: 100\n     * });\n     */\n    initialize: function(points, options) {\n      options = options || {};\n      this.points = points || [];\n      this.callSuper('initialize', options);\n      this._calcDimensions();\n      if (!('top' in options)) {\n        this.top = this.minY;\n      }\n      if (!('left' in options)) {\n        this.left = this.minX;\n      }\n      this.pathOffset = {\n        x: this.minX + this.width / 2,\n        y: this.minY + this.height / 2\n      };\n    },\n\n    /**\n     * @private\n     */\n    _calcDimensions: function() {\n\n      var points = this.points,\n          minX = min(points, 'x'),\n          minY = min(points, 'y'),\n          maxX = max(points, 'x'),\n          maxY = max(points, 'y');\n\n      this.width = (maxX - minX) || 0;\n      this.height = (maxY - minY) || 0;\n      this.minX = minX || 0;\n      this.minY = minY || 0;\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return extend(this.callSuper('toObject', propertiesToInclude), {\n        points: this.points.concat()\n      });\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var points = [],\n          diffX = 0,\n          diffY = 0,\n          markup = this._createBaseSVGMarkup();\n\n      if (!(this.group && this.group.type === 'path-group')) {\n        diffX = this.pathOffset.x;\n        diffY = this.pathOffset.y;\n      }\n\n      for (var i = 0, len = this.points.length; i < len; i++) {\n        points.push(\n          toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), ',',\n          toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), ' '\n        );\n      }\n      markup.push(\n        '<', this.type, ' ', this.getSvgId(),\n          'points=\"', points.join(''),\n          '\" style=\"', this.getSvgStyles(),\n          '\" transform=\"', this.getSvgTransform(),\n          ' ', this.getSvgTransformMatrix(),\n        '\"/>\\n'\n      );\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} noTransform\n     */\n    commonRender: function(ctx, noTransform) {\n      var point, len = this.points.length,\n          x = noTransform ? 0 : this.pathOffset.x,\n          y = noTransform ? 0 : this.pathOffset.y;\n\n      if (!len || isNaN(this.points[len - 1].y)) {\n        // do not draw if no points or odd points\n        // NaN comes from parseFloat of a empty string in parser\n        return false;\n      }\n      ctx.beginPath();\n      ctx.moveTo(this.points[0].x - x, this.points[0].y - y);\n      for (var i = 0; i < len; i++) {\n        point = this.points[i];\n        ctx.lineTo(point.x - x, point.y - y);\n      }\n      return true;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} noTransform\n     */\n    _render: function(ctx, noTransform) {\n      if (!this.commonRender(ctx, noTransform)) {\n        return;\n      }\n      this._renderFill(ctx);\n      this._renderStroke(ctx);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderDashedStroke: function(ctx) {\n      var p1, p2;\n\n      ctx.beginPath();\n      for (var i = 0, len = this.points.length; i < len; i++) {\n        p1 = this.points[i];\n        p2 = this.points[i + 1] || p1;\n        fabric.util.drawDashedLine(ctx, p1.x, p1.y, p2.x, p2.y, this.strokeDashArray);\n      }\n    },\n\n    /**\n     * Returns complexity of an instance\n     * @return {Number} complexity of this instance\n     */\n    complexity: function() {\n      return this.get('points').length;\n    }\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Polyline.fromElement})\n   * @static\n   * @memberOf fabric.Polyline\n   * @see: http://www.w3.org/TR/SVG/shapes.html#PolylineElement\n   */\n  fabric.Polyline.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();\n\n  /**\n   * Returns fabric.Polyline instance from an SVG element\n   * @static\n   * @memberOf fabric.Polyline\n   * @param {SVGElement} element Element to parse\n   * @param {Object} [options] Options object\n   * @return {fabric.Polyline} Instance of fabric.Polyline\n   */\n  fabric.Polyline.fromElement = function(element, options) {\n    if (!element) {\n      return null;\n    }\n    options || (options = { });\n\n    var points = fabric.parsePointsAttribute(element.getAttribute('points')),\n        parsedAttributes = fabric.parseAttributes(element, fabric.Polyline.ATTRIBUTE_NAMES);\n\n    return new fabric.Polyline(points, fabric.util.object.extend(parsedAttributes, options));\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns fabric.Polyline instance from an object representation\n   * @static\n   * @memberOf fabric.Polyline\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {fabric.Polyline} Instance of fabric.Polyline\n   */\n  fabric.Polyline.fromObject = function(object, callback, forceAsync) {\n    return fabric.Object._fromObject('Polyline', object, callback, forceAsync, 'points');\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend;\n\n  if (fabric.Polygon) {\n    fabric.warn('fabric.Polygon is already defined');\n    return;\n  }\n\n  /**\n   * Polygon class\n   * @class fabric.Polygon\n   * @extends fabric.Polyline\n   * @see {@link fabric.Polygon#initialize} for constructor definition\n   */\n  fabric.Polygon = fabric.util.createClass(fabric.Polyline, /** @lends fabric.Polygon.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'polygon',\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} noTransform\n     */\n    _render: function(ctx, noTransform) {\n      if (!this.commonRender(ctx, noTransform)) {\n        return;\n      }\n      ctx.closePath();\n      this._renderFill(ctx);\n      this._renderStroke(ctx);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderDashedStroke: function(ctx) {\n      this.callSuper('_renderDashedStroke', ctx);\n      ctx.closePath();\n    },\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`)\n   * @static\n   * @memberOf fabric.Polygon\n   * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement\n   */\n  fabric.Polygon.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();\n\n  /**\n   * Returns {@link fabric.Polygon} instance from an SVG element\n   * @static\n   * @memberOf fabric.Polygon\n   * @param {SVGElement} element Element to parse\n   * @param {Object} [options] Options object\n   * @return {fabric.Polygon} Instance of fabric.Polygon\n   */\n  fabric.Polygon.fromElement = function(element, options) {\n    if (!element) {\n      return null;\n    }\n\n    options || (options = { });\n\n    var points = fabric.parsePointsAttribute(element.getAttribute('points')),\n        parsedAttributes = fabric.parseAttributes(element, fabric.Polygon.ATTRIBUTE_NAMES);\n\n    return new fabric.Polygon(points, extend(parsedAttributes, options));\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns fabric.Polygon instance from an object representation\n   * @static\n   * @memberOf fabric.Polygon\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {fabric.Polygon} Instance of fabric.Polygon\n   */\n  fabric.Polygon.fromObject = function(object, callback, forceAsync) {\n    return fabric.Object._fromObject('Polygon', object, callback, forceAsync, 'points');\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      min = fabric.util.array.min,\n      max = fabric.util.array.max,\n      extend = fabric.util.object.extend,\n      _toString = Object.prototype.toString,\n      drawArc = fabric.util.drawArc,\n      commandLengths = {\n        m: 2,\n        l: 2,\n        h: 1,\n        v: 1,\n        c: 6,\n        s: 4,\n        q: 4,\n        t: 2,\n        a: 7\n      },\n      repeatedCommands = {\n        m: 'l',\n        M: 'L'\n      };\n\n  if (fabric.Path) {\n    fabric.warn('fabric.Path is already defined');\n    return;\n  }\n\n  /**\n   * Path class\n   * @class fabric.Path\n   * @extends fabric.Object\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#path_and_pathgroup}\n   * @see {@link fabric.Path#initialize} for constructor definition\n   */\n  fabric.Path = fabric.util.createClass(fabric.Object, /** @lends fabric.Path.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'path',\n\n    /**\n     * Array of path points\n     * @type Array\n     * @default\n     */\n    path: null,\n\n    /**\n     * Minimum X from points values, necessary to offset points\n     * @type Number\n     * @default\n     */\n    minX: 0,\n\n    /**\n     * Minimum Y from points values, necessary to offset points\n     * @type Number\n     * @default\n     */\n    minY: 0,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('path', 'fillRule'),\n\n    stateProperties: fabric.Object.prototype.stateProperties.concat('path'),\n\n    /**\n     * Constructor\n     * @param {Array|String} path Path data (sequence of coordinates and corresponding \"command\" tokens)\n     * @param {Object} [options] Options object\n     * @return {fabric.Path} thisArg\n     */\n    initialize: function(path, options) {\n      options = options || { };\n      this.callSuper('initialize', options);\n\n      if (!path) {\n        path = [];\n      }\n\n      var fromArray = _toString.call(path) === '[object Array]';\n\n      this.path = fromArray\n        ? path\n        // one of commands (m,M,l,L,q,Q,c,C,etc.) followed by non-command characters (i.e. command values)\n        : path.match && path.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi);\n\n      if (!this.path) {\n        return;\n      }\n\n      if (!fromArray) {\n        this.path = this._parsePath();\n      }\n\n      this._setPositionDimensions(options);\n    },\n\n    /**\n     * @private\n     * @param {Object} options Options object\n     */\n    _setPositionDimensions: function(options) {\n      var calcDim = this._parseDimensions();\n\n      this.minX = calcDim.left;\n      this.minY = calcDim.top;\n      this.width = calcDim.width;\n      this.height = calcDim.height;\n\n      if (typeof options.left === 'undefined') {\n        this.left = calcDim.left + (this.originX === 'center'\n          ? this.width / 2\n          : this.originX === 'right'\n            ? this.width\n            : 0);\n      }\n\n      if (typeof options.top === 'undefined') {\n        this.top = calcDim.top + (this.originY === 'center'\n          ? this.height / 2\n          : this.originY === 'bottom'\n            ? this.height\n            : 0);\n      }\n\n      this.pathOffset = this.pathOffset || {\n        x: this.minX + this.width / 2,\n        y: this.minY + this.height / 2\n      };\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx context to render path on\n     */\n    _renderPathCommands: function(ctx) {\n      var current, // current instruction\n          previous = null,\n          subpathStartX = 0,\n          subpathStartY = 0,\n          x = 0, // current x\n          y = 0, // current y\n          controlX = 0, // current control point x\n          controlY = 0, // current control point y\n          tempX,\n          tempY,\n          l = -this.pathOffset.x,\n          t = -this.pathOffset.y;\n\n      if (this.group && this.group.type === 'path-group') {\n        l = 0;\n        t = 0;\n      }\n\n      ctx.beginPath();\n\n      for (var i = 0, len = this.path.length; i < len; ++i) {\n\n        current = this.path[i];\n\n        switch (current[0]) { // first letter\n\n          case 'l': // lineto, relative\n            x += current[1];\n            y += current[2];\n            ctx.lineTo(x + l, y + t);\n            break;\n\n          case 'L': // lineto, absolute\n            x = current[1];\n            y = current[2];\n            ctx.lineTo(x + l, y + t);\n            break;\n\n          case 'h': // horizontal lineto, relative\n            x += current[1];\n            ctx.lineTo(x + l, y + t);\n            break;\n\n          case 'H': // horizontal lineto, absolute\n            x = current[1];\n            ctx.lineTo(x + l, y + t);\n            break;\n\n          case 'v': // vertical lineto, relative\n            y += current[1];\n            ctx.lineTo(x + l, y + t);\n            break;\n\n          case 'V': // verical lineto, absolute\n            y = current[1];\n            ctx.lineTo(x + l, y + t);\n            break;\n\n          case 'm': // moveTo, relative\n            x += current[1];\n            y += current[2];\n            subpathStartX = x;\n            subpathStartY = y;\n            ctx.moveTo(x + l, y + t);\n            break;\n\n          case 'M': // moveTo, absolute\n            x = current[1];\n            y = current[2];\n            subpathStartX = x;\n            subpathStartY = y;\n            ctx.moveTo(x + l, y + t);\n            break;\n\n          case 'c': // bezierCurveTo, relative\n            tempX = x + current[5];\n            tempY = y + current[6];\n            controlX = x + current[3];\n            controlY = y + current[4];\n            ctx.bezierCurveTo(\n              x + current[1] + l, // x1\n              y + current[2] + t, // y1\n              controlX + l, // x2\n              controlY + t, // y2\n              tempX + l,\n              tempY + t\n            );\n            x = tempX;\n            y = tempY;\n            break;\n\n          case 'C': // bezierCurveTo, absolute\n            x = current[5];\n            y = current[6];\n            controlX = current[3];\n            controlY = current[4];\n            ctx.bezierCurveTo(\n              current[1] + l,\n              current[2] + t,\n              controlX + l,\n              controlY + t,\n              x + l,\n              y + t\n            );\n            break;\n\n          case 's': // shorthand cubic bezierCurveTo, relative\n\n            // transform to absolute x,y\n            tempX = x + current[3];\n            tempY = y + current[4];\n\n            if (previous[0].match(/[CcSs]/) === null) {\n              // If there is no previous command or if the previous command was not a C, c, S, or s,\n              // the control point is coincident with the current point\n              controlX = x;\n              controlY = y;\n            }\n            else {\n              // calculate reflection of previous control points\n              controlX = 2 * x - controlX;\n              controlY = 2 * y - controlY;\n            }\n\n            ctx.bezierCurveTo(\n              controlX + l,\n              controlY + t,\n              x + current[1] + l,\n              y + current[2] + t,\n              tempX + l,\n              tempY + t\n            );\n            // set control point to 2nd one of this command\n            // \"... the first control point is assumed to be\n            // the reflection of the second control point on\n            // the previous command relative to the current point.\"\n            controlX = x + current[1];\n            controlY = y + current[2];\n\n            x = tempX;\n            y = tempY;\n            break;\n\n          case 'S': // shorthand cubic bezierCurveTo, absolute\n            tempX = current[3];\n            tempY = current[4];\n            if (previous[0].match(/[CcSs]/) === null) {\n              // If there is no previous command or if the previous command was not a C, c, S, or s,\n              // the control point is coincident with the current point\n              controlX = x;\n              controlY = y;\n            }\n            else {\n              // calculate reflection of previous control points\n              controlX = 2 * x - controlX;\n              controlY = 2 * y - controlY;\n            }\n            ctx.bezierCurveTo(\n              controlX + l,\n              controlY + t,\n              current[1] + l,\n              current[2] + t,\n              tempX + l,\n              tempY + t\n            );\n            x = tempX;\n            y = tempY;\n\n            // set control point to 2nd one of this command\n            // \"... the first control point is assumed to be\n            // the reflection of the second control point on\n            // the previous command relative to the current point.\"\n            controlX = current[1];\n            controlY = current[2];\n\n            break;\n\n          case 'q': // quadraticCurveTo, relative\n            // transform to absolute x,y\n            tempX = x + current[3];\n            tempY = y + current[4];\n\n            controlX = x + current[1];\n            controlY = y + current[2];\n\n            ctx.quadraticCurveTo(\n              controlX + l,\n              controlY + t,\n              tempX + l,\n              tempY + t\n            );\n            x = tempX;\n            y = tempY;\n            break;\n\n          case 'Q': // quadraticCurveTo, absolute\n            tempX = current[3];\n            tempY = current[4];\n\n            ctx.quadraticCurveTo(\n              current[1] + l,\n              current[2] + t,\n              tempX + l,\n              tempY + t\n            );\n            x = tempX;\n            y = tempY;\n            controlX = current[1];\n            controlY = current[2];\n            break;\n\n          case 't': // shorthand quadraticCurveTo, relative\n\n            // transform to absolute x,y\n            tempX = x + current[1];\n            tempY = y + current[2];\n\n            if (previous[0].match(/[QqTt]/) === null) {\n              // If there is no previous command or if the previous command was not a Q, q, T or t,\n              // assume the control point is coincident with the current point\n              controlX = x;\n              controlY = y;\n            }\n            else {\n              // calculate reflection of previous control point\n              controlX = 2 * x - controlX;\n              controlY = 2 * y - controlY;\n            }\n\n            ctx.quadraticCurveTo(\n              controlX + l,\n              controlY + t,\n              tempX + l,\n              tempY + t\n            );\n            x = tempX;\n            y = tempY;\n\n            break;\n\n          case 'T':\n            tempX = current[1];\n            tempY = current[2];\n\n            if (previous[0].match(/[QqTt]/) === null) {\n              // If there is no previous command or if the previous command was not a Q, q, T or t,\n              // assume the control point is coincident with the current point\n              controlX = x;\n              controlY = y;\n            }\n            else {\n              // calculate reflection of previous control point\n              controlX = 2 * x - controlX;\n              controlY = 2 * y - controlY;\n            }\n            ctx.quadraticCurveTo(\n              controlX + l,\n              controlY + t,\n              tempX + l,\n              tempY + t\n            );\n            x = tempX;\n            y = tempY;\n            break;\n\n          case 'a':\n            // TODO: optimize this\n            drawArc(ctx, x + l, y + t, [\n              current[1],\n              current[2],\n              current[3],\n              current[4],\n              current[5],\n              current[6] + x + l,\n              current[7] + y + t\n            ]);\n            x += current[6];\n            y += current[7];\n            break;\n\n          case 'A':\n            // TODO: optimize this\n            drawArc(ctx, x + l, y + t, [\n              current[1],\n              current[2],\n              current[3],\n              current[4],\n              current[5],\n              current[6] + l,\n              current[7] + t\n            ]);\n            x = current[6];\n            y = current[7];\n            break;\n\n          case 'z':\n          case 'Z':\n            x = subpathStartX;\n            y = subpathStartY;\n            ctx.closePath();\n            break;\n        }\n        previous = current;\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx context to render path on\n     */\n    _render: function(ctx) {\n      this._renderPathCommands(ctx);\n      this._renderFill(ctx);\n      this._renderStroke(ctx);\n    },\n\n    /**\n     * Returns string representation of an instance\n     * @return {String} string representation of an instance\n     */\n    toString: function() {\n      return '#<fabric.Path (' + this.complexity() +\n        '): { \"top\": ' + this.top + ', \"left\": ' + this.left + ' }>';\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var o = extend(this.callSuper('toObject', ['sourcePath', 'pathOffset'].concat(propertiesToInclude)), {\n        path: this.path.map(function(item) { return item.slice(); }),\n        top: this.top,\n        left: this.left,\n      });\n      return o;\n    },\n\n    /**\n     * Returns dataless object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toDatalessObject: function(propertiesToInclude) {\n      var o = this.toObject(propertiesToInclude);\n      if (this.sourcePath) {\n        o.path = this.sourcePath;\n      }\n      delete o.sourcePath;\n      return o;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var chunks = [],\n          markup = this._createBaseSVGMarkup(), addTransform = '';\n\n      for (var i = 0, len = this.path.length; i < len; i++) {\n        chunks.push(this.path[i].join(' '));\n      }\n      var path = chunks.join(' ');\n      if (!(this.group && this.group.type === 'path-group')) {\n        addTransform = ' translate(' + (-this.pathOffset.x) + ', ' + (-this.pathOffset.y) + ') ';\n      }\n      markup.push(\n        '<path ', this.getSvgId(),\n          'd=\"', path,\n          '\" style=\"', this.getSvgStyles(),\n          '\" transform=\"', this.getSvgTransform(), addTransform,\n          this.getSvgTransformMatrix(), '\" stroke-linecap=\"round\" ',\n        '/>\\n'\n      );\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns number representation of an instance complexity\n     * @return {Number} complexity of this instance\n     */\n    complexity: function() {\n      return this.path.length;\n    },\n\n    /**\n     * @private\n     */\n    _parsePath: function() {\n      var result = [],\n          coords = [],\n          currentPath,\n          parsed,\n          re = /([-+]?((\\d+\\.\\d+)|((\\d+)|(\\.\\d+)))(?:e[-+]?\\d+)?)/ig,\n          match,\n          coordsStr;\n\n      for (var i = 0, coordsParsed, len = this.path.length; i < len; i++) {\n        currentPath = this.path[i];\n\n        coordsStr = currentPath.slice(1).trim();\n        coords.length = 0;\n\n        while ((match = re.exec(coordsStr))) {\n          coords.push(match[0]);\n        }\n\n        coordsParsed = [currentPath.charAt(0)];\n\n        for (var j = 0, jlen = coords.length; j < jlen; j++) {\n          parsed = parseFloat(coords[j]);\n          if (!isNaN(parsed)) {\n            coordsParsed.push(parsed);\n          }\n        }\n\n        var command = coordsParsed[0],\n            commandLength = commandLengths[command.toLowerCase()],\n            repeatedCommand = repeatedCommands[command] || command;\n\n        if (coordsParsed.length - 1 > commandLength) {\n          for (var k = 1, klen = coordsParsed.length; k < klen; k += commandLength) {\n            result.push([command].concat(coordsParsed.slice(k, k + commandLength)));\n            command = repeatedCommand;\n          }\n        }\n        else {\n          result.push(coordsParsed);\n        }\n      }\n\n      return result;\n    },\n\n    /**\n     * @private\n     */\n    _parseDimensions: function() {\n\n      var aX = [],\n          aY = [],\n          current, // current instruction\n          previous = null,\n          subpathStartX = 0,\n          subpathStartY = 0,\n          x = 0, // current x\n          y = 0, // current y\n          controlX = 0, // current control point x\n          controlY = 0, // current control point y\n          tempX,\n          tempY,\n          bounds;\n\n      for (var i = 0, len = this.path.length; i < len; ++i) {\n\n        current = this.path[i];\n\n        switch (current[0]) { // first letter\n\n          case 'l': // lineto, relative\n            x += current[1];\n            y += current[2];\n            bounds = [];\n            break;\n\n          case 'L': // lineto, absolute\n            x = current[1];\n            y = current[2];\n            bounds = [];\n            break;\n\n          case 'h': // horizontal lineto, relative\n            x += current[1];\n            bounds = [];\n            break;\n\n          case 'H': // horizontal lineto, absolute\n            x = current[1];\n            bounds = [];\n            break;\n\n          case 'v': // vertical lineto, relative\n            y += current[1];\n            bounds = [];\n            break;\n\n          case 'V': // verical lineto, absolute\n            y = current[1];\n            bounds = [];\n            break;\n\n          case 'm': // moveTo, relative\n            x += current[1];\n            y += current[2];\n            subpathStartX = x;\n            subpathStartY = y;\n            bounds = [];\n            break;\n\n          case 'M': // moveTo, absolute\n            x = current[1];\n            y = current[2];\n            subpathStartX = x;\n            subpathStartY = y;\n            bounds = [];\n            break;\n\n          case 'c': // bezierCurveTo, relative\n            tempX = x + current[5];\n            tempY = y + current[6];\n            controlX = x + current[3];\n            controlY = y + current[4];\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              x + current[1], // x1\n              y + current[2], // y1\n              controlX, // x2\n              controlY, // y2\n              tempX,\n              tempY\n            );\n            x = tempX;\n            y = tempY;\n            break;\n\n          case 'C': // bezierCurveTo, absolute\n            controlX = current[3];\n            controlY = current[4];\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              current[1],\n              current[2],\n              controlX,\n              controlY,\n              current[5],\n              current[6]\n            );\n            x = current[5];\n            y = current[6];\n            break;\n\n          case 's': // shorthand cubic bezierCurveTo, relative\n\n            // transform to absolute x,y\n            tempX = x + current[3];\n            tempY = y + current[4];\n\n            if (previous[0].match(/[CcSs]/) === null) {\n              // If there is no previous command or if the previous command was not a C, c, S, or s,\n              // the control point is coincident with the current point\n              controlX = x;\n              controlY = y;\n            }\n            else {\n              // calculate reflection of previous control points\n              controlX = 2 * x - controlX;\n              controlY = 2 * y - controlY;\n            }\n\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              controlX,\n              controlY,\n              x + current[1],\n              y + current[2],\n              tempX,\n              tempY\n            );\n            // set control point to 2nd one of this command\n            // \"... the first control point is assumed to be\n            // the reflection of the second control point on\n            // the previous command relative to the current point.\"\n            controlX = x + current[1];\n            controlY = y + current[2];\n            x = tempX;\n            y = tempY;\n            break;\n\n          case 'S': // shorthand cubic bezierCurveTo, absolute\n            tempX = current[3];\n            tempY = current[4];\n            if (previous[0].match(/[CcSs]/) === null) {\n              // If there is no previous command or if the previous command was not a C, c, S, or s,\n              // the control point is coincident with the current point\n              controlX = x;\n              controlY = y;\n            }\n            else {\n              // calculate reflection of previous control points\n              controlX = 2 * x - controlX;\n              controlY = 2 * y - controlY;\n            }\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              controlX,\n              controlY,\n              current[1],\n              current[2],\n              tempX,\n              tempY\n            );\n            x = tempX;\n            y = tempY;\n            // set control point to 2nd one of this command\n            // \"... the first control point is assumed to be\n            // the reflection of the second control point on\n            // the previous command relative to the current point.\"\n            controlX = current[1];\n            controlY = current[2];\n            break;\n\n          case 'q': // quadraticCurveTo, relative\n            // transform to absolute x,y\n            tempX = x + current[3];\n            tempY = y + current[4];\n            controlX = x + current[1];\n            controlY = y + current[2];\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              controlX,\n              controlY,\n              controlX,\n              controlY,\n              tempX,\n              tempY\n            );\n            x = tempX;\n            y = tempY;\n            break;\n\n          case 'Q': // quadraticCurveTo, absolute\n            controlX = current[1];\n            controlY = current[2];\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              controlX,\n              controlY,\n              controlX,\n              controlY,\n              current[3],\n              current[4]\n            );\n            x = current[3];\n            y = current[4];\n            break;\n\n          case 't': // shorthand quadraticCurveTo, relative\n            // transform to absolute x,y\n            tempX = x + current[1];\n            tempY = y + current[2];\n            if (previous[0].match(/[QqTt]/) === null) {\n              // If there is no previous command or if the previous command was not a Q, q, T or t,\n              // assume the control point is coincident with the current point\n              controlX = x;\n              controlY = y;\n            }\n            else {\n              // calculate reflection of previous control point\n              controlX = 2 * x - controlX;\n              controlY = 2 * y - controlY;\n            }\n\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              controlX,\n              controlY,\n              controlX,\n              controlY,\n              tempX,\n              tempY\n            );\n            x = tempX;\n            y = tempY;\n\n            break;\n\n          case 'T':\n            tempX = current[1];\n            tempY = current[2];\n\n            if (previous[0].match(/[QqTt]/) === null) {\n              // If there is no previous command or if the previous command was not a Q, q, T or t,\n              // assume the control point is coincident with the current point\n              controlX = x;\n              controlY = y;\n            }\n            else {\n              // calculate reflection of previous control point\n              controlX = 2 * x - controlX;\n              controlY = 2 * y - controlY;\n            }\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              controlX,\n              controlY,\n              controlX,\n              controlY,\n              tempX,\n              tempY\n            );\n            x = tempX;\n            y = tempY;\n            break;\n\n          case 'a':\n            // TODO: optimize this\n            bounds = fabric.util.getBoundsOfArc(x, y,\n              current[1],\n              current[2],\n              current[3],\n              current[4],\n              current[5],\n              current[6] + x,\n              current[7] + y\n            );\n            x += current[6];\n            y += current[7];\n            break;\n\n          case 'A':\n            // TODO: optimize this\n            bounds = fabric.util.getBoundsOfArc(x, y,\n              current[1],\n              current[2],\n              current[3],\n              current[4],\n              current[5],\n              current[6],\n              current[7]\n            );\n            x = current[6];\n            y = current[7];\n            break;\n\n          case 'z':\n          case 'Z':\n            x = subpathStartX;\n            y = subpathStartY;\n            break;\n        }\n        previous = current;\n        bounds.forEach(function (point) {\n          aX.push(point.x);\n          aY.push(point.y);\n        });\n        aX.push(x);\n        aY.push(y);\n      }\n\n      var minX = min(aX) || 0,\n          minY = min(aY) || 0,\n          maxX = max(aX) || 0,\n          maxY = max(aY) || 0,\n          deltaX = maxX - minX,\n          deltaY = maxY - minY,\n\n          o = {\n            left: minX,\n            top: minY,\n            width: deltaX,\n            height: deltaY\n          };\n\n      return o;\n    }\n  });\n\n  /**\n   * Creates an instance of fabric.Path from an object\n   * @static\n   * @memberOf fabric.Path\n   * @param {Object} object\n   * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   */\n  fabric.Path.fromObject = function(object, callback, forceAsync) {\n    // remove this pattern rom 2.0, accept just object.\n    var path;\n    if (typeof object.path === 'string') {\n      fabric.loadSVGFromURL(object.path, function (elements) {\n        var pathUrl = object.path;\n        path = elements[0];\n        delete object.path;\n\n        path.setOptions(object);\n        path.setSourcePath(pathUrl);\n\n        callback && callback(path);\n      });\n    }\n    else {\n      return fabric.Object._fromObject('Path', object, callback, forceAsync, 'path');\n    }\n  };\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by `fabric.Path.fromElement`)\n   * @static\n   * @memberOf fabric.Path\n   * @see http://www.w3.org/TR/SVG/paths.html#PathElement\n   */\n  fabric.Path.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(['d']);\n\n  /**\n   * Creates an instance of fabric.Path from an SVG <path> element\n   * @static\n   * @memberOf fabric.Path\n   * @param {SVGElement} element to parse\n   * @param {Function} callback Callback to invoke when an fabric.Path instance is created\n   * @param {Object} [options] Options object\n   */\n  fabric.Path.fromElement = function(element, callback, options) {\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES);\n    callback && callback(new fabric.Path(parsedAttributes.d, extend(parsedAttributes, options)));\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Indicates that instances of this type are async\n   * @static\n   * @memberOf fabric.Path\n   * @type Boolean\n   * @default\n   */\n  fabric.Path.async = true;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend;\n\n  if (fabric.PathGroup) {\n    fabric.warn('fabric.PathGroup is already defined');\n    return;\n  }\n\n  /**\n   * Path group class\n   * @class fabric.PathGroup\n   * @extends fabric.Path\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#path_and_pathgroup}\n   * @see {@link fabric.PathGroup#initialize} for constructor definition\n   */\n  fabric.PathGroup = fabric.util.createClass(fabric.Object, /** @lends fabric.PathGroup.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'path-group',\n\n    /**\n     * Fill value\n     * @type String\n     * @default\n     */\n    fill: '',\n\n    /**\n     * Pathgroups are container, do not render anything on theyr own, ence no cache properties\n     * @type Boolean\n     * @default\n     */\n    cacheProperties: [],\n\n    /**\n     * Constructor\n     * @param {Array} paths\n     * @param {Object} [options] Options object\n     * @return {fabric.PathGroup} thisArg\n     */\n    initialize: function(paths, options) {\n\n      options = options || { };\n      this.paths = paths || [];\n\n      for (var i = this.paths.length; i--;) {\n        this.paths[i].group = this;\n      }\n\n      if (options.toBeParsed) {\n        this.parseDimensionsFromPaths(options);\n        delete options.toBeParsed;\n      }\n      this.setOptions(options);\n      this.setCoords();\n    },\n\n    /**\n     * Calculate width and height based on paths contained\n     */\n    parseDimensionsFromPaths: function(options) {\n      var points, p, xC = [], yC = [], path, height, width,\n          m;\n      for (var j = this.paths.length; j--;) {\n        path = this.paths[j];\n        height = path.height + path.strokeWidth;\n        width = path.width + path.strokeWidth;\n        points = [\n          { x: path.left, y: path.top },\n          { x: path.left + width, y: path.top },\n          { x: path.left, y: path.top + height },\n          { x: path.left + width, y: path.top + height }\n        ];\n        m = this.paths[j].transformMatrix;\n        for (var i = 0; i < points.length; i++) {\n          p = points[i];\n          if (m) {\n            p = fabric.util.transformPoint(p, m, false);\n          }\n          xC.push(p.x);\n          yC.push(p.y);\n        }\n      }\n      options.width = Math.max.apply(null, xC);\n      options.height = Math.max.apply(null, yC);\n    },\n\n    /**\n     * Execute the drawing operation for an object on a specified context\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} [noTransform] When true, context is not transformed\n     */\n    drawObject: function(ctx) {\n      ctx.save();\n      ctx.translate(-this.width / 2, -this.height / 2);\n      for (var i = 0, l = this.paths.length; i < l; ++i) {\n        this.paths[i].render(ctx, true);\n      }\n      ctx.restore();\n    },\n\n    /**\n     * Decide if the object should cache or not.\n     * objectCaching is a global flag, wins over everything\n     * needsItsOwnCache should be used when the object drawing method requires\n     * a cache step. None of the fabric classes requires it.\n     * Generally you do not cache objects in groups because the group outside is cached.\n     * @return {Boolean}\n     */\n    shouldCache: function() {\n      var parentCache = this.objectCaching && (!this.group || this.needsItsOwnCache() || !this.group.isCaching());\n      this.caching = parentCache;\n      if (parentCache) {\n        for (var i = 0, len = this.paths.length; i < len; i++) {\n          if (this.paths[i].willDrawShadow()) {\n            this.caching = false;\n            return false;\n          }\n        }\n      }\n      return parentCache;\n    },\n\n    /**\n     * Check if this object or a child object will cast a shadow\n     * @return {Boolean}\n     */\n    willDrawShadow: function() {\n      if (this.shadow) {\n        return true;\n      }\n      for (var i = 0, len = this.paths.length; i < len; i++) {\n        if (this.paths[i].willDrawShadow()) {\n          return true;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Check if this group or its parent group are caching, recursively up\n     * @return {Boolean}\n     */\n    isCaching: function() {\n      return this.caching || this.group && this.group.isCaching();\n    },\n\n    /**\n     * Check if cache is dirty\n     */\n    isCacheDirty: function() {\n      if (this.callSuper('isCacheDirty')) {\n        return true;\n      }\n      if (!this.statefullCache) {\n        return false;\n      }\n      for (var i = 0, len = this.paths.length; i < len; i++) {\n        if (this.paths[i].isCacheDirty(true)) {\n          if (this._cacheCanvas) {\n            var x = this.cacheWidth / this.zoomX, y = this.cacheHeight / this.zoomY;\n            this._cacheContext.clearRect(-x / 2, -y / 2, x, y);\n          }\n          return true;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Sets certain property to a certain value\n     * @param {String} prop\n     * @param {*} value\n     * @return {fabric.PathGroup} thisArg\n     */\n    _set: function(prop, value) {\n\n      if (prop === 'fill' && value && this.isSameColor()) {\n        var i = this.paths.length;\n        while (i--) {\n          this.paths[i]._set(prop, value);\n        }\n      }\n\n      return this.callSuper('_set', prop, value);\n    },\n\n    /**\n     * Returns object representation of this path group\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var pathsToObject = this.paths.map(function(path) {\n        var originalDefaults = path.includeDefaultValues;\n        path.includeDefaultValues = path.group.includeDefaultValues;\n        var obj = path.toObject(propertiesToInclude);\n        path.includeDefaultValues = originalDefaults;\n        return obj;\n      });\n      var o = extend(this.callSuper('toObject', ['sourcePath'].concat(propertiesToInclude)), {\n        paths: pathsToObject\n      });\n      return o;\n    },\n\n    /**\n     * Returns dataless object representation of this path group\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} dataless object representation of an instance\n     */\n    toDatalessObject: function(propertiesToInclude) {\n      var o = this.toObject(propertiesToInclude);\n      if (this.sourcePath) {\n        o.paths = this.sourcePath;\n      }\n      return o;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var objects = this.getObjects(),\n          p = this.getPointByOrigin('left', 'top'),\n          translatePart = 'translate(' + p.x + ' ' + p.y + ')',\n          markup = this._createBaseSVGMarkup();\n      markup.push(\n        '<g ', this.getSvgId(),\n        'style=\"', this.getSvgStyles(), '\" ',\n        'transform=\"', this.getSvgTransformMatrix(), translatePart, this.getSvgTransform(), '\" ',\n        '>\\n'\n      );\n\n      for (var i = 0, len = objects.length; i < len; i++) {\n        markup.push('\\t', objects[i].toSVG(reviver));\n      }\n      markup.push('</g>\\n');\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns a string representation of this path group\n     * @return {String} string representation of an object\n     */\n    toString: function() {\n      return '#<fabric.PathGroup (' + this.complexity() +\n        '): { top: ' + this.top + ', left: ' + this.left + ' }>';\n    },\n\n    /**\n     * Returns true if all paths in this group are of same color\n     * @return {Boolean} true if all paths are of the same color (`fill`)\n     */\n    isSameColor: function() {\n      var firstPathFill = this.getObjects()[0].get('fill') || '';\n      if (typeof firstPathFill !== 'string') {\n        return false;\n      }\n      firstPathFill = firstPathFill.toLowerCase();\n      return this.getObjects().every(function(path) {\n        var pathFill = path.get('fill') || '';\n        return typeof pathFill === 'string' && (pathFill).toLowerCase() === firstPathFill;\n      });\n    },\n\n    /**\n     * Returns number representation of object's complexity\n     * @return {Number} complexity\n     */\n    complexity: function() {\n      return this.paths.reduce(function(total, path) {\n        return total + ((path && path.complexity) ? path.complexity() : 0);\n      }, 0);\n    },\n\n    /**\n     * Returns all paths in this path group\n     * @return {Array} array of path objects included in this path group\n     */\n    getObjects: function() {\n      return this.paths;\n    }\n  });\n\n  /**\n   * Creates fabric.PathGroup instance from an object representation\n   * @static\n   * @memberOf fabric.PathGroup\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.PathGroup instance is created\n   */\n  fabric.PathGroup.fromObject = function(object, callback) {\n    var originalPaths = object.paths;\n    delete object.paths;\n    if (typeof originalPaths === 'string') {\n      fabric.loadSVGFromURL(originalPaths, function (elements) {\n        var pathUrl = originalPaths;\n        var pathGroup = fabric.util.groupSVGElements(elements, object, pathUrl);\n        object.paths = originalPaths;\n        callback(pathGroup);\n      });\n    }\n    else {\n      fabric.util.enlivenObjects(originalPaths, function(enlivenedObjects) {\n        var pathGroup = new fabric.PathGroup(enlivenedObjects, object);\n        object.paths = originalPaths;\n        callback(pathGroup);\n      });\n    }\n  };\n\n  /**\n   * Indicates that instances of this type are async\n   * @static\n   * @memberOf fabric.PathGroup\n   * @type Boolean\n   * @default\n   */\n  fabric.PathGroup.async = true;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      min = fabric.util.array.min,\n      max = fabric.util.array.max;\n\n  if (fabric.Group) {\n    return;\n  }\n\n  // lock-related properties, for use in fabric.Group#get\n  // to enable locking behavior on group\n  // when one of its objects has lock-related properties set\n  var _lockProperties = {\n    lockMovementX:  true,\n    lockMovementY:  true,\n    lockRotation:   true,\n    lockScalingX:   true,\n    lockScalingY:   true,\n    lockUniScaling: true\n  };\n\n  /**\n   * Group class\n   * @class fabric.Group\n   * @extends fabric.Object\n   * @mixes fabric.Collection\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#groups}\n   * @see {@link fabric.Group#initialize} for constructor definition\n   */\n  fabric.Group = fabric.util.createClass(fabric.Object, fabric.Collection, /** @lends fabric.Group.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'group',\n\n    /**\n     * Width of stroke\n     * @type Number\n     * @default\n     */\n    strokeWidth: 0,\n\n    /**\n     * Indicates if click events should also check for subtargets\n     * @type Boolean\n     * @default\n     */\n    subTargetCheck: false,\n\n    /**\n     * Groups are container, do not render anything on theyr own, ence no cache properties\n     * @type Boolean\n     * @default\n     */\n    cacheProperties: [],\n\n    /**\n     * Constructor\n     * @param {Object} objects Group objects\n     * @param {Object} [options] Options object\n     * @param {Boolean} [isAlreadyGrouped] if true, objects have been grouped already.\n     * @return {Object} thisArg\n     */\n    initialize: function(objects, options, isAlreadyGrouped) {\n      options = options || { };\n\n      this._objects = [];\n      // if objects enclosed in a group have been grouped already,\n      // we cannot change properties of objects.\n      // Thus we need to set options to group without objects,\n      // because delegatedProperties propagate to objects.\n      isAlreadyGrouped && this.callSuper('initialize', options);\n\n      this._objects = objects || [];\n      for (var i = this._objects.length; i--; ) {\n        this._objects[i].group = this;\n      }\n\n      if (options.originX) {\n        this.originX = options.originX;\n      }\n      if (options.originY) {\n        this.originY = options.originY;\n      }\n\n      if (isAlreadyGrouped) {\n        // do not change coordinate of objects enclosed in a group,\n        // because objects coordinate system have been group coodinate system already.\n        this._updateObjectsCoords(true);\n        this._updateObjectsACoords();\n      }\n      else {\n        this._calcBounds();\n        this._updateObjectsCoords();\n        this.callSuper('initialize', options);\n      }\n\n      this.setCoords();\n      this.saveCoords();\n    },\n\n    _updateObjectsACoords: function() {\n      var ignoreZoom = true, skipAbsolute = true;\n      for (var i = this._objects.length; i--; ){\n        this._objects[i].setCoords(ignoreZoom, skipAbsolute);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Boolean} [skipCoordsChange] if true, coordinates of objects enclosed in a group do not change\n     */\n    _updateObjectsCoords: function(skipCoordsChange) {\n      var center = this.getCenterPoint();\n      for (var i = this._objects.length; i--; ){\n        this._updateObjectCoords(this._objects[i], center, skipCoordsChange);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Object} object\n     * @param {fabric.Point} center, current center of group.\n     * @param {Boolean} [skipCoordsChange] if true, coordinates of object dose not change\n     */\n    _updateObjectCoords: function(object, center, skipCoordsChange) {\n      // do not display corners of objects enclosed in a group\n      object.__origHasControls = object.hasControls;\n      object.hasControls = false;\n\n      if (skipCoordsChange) {\n        return;\n      }\n\n      var objectLeft = object.getLeft(),\n          objectTop = object.getTop(),\n          ignoreZoom = true, skipAbsolute = true;\n\n      object.set({\n        left: objectLeft - center.x,\n        top: objectTop - center.y\n      });\n      object.setCoords(ignoreZoom, skipAbsolute);\n    },\n\n    /**\n     * Returns string represenation of a group\n     * @return {String}\n     */\n    toString: function() {\n      return '#<fabric.Group: (' + this.complexity() + ')>';\n    },\n\n    /**\n     * Adds an object to a group; Then recalculates group's dimension, position.\n     * @param {Object} object\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    addWithUpdate: function(object) {\n      this._restoreObjectsState();\n      fabric.util.resetObjectTransform(this);\n      if (object) {\n        this._objects.push(object);\n        object.group = this;\n        object._set('canvas', this.canvas);\n      }\n      // since _restoreObjectsState set objects inactive\n      this.forEachObject(this._setObjectActive, this);\n      this._calcBounds();\n      this._updateObjectsCoords();\n      this.setCoords();\n      this.dirty = true;\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _setObjectActive: function(object) {\n      object.set('active', true);\n      object.group = this;\n    },\n\n    /**\n     * Removes an object from a group; Then recalculates group's dimension, position.\n     * @param {Object} object\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    removeWithUpdate: function(object) {\n      this._restoreObjectsState();\n      fabric.util.resetObjectTransform(this);\n      // since _restoreObjectsState set objects inactive\n      this.forEachObject(this._setObjectActive, this);\n\n      this.remove(object);\n      this._calcBounds();\n      this._updateObjectsCoords();\n      this.setCoords();\n      this.dirty = true;\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _onObjectAdded: function(object) {\n      this.dirty = true;\n      object.group = this;\n      object._set('canvas', this.canvas);\n    },\n\n    /**\n     * @private\n     */\n    _onObjectRemoved: function(object) {\n      this.dirty = true;\n      delete object.group;\n      object.set('active', false);\n    },\n\n    /**\n     * Properties that are delegated to group objects when reading/writing\n     * @param {Object} delegatedProperties\n     */\n    delegatedProperties: {\n      fill:             true,\n      stroke:           true,\n      strokeWidth:      true,\n      fontFamily:       true,\n      fontWeight:       true,\n      fontSize:         true,\n      fontStyle:        true,\n      lineHeight:       true,\n      textDecoration:   true,\n      textAlign:        true,\n      backgroundColor:  true\n    },\n\n    /**\n     * @private\n     */\n    _set: function(key, value) {\n      var i = this._objects.length;\n\n      if (this.delegatedProperties[key] || key === 'canvas') {\n        while (i--) {\n          this._objects[i].set(key, value);\n        }\n      }\n      else {\n        while (i--) {\n          this._objects[i].setOnGroup(key, value);\n        }\n      }\n\n      this.callSuper('_set', key, value);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var objsToObject = this.getObjects().map(function(obj) {\n        var originalDefaults = obj.includeDefaultValues;\n        obj.includeDefaultValues = obj.group.includeDefaultValues;\n        var _obj = obj.toObject(propertiesToInclude);\n        obj.includeDefaultValues = originalDefaults;\n        return _obj;\n      });\n      return extend(this.callSuper('toObject', propertiesToInclude), {\n        objects: objsToObject\n      });\n    },\n\n    /**\n     * Returns object representation of an instance, in dataless mode.\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toDatalessObject: function(propertiesToInclude) {\n      var objsToObject = this.getObjects().map(function(obj) {\n        var originalDefaults = obj.includeDefaultValues;\n        obj.includeDefaultValues = obj.group.includeDefaultValues;\n        var _obj = obj.toDatalessObject(propertiesToInclude);\n        obj.includeDefaultValues = originalDefaults;\n        return _obj;\n      });\n      return extend(this.callSuper('toDatalessObject', propertiesToInclude), {\n        objects: objsToObject\n      });\n    },\n\n    /**\n     * Renders instance on a given context\n     * @param {CanvasRenderingContext2D} ctx context to render instance on\n     */\n    render: function(ctx) {\n      this._transformDone = true;\n      this.callSuper('render', ctx);\n      this._transformDone = false;\n    },\n\n    /**\n     * Decide if the object should cache or not.\n     * objectCaching is a global flag, wins over everything\n     * needsItsOwnCache should be used when the object drawing method requires\n     * a cache step. None of the fabric classes requires it.\n     * Generally you do not cache objects in groups because the group outside is cached.\n     * @return {Boolean}\n     */\n    shouldCache: function() {\n      var parentCache = this.objectCaching && (!this.group || this.needsItsOwnCache() || !this.group.isCaching());\n      this.caching = parentCache;\n      if (parentCache) {\n        for (var i = 0, len = this._objects.length; i < len; i++) {\n          if (this._objects[i].willDrawShadow()) {\n            this.caching = false;\n            return false;\n          }\n        }\n      }\n      return parentCache;\n    },\n\n    /**\n     * Check if this object or a child object will cast a shadow\n     * @return {Boolean}\n     */\n    willDrawShadow: function() {\n      if (this.callSuper('willDrawShadow')) {\n        return true;\n      }\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        if (this._objects[i].willDrawShadow()) {\n          return true;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Check if this group or its parent group are caching, recursively up\n     * @return {Boolean}\n     */\n    isCaching: function() {\n      return this.caching || this.group && this.group.isCaching();\n    },\n\n    /**\n     * Execute the drawing operation for an object on a specified context\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} [noTransform] When true, context is not transformed\n     */\n    drawObject: function(ctx) {\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        this._renderObject(this._objects[i], ctx);\n      }\n    },\n\n    /**\n     * Check if cache is dirty\n     */\n    isCacheDirty: function() {\n      if (this.callSuper('isCacheDirty')) {\n        return true;\n      }\n      if (!this.statefullCache) {\n        return false;\n      }\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        if (this._objects[i].isCacheDirty(true)) {\n          if (this._cacheCanvas) {\n            // if this group has not a cache canvas there is nothing to clean\n            var x = this.cacheWidth / this.zoomX, y = this.cacheHeight / this.zoomY;\n            this._cacheContext.clearRect(-x / 2, -y / 2, x, y);\n          }\n          return true;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Renders controls and borders for the object\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} [noTransform] When true, context is not transformed\n     */\n    _renderControls: function(ctx, noTransform) {\n      ctx.save();\n      ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;\n      this.callSuper('_renderControls', ctx, noTransform);\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        this._objects[i]._renderControls(ctx);\n      }\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     */\n    _renderObject: function(object, ctx) {\n      // do not render if object is not visible\n      if (!object.visible) {\n        return;\n      }\n\n      var originalHasRotatingPoint = object.hasRotatingPoint;\n      object.hasRotatingPoint = false;\n      object.render(ctx);\n      object.hasRotatingPoint = originalHasRotatingPoint;\n    },\n\n    /**\n     * Retores original state of each of group objects (original state is that which was before group was created).\n     * @private\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    _restoreObjectsState: function() {\n      this._objects.forEach(this._restoreObjectState, this);\n      return this;\n    },\n\n    /**\n     * Realises the transform from this group onto the supplied object\n     * i.e. it tells you what would happen if the supplied object was in\n     * the group, and then the group was destroyed. It mutates the supplied\n     * object.\n     * @param {fabric.Object} object\n     * @return {fabric.Object} transformedObject\n     */\n    realizeTransform: function(object) {\n      var matrix = object.calcTransformMatrix(),\n          options = fabric.util.qrDecompose(matrix),\n          center = new fabric.Point(options.translateX, options.translateY);\n      object.flipX = false;\n      object.flipY = false;\n      object.set('scaleX', options.scaleX);\n      object.set('scaleY', options.scaleY);\n      object.skewX = options.skewX;\n      object.skewY = options.skewY;\n      object.angle = options.angle;\n      object.setPositionByOrigin(center, 'center', 'center');\n      return object;\n    },\n\n    /**\n     * Restores original state of a specified object in group\n     * @private\n     * @param {fabric.Object} object\n     * @return {fabric.Group} thisArg\n     */\n    _restoreObjectState: function(object) {\n      this.realizeTransform(object);\n      object.setCoords();\n      object.hasControls = object.__origHasControls;\n      delete object.__origHasControls;\n      object.set('active', false);\n      delete object.group;\n\n      return this;\n    },\n\n    /**\n     * Destroys a group (restoring state of its objects)\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    destroy: function() {\n      // when group is destroyed objects needs to get a repaint to be eventually\n      // displayed on canvas.\n      this._objects.forEach(function(object) {\n        object.set('dirty', true);\n      });\n      return this._restoreObjectsState();\n    },\n\n    /**\n     * Saves coordinates of this instance (to be used together with `hasMoved`)\n     * @saveCoords\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    saveCoords: function() {\n      this._originalLeft = this.get('left');\n      this._originalTop = this.get('top');\n      return this;\n    },\n\n    /**\n     * Checks whether this group was moved (since `saveCoords` was called last)\n     * @return {Boolean} true if an object was moved (since fabric.Group#saveCoords was called)\n     */\n    hasMoved: function() {\n      return this._originalLeft !== this.get('left') ||\n             this._originalTop !== this.get('top');\n    },\n\n    /**\n     * Sets coordinates of all objects inside group\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    setObjectsCoords: function() {\n      var ignoreZoom = true, skipAbsolute = true;\n      this.forEachObject(function(object) {\n        object.setCoords(ignoreZoom, skipAbsolute);\n      });\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _calcBounds: function(onlyWidthHeight) {\n      var aX = [],\n          aY = [],\n          o, prop,\n          props = ['tr', 'br', 'bl', 'tl'],\n          i = 0, iLen = this._objects.length,\n          j, jLen = props.length,\n          ignoreZoom = true;\n\n      for ( ; i < iLen; ++i) {\n        o = this._objects[i];\n        o.setCoords(ignoreZoom);\n        for (j = 0; j < jLen; j++) {\n          prop = props[j];\n          aX.push(o.oCoords[prop].x);\n          aY.push(o.oCoords[prop].y);\n        }\n      }\n\n      this.set(this._getBounds(aX, aY, onlyWidthHeight));\n    },\n\n    /**\n     * @private\n     */\n    _getBounds: function(aX, aY, onlyWidthHeight) {\n      var minXY = new fabric.Point(min(aX), min(aY)),\n          maxXY = new fabric.Point(max(aX), max(aY)),\n          obj = {\n            width: (maxXY.x - minXY.x) || 0,\n            height: (maxXY.y - minXY.y) || 0\n          };\n\n      if (!onlyWidthHeight) {\n        obj.left = minXY.x || 0;\n        obj.top = minXY.y || 0;\n        if (this.originX === 'center') {\n          obj.left += obj.width / 2;\n        }\n        if (this.originX === 'right') {\n          obj.left += obj.width;\n        }\n        if (this.originY === 'center') {\n          obj.top += obj.height / 2;\n        }\n        if (this.originY === 'bottom') {\n          obj.top += obj.height;\n        }\n      }\n      return obj;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var markup = this._createBaseSVGMarkup();\n      markup.push(\n        '<g ', this.getSvgId(), 'transform=\"',\n        /* avoiding styles intentionally */\n        this.getSvgTransform(),\n        this.getSvgTransformMatrix(),\n        '\" style=\"',\n        this.getSvgFilter(),\n        '\">\\n'\n      );\n\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        markup.push('\\t', this._objects[i].toSVG(reviver));\n      }\n\n      markup.push('</g>\\n');\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns requested property\n     * @param {String} prop Property to get\n     * @return {*}\n     */\n    get: function(prop) {\n      if (prop in _lockProperties) {\n        if (this[prop]) {\n          return this[prop];\n        }\n        else {\n          for (var i = 0, len = this._objects.length; i < len; i++) {\n            if (this._objects[i][prop]) {\n              return true;\n            }\n          }\n          return false;\n        }\n      }\n      else {\n        if (prop in this.delegatedProperties) {\n          return this._objects[0] && this._objects[0].get(prop);\n        }\n        return this[prop];\n      }\n    }\n  });\n\n  /**\n   * Returns {@link fabric.Group} instance from an object representation\n   * @static\n   * @memberOf fabric.Group\n   * @param {Object} object Object to create a group from\n   * @param {Function} [callback] Callback to invoke when an group instance is created\n   */\n  fabric.Group.fromObject = function(object, callback) {\n    fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) {\n      var options = fabric.util.object.clone(object, true);\n      delete options.objects;\n      callback && callback(new fabric.Group(enlivenedObjects, options, true));\n    });\n  };\n\n  /**\n   * Indicates that instances of this type are async\n   * @static\n   * @memberOf fabric.Group\n   * @type Boolean\n   * @default\n   */\n  fabric.Group.async = true;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var extend = fabric.util.object.extend;\n\n  if (!global.fabric) {\n    global.fabric = { };\n  }\n\n  if (global.fabric.Image) {\n    fabric.warn('fabric.Image is already defined.');\n    return;\n  }\n\n  /**\n   * Image class\n   * @class fabric.Image\n   * @extends fabric.Object\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#images}\n   * @see {@link fabric.Image#initialize} for constructor definition\n   */\n  fabric.Image = fabric.util.createClass(fabric.Object, /** @lends fabric.Image.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'image',\n\n    /**\n     * crossOrigin value (one of \"\", \"anonymous\", \"use-credentials\")\n     * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes\n     * @type String\n     * @default\n     */\n    crossOrigin: '',\n\n    /**\n     * AlignX value, part of preserveAspectRatio (one of \"none\", \"mid\", \"min\", \"max\")\n     * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute\n     * This parameter defines how the picture is aligned to its viewport when image element width differs from image width.\n     * @type String\n     * @default\n     */\n    alignX: 'none',\n\n    /**\n     * AlignY value, part of preserveAspectRatio (one of \"none\", \"mid\", \"min\", \"max\")\n     * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute\n     * This parameter defines how the picture is aligned to its viewport when image element height differs from image height.\n     * @type String\n     * @default\n     */\n    alignY: 'none',\n\n    /**\n     * meetOrSlice value, part of preserveAspectRatio  (one of \"meet\", \"slice\").\n     * if meet the image is always fully visibile, if slice the viewport is always filled with image.\n     * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute\n     * @type String\n     * @default\n     */\n    meetOrSlice: 'meet',\n\n    /**\n     * Width of a stroke.\n     * For image quality a stroke multiple of 2 gives better results.\n     * @type Number\n     * @default\n     */\n    strokeWidth: 0,\n\n    /**\n     * private\n     * contains last value of scaleX to detect\n     * if the Image got resized after the last Render\n     * @type Number\n     */\n    _lastScaleX: 1,\n\n    /**\n     * private\n     * contains last value of scaleY to detect\n     * if the Image got resized after the last Render\n     * @type Number\n     */\n    _lastScaleY: 1,\n\n    /**\n     * minimum scale factor under which any resizeFilter is triggered to resize the image\n     * 0 will disable the automatic resize. 1 will trigger automatically always.\n     * number bigger than 1 can be used in case we want to scale with some filter above\n     * the natural image dimensions\n     * @type Number\n     */\n    minimumScaleTrigger: 0.5,\n\n    /**\n     * List of properties to consider when checking if\n     * state of an object is changed ({@link fabric.Object#hasStateChanged})\n     * as well as for history (undo/redo) purposes\n     * @type Array\n     */\n    stateProperties: fabric.Object.prototype.stateProperties.concat(\n      'alignX',\n      'alignY',\n      'meetOrSlice'),\n\n    /**\n     * When `true`, object is cached on an additional canvas.\n     * default to false for images\n     * since 1.7.0\n     * @type Boolean\n     * @default\n     */\n    objectCaching: false,\n\n    /**\n     * Constructor\n     * @param {HTMLImageElement | String} element Image element\n     * @param {Object} [options] Options object\n     * @param {function} [callback] callback function to call after eventual filters applied.\n     * @return {fabric.Image} thisArg\n     */\n    initialize: function(element, options, callback) {\n      options || (options = { });\n      this.filters = [];\n      this.resizeFilters = [];\n      this.callSuper('initialize', options);\n      this._initElement(element, options, callback);\n    },\n\n    /**\n     * Returns image element which this instance if based on\n     * @return {HTMLImageElement} Image element\n     */\n    getElement: function() {\n      return this._element;\n    },\n\n    /**\n     * Sets image element for this instance to a specified one.\n     * If filters defined they are applied to new image.\n     * You might need to call `canvas.renderAll` and `object.setCoords` after replacing, to render new image and update controls area.\n     * @param {HTMLImageElement} element\n     * @param {Function} [callback] Callback is invoked when all filters have been applied and new image is generated\n     * @param {Object} [options] Options object\n     * @return {fabric.Image} thisArg\n     * @chainable\n     */\n    setElement: function(element, callback, options) {\n\n      var _callback, _this;\n\n      this._element = element;\n      this._originalElement = element;\n      this._initConfig(options);\n\n      if (this.resizeFilters.length === 0) {\n        _callback = callback;\n      }\n      else {\n        _this = this;\n        _callback = function() {\n          _this.applyFilters(callback, _this.resizeFilters, _this._filteredEl || _this._originalElement, true);\n        };\n      }\n\n      if (this.filters.length !== 0) {\n        this.applyFilters(_callback);\n      }\n      else if (_callback) {\n        _callback(this);\n      }\n\n      return this;\n    },\n\n    /**\n     * Sets crossOrigin value (on an instance and corresponding image element)\n     * @return {fabric.Image} thisArg\n     * @chainable\n     */\n    setCrossOrigin: function(value) {\n      this.crossOrigin = value;\n      this._element.crossOrigin = value;\n\n      return this;\n    },\n\n    /**\n     * Returns original size of an image\n     * @return {Object} Object with \"width\" and \"height\" properties\n     */\n    getOriginalSize: function() {\n      var element = this.getElement();\n      return {\n        width: element.width,\n        height: element.height\n      };\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _stroke: function(ctx) {\n      if (!this.stroke || this.strokeWidth === 0) {\n        return;\n      }\n      var w = this.width / 2, h = this.height / 2;\n      ctx.beginPath();\n      ctx.moveTo(-w, -h);\n      ctx.lineTo(w, -h);\n      ctx.lineTo(w, h);\n      ctx.lineTo(-w, h);\n      ctx.lineTo(-w, -h);\n      ctx.closePath();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderDashedStroke: function(ctx) {\n      var x = -this.width / 2,\n          y = -this.height / 2,\n          w = this.width,\n          h = this.height;\n\n      ctx.save();\n      this._setStrokeStyles(ctx);\n\n      ctx.beginPath();\n      fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray);\n      fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray);\n      fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray);\n      fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray);\n      ctx.closePath();\n      ctx.restore();\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var filters = [], resizeFilters = [],\n          scaleX = 1, scaleY = 1;\n\n      this.filters.forEach(function(filterObj) {\n        if (filterObj) {\n          if (filterObj.type === 'Resize') {\n            scaleX *= filterObj.scaleX;\n            scaleY *= filterObj.scaleY;\n          }\n          filters.push(filterObj.toObject());\n        }\n      });\n\n      this.resizeFilters.forEach(function(filterObj) {\n        filterObj && resizeFilters.push(filterObj.toObject());\n      });\n      var object = extend(\n        this.callSuper(\n          'toObject',\n          ['crossOrigin', 'alignX', 'alignY', 'meetOrSlice'].concat(propertiesToInclude)\n        ), {\n          src: this.getSrc(),\n          filters: filters,\n          resizeFilters: resizeFilters,\n        });\n\n      object.width /= scaleX;\n      object.height /= scaleY;\n\n      return object;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2,\n          preserveAspectRatio = 'none', filtered = true;\n      if (this.group && this.group.type === 'path-group') {\n        x = this.left;\n        y = this.top;\n      }\n      if (this.alignX !== 'none' && this.alignY !== 'none') {\n        preserveAspectRatio = 'x' + this.alignX + 'Y' + this.alignY + ' ' + this.meetOrSlice;\n      }\n      markup.push(\n        '<g transform=\"', this.getSvgTransform(), this.getSvgTransformMatrix(), '\">\\n',\n          '<image ', this.getSvgId(), 'xlink:href=\"', this.getSvgSrc(filtered),\n            '\" x=\"', x, '\" y=\"', y,\n            '\" style=\"', this.getSvgStyles(),\n            // we're essentially moving origin of transformation from top/left corner to the center of the shape\n            // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left\n            // so that object's center aligns with container's left/top\n            '\" width=\"', this.width,\n            '\" height=\"', this.height,\n            '\" preserveAspectRatio=\"', preserveAspectRatio, '\"',\n          '></image>\\n'\n      );\n\n      if (this.stroke || this.strokeDashArray) {\n        var origFill = this.fill;\n        this.fill = null;\n        markup.push(\n          '<rect ',\n            'x=\"', x, '\" y=\"', y,\n            '\" width=\"', this.width, '\" height=\"', this.height,\n            '\" style=\"', this.getSvgStyles(),\n          '\"/>\\n'\n        );\n        this.fill = origFill;\n      }\n\n      markup.push('</g>\\n');\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns source of an image\n     * @param {Boolean} filtered indicates if the src is needed for svg\n     * @return {String} Source of an image\n     */\n    getSrc: function(filtered) {\n      var element = filtered ? this._element : this._originalElement;\n      if (element) {\n        return fabric.isLikelyNode ? element._src : element.src;\n      }\n      else {\n        return this.src || '';\n      }\n    },\n\n    /**\n     * Sets source of an image\n     * @param {String} src Source string (URL)\n     * @param {Function} [callback] Callback is invoked when image has been loaded (and all filters have been applied)\n     * @param {Object} [options] Options object\n     * @return {fabric.Image} thisArg\n     * @chainable\n     */\n    setSrc: function(src, callback, options) {\n      fabric.util.loadImage(src, function(img) {\n        return this.setElement(img, callback, options);\n      }, this, options && options.crossOrigin);\n    },\n\n    /**\n     * Returns string representation of an instance\n     * @return {String} String representation of an instance\n     */\n    toString: function() {\n      return '#<fabric.Image: { src: \"' + this.getSrc() + '\" }>';\n    },\n\n    /**\n     * Applies filters assigned to this image (from \"filters\" array)\n     * @method applyFilters\n     * @param {Function} callback Callback is invoked when all filters have been applied and new image is generated\n     * @param {Array} filters to be applied\n     * @param {fabric.Image} imgElement image to filter ( default to this._element )\n     * @param {Boolean} forResizing\n     * @return {CanvasElement} canvasEl to be drawn immediately\n     * @chainable\n     */\n    applyFilters: function(callback, filters, imgElement, forResizing) {\n\n      filters = filters || this.filters;\n      imgElement = imgElement || this._originalElement;\n\n      if (!imgElement) {\n        return;\n      }\n\n      var replacement = fabric.util.createImage(),\n          retinaScaling = this.canvas ? this.canvas.getRetinaScaling() : fabric.devicePixelRatio,\n          minimumScale = this.minimumScaleTrigger / retinaScaling,\n          _this = this, scaleX, scaleY;\n\n      if (filters.length === 0) {\n        this._element = imgElement;\n        callback && callback(this);\n        return imgElement;\n      }\n\n      var canvasEl = fabric.util.createCanvasElement();\n      canvasEl.width = imgElement.width;\n      canvasEl.height = imgElement.height;\n      canvasEl.getContext('2d').drawImage(imgElement, 0, 0, imgElement.width, imgElement.height);\n\n      filters.forEach(function(filter) {\n        if (!filter) {\n          return;\n        }\n        if (forResizing) {\n          scaleX = _this.scaleX < minimumScale ? _this.scaleX : 1;\n          scaleY = _this.scaleY < minimumScale ? _this.scaleY : 1;\n          if (scaleX * retinaScaling < 1) {\n            scaleX *= retinaScaling;\n          }\n          if (scaleY * retinaScaling < 1) {\n            scaleY *= retinaScaling;\n          }\n        }\n        else {\n          scaleX = filter.scaleX;\n          scaleY = filter.scaleY;\n        }\n        filter.applyTo(canvasEl, scaleX, scaleY);\n        if (!forResizing && filter.type === 'Resize') {\n          _this.width *= filter.scaleX;\n          _this.height *= filter.scaleY;\n        }\n      });\n\n      /** @ignore */\n      replacement.width = canvasEl.width;\n      replacement.height = canvasEl.height;\n      if (fabric.isLikelyNode) {\n        replacement.src = canvasEl.toBuffer(undefined, fabric.Image.pngCompression);\n        // onload doesn't fire in some node versions, so we invoke callback manually\n        _this._element = replacement;\n        !forResizing && (_this._filteredEl = replacement);\n        callback && callback(_this);\n      }\n      else {\n        replacement.onload = function() {\n          _this._element = replacement;\n          !forResizing && (_this._filteredEl = replacement);\n          callback && callback(_this);\n          replacement.onload = canvasEl = null;\n        };\n        replacement.src = canvasEl.toDataURL('image/png');\n      }\n      return canvasEl;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} noTransform\n     */\n    _render: function(ctx, noTransform) {\n      var x, y, imageMargins = this._findMargins(), elementToDraw;\n\n      x = (noTransform ? this.left : -this.width / 2);\n      y = (noTransform ? this.top : -this.height / 2);\n\n      if (this.meetOrSlice === 'slice') {\n        ctx.beginPath();\n        ctx.rect(x, y, this.width, this.height);\n        ctx.clip();\n      }\n\n      if (this.isMoving === false && this.resizeFilters.length && this._needsResize()) {\n        this._lastScaleX = this.scaleX;\n        this._lastScaleY = this.scaleY;\n        elementToDraw = this.applyFilters(null, this.resizeFilters, this._filteredEl || this._originalElement, true);\n      }\n      else {\n        elementToDraw = this._element;\n      }\n      elementToDraw && ctx.drawImage(elementToDraw,\n                                     x + imageMargins.marginX,\n                                     y + imageMargins.marginY,\n                                     imageMargins.width,\n                                     imageMargins.height\n                                    );\n\n      this._stroke(ctx);\n      this._renderStroke(ctx);\n    },\n\n    /**\n     * @private, needed to check if image needs resize\n     */\n    _needsResize: function() {\n      return (this.scaleX !== this._lastScaleX || this.scaleY !== this._lastScaleY);\n    },\n\n    /**\n     * @private\n     */\n    _findMargins: function() {\n      var width = this.width, height = this.height, scales,\n          scale, marginX = 0, marginY = 0;\n\n      if (this.alignX !== 'none' || this.alignY !== 'none') {\n        scales = [this.width / this._element.width, this.height / this._element.height];\n        scale = this.meetOrSlice === 'meet'\n                ? Math.min.apply(null, scales) : Math.max.apply(null, scales);\n        width = this._element.width * scale;\n        height = this._element.height * scale;\n        if (this.alignX === 'Mid') {\n          marginX = (this.width - width) / 2;\n        }\n        if (this.alignX === 'Max') {\n          marginX = this.width - width;\n        }\n        if (this.alignY === 'Mid') {\n          marginY = (this.height - height) / 2;\n        }\n        if (this.alignY === 'Max') {\n          marginY = this.height - height;\n        }\n      }\n      return {\n        width:  width,\n        height: height,\n        marginX: marginX,\n        marginY: marginY\n      };\n    },\n\n    /**\n     * @private\n     */\n    _resetWidthHeight: function() {\n      var element = this.getElement();\n\n      this.set('width', element.width);\n      this.set('height', element.height);\n    },\n\n    /**\n     * The Image class's initialization method. This method is automatically\n     * called by the constructor.\n     * @private\n     * @param {HTMLImageElement|String} element The element representing the image\n     * @param {Object} [options] Options object\n     */\n    _initElement: function(element, options, callback) {\n      this.setElement(fabric.util.getById(element), callback, options);\n      fabric.util.addClass(this.getElement(), fabric.Image.CSS_CANVAS);\n    },\n\n    /**\n     * @private\n     * @param {Object} [options] Options object\n     */\n    _initConfig: function(options) {\n      options || (options = { });\n      this.setOptions(options);\n      this._setWidthHeight(options);\n      if (this._element && this.crossOrigin) {\n        this._element.crossOrigin = this.crossOrigin;\n      }\n    },\n\n    /**\n     * @private\n     * @param {Array} filters to be initialized\n     * @param {Function} callback Callback to invoke when all fabric.Image.filters instances are created\n     */\n    _initFilters: function(filters, callback) {\n      if (filters && filters.length) {\n        fabric.util.enlivenObjects(filters, function(enlivenedObjects) {\n          callback && callback(enlivenedObjects);\n        }, 'fabric.Image.filters');\n      }\n      else {\n        callback && callback();\n      }\n    },\n\n    /**\n     * @private\n     * @param {Object} [options] Object with width/height properties\n     */\n    _setWidthHeight: function(options) {\n      this.width = 'width' in options\n        ? options.width\n        : (this.getElement()\n            ? this.getElement().width || 0\n            : 0);\n\n      this.height = 'height' in options\n        ? options.height\n        : (this.getElement()\n            ? this.getElement().height || 0\n            : 0);\n    },\n  });\n\n  /**\n   * Default CSS class name for canvas\n   * @static\n   * @type String\n   * @default\n   */\n  fabric.Image.CSS_CANVAS = 'canvas-img';\n\n  /**\n   * Alias for getSrc\n   * @static\n   */\n  fabric.Image.prototype.getSvgSrc = fabric.Image.prototype.getSrc;\n\n  /**\n   * Creates an instance of fabric.Image from its object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} callback Callback to invoke when an image instance is created\n   */\n  fabric.Image.fromObject = function(object, callback) {\n    fabric.util.loadImage(object.src, function(img, error) {\n      if (error) {\n        callback && callback(null, error);\n        return;\n      }\n      fabric.Image.prototype._initFilters.call(object, object.filters, function(filters) {\n        object.filters = filters || [];\n        fabric.Image.prototype._initFilters.call(object, object.resizeFilters, function(resizeFilters) {\n          object.resizeFilters = resizeFilters || [];\n          return new fabric.Image(img, object, callback);\n        });\n      });\n    }, null, object.crossOrigin);\n  };\n\n  /**\n   * Creates an instance of fabric.Image from an URL string\n   * @static\n   * @param {String} url URL to create an image from\n   * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument)\n   * @param {Object} [imgOptions] Options object\n   */\n  fabric.Image.fromURL = function(url, callback, imgOptions) {\n    fabric.util.loadImage(url, function(img) {\n      callback && callback(new fabric.Image(img, imgOptions));\n    }, null, imgOptions && imgOptions.crossOrigin);\n  };\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Image.fromElement})\n   * @static\n   * @see {@link http://www.w3.org/TR/SVG/struct.html#ImageElement}\n   */\n  fabric.Image.ATTRIBUTE_NAMES =\n    fabric.SHARED_ATTRIBUTES.concat('x y width height preserveAspectRatio xlink:href crossOrigin'.split(' '));\n\n  /**\n   * Returns {@link fabric.Image} instance from an SVG element\n   * @static\n   * @param {SVGElement} element Element to parse\n   * @param {Function} callback Callback to execute when fabric.Image object is created\n   * @param {Object} [options] Options object\n   * @return {fabric.Image} Instance of fabric.Image\n   */\n  fabric.Image.fromElement = function(element, callback, options) {\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES),\n        preserveAR;\n\n    if (parsedAttributes.preserveAspectRatio) {\n      preserveAR = fabric.util.parsePreserveAspectRatioAttribute(parsedAttributes.preserveAspectRatio);\n      extend(parsedAttributes, preserveAR);\n    }\n\n    fabric.Image.fromURL(parsedAttributes['xlink:href'], callback,\n      extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Indicates that instances of this type are async\n   * @static\n   * @type Boolean\n   * @default\n   */\n  fabric.Image.async = true;\n\n  /**\n   * Indicates compression level used when generating PNG under Node (in applyFilters). Any of 0-9\n   * @static\n   * @type Number\n   * @default\n   */\n  fabric.Image.pngCompression = 1;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n  /**\n   * @private\n   * @return {Number} angle value\n   */\n  _getAngleValueForStraighten: function() {\n    var angle = this.getAngle() % 360;\n    if (angle > 0) {\n      return Math.round((angle - 1) / 90) * 90;\n    }\n    return Math.round(angle / 90) * 90;\n  },\n\n  /**\n   * Straightens an object (rotating it from current angle to one of 0, 90, 180, 270, etc. depending on which is closer)\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  straighten: function() {\n    this.setAngle(this._getAngleValueForStraighten());\n    return this;\n  },\n\n  /**\n   * Same as {@link fabric.Object.prototype.straighten} but with animation\n   * @param {Object} callbacks Object with callback functions\n   * @param {Function} [callbacks.onComplete] Invoked on completion\n   * @param {Function} [callbacks.onChange] Invoked on every step of animation\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  fxStraighten: function(callbacks) {\n    callbacks = callbacks || { };\n\n    var empty = function() { },\n        onComplete = callbacks.onComplete || empty,\n        onChange = callbacks.onChange || empty,\n        _this = this;\n\n    fabric.util.animate({\n      startValue: this.get('angle'),\n      endValue: this._getAngleValueForStraighten(),\n      duration: this.FX_DURATION,\n      onChange: function(value) {\n        _this.setAngle(value);\n        onChange();\n      },\n      onComplete: function() {\n        _this.setCoords();\n        onComplete();\n      },\n      onStart: function() {\n        _this.set('active', false);\n      }\n    });\n\n    return this;\n  }\n});\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n  /**\n   * Straightens object, then rerenders canvas\n   * @param {fabric.Object} object Object to straighten\n   * @return {fabric.Canvas} thisArg\n   * @chainable\n   */\n  straightenObject: function (object) {\n    object.straighten();\n    this.renderAll();\n    return this;\n  },\n\n  /**\n   * Same as {@link fabric.Canvas.prototype.straightenObject}, but animated\n   * @param {fabric.Object} object Object to straighten\n   * @return {fabric.Canvas} thisArg\n   * @chainable\n   */\n  fxStraightenObject: function (object) {\n    object.fxStraighten({\n      onChange: this.renderAll.bind(this)\n    });\n    return this;\n  }\n});\n\n\n/**\n * @namespace fabric.Image.filters\n * @memberOf fabric.Image\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#image_filters}\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n */\nfabric.Image.filters = fabric.Image.filters || { };\n\n/**\n * Root filter class from which all filter classes inherit from\n * @class fabric.Image.filters.BaseFilter\n * @memberOf fabric.Image.filters\n */\nfabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Image.filters.BaseFilter.prototype */ {\n\n  /**\n   * Filter type\n   * @param {String} type\n   * @default\n   */\n  type: 'BaseFilter',\n\n  /**\n   * Constructor\n   * @param {Object} [options] Options object\n   */\n  initialize: function(options) {\n    if (options) {\n      this.setOptions(options);\n    }\n  },\n\n  /**\n   * Sets filter's properties from options\n   * @param {Object} [options] Options object\n   */\n  setOptions: function(options) {\n    for (var prop in options) {\n      this[prop] = options[prop];\n    }\n  },\n\n  /**\n   * Returns object representation of an instance\n   * @return {Object} Object representation of an instance\n   */\n  toObject: function() {\n    return { type: this.type };\n  },\n\n  /**\n   * Returns a JSON representation of an instance\n   * @return {Object} JSON\n   */\n  toJSON: function() {\n    // delegate, not alias\n    return this.toObject();\n  }\n});\n\nfabric.Image.filters.BaseFilter.fromObject = function(object, callback) {\n  var filter = new fabric.Image.filters[object.type](object);\n  callback && callback(filter);\n  return filter;\n};\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Brightness filter class\n   * @class fabric.Image.filters.Brightness\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Brightness#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Brightness({\n   *   brightness: 200\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Brightness = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Brightness.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Brightness',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Brightness.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.brightness=0] Value to brighten the image up (-255..255)\n     */\n    initialize: function(options) {\n      options = options || { };\n      this.brightness = options.brightness || 0;\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          brightness = this.brightness;\n\n      for (var i = 0, len = data.length; i < len; i += 4) {\n        data[i] += brightness;\n        data[i + 1] += brightness;\n        data[i + 2] += brightness;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        brightness: this.brightness\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Brightness} Instance of fabric.Image.filters.Brightness\n   */\n  fabric.Image.filters.Brightness.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Adapted from <a href=\"http://www.html5rocks.com/en/tutorials/canvas/imagefilters/\">html5rocks article</a>\n   * @class fabric.Image.filters.Convolute\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Convolute#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example <caption>Sharpen filter</caption>\n   * var filter = new fabric.Image.filters.Convolute({\n   *   matrix: [ 0, -1,  0,\n   *            -1,  5, -1,\n   *             0, -1,  0 ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   * @example <caption>Blur filter</caption>\n   * var filter = new fabric.Image.filters.Convolute({\n   *   matrix: [ 1/9, 1/9, 1/9,\n   *             1/9, 1/9, 1/9,\n   *             1/9, 1/9, 1/9 ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   * @example <caption>Emboss filter</caption>\n   * var filter = new fabric.Image.filters.Convolute({\n   *   matrix: [ 1,   1,  1,\n   *             1, 0.7, -1,\n   *            -1,  -1, -1 ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   * @example <caption>Emboss filter with opaqueness</caption>\n   * var filter = new fabric.Image.filters.Convolute({\n   *   opaque: true,\n   *   matrix: [ 1,   1,  1,\n   *             1, 0.7, -1,\n   *            -1,  -1, -1 ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Convolute = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Convolute.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Convolute',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Convolute.prototype\n     * @param {Object} [options] Options object\n     * @param {Boolean} [options.opaque=false] Opaque value (true/false)\n     * @param {Array} [options.matrix] Filter matrix\n     */\n    initialize: function(options) {\n      options = options || { };\n\n      this.opaque = options.opaque;\n      this.matrix = options.matrix || [\n        0, 0, 0,\n        0, 1, 0,\n        0, 0, 0\n      ];\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n\n      var weights = this.matrix,\n          context = canvasEl.getContext('2d'),\n          pixels = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n\n          side = Math.round(Math.sqrt(weights.length)),\n          halfSide = Math.floor(side / 2),\n          src = pixels.data,\n          sw = pixels.width,\n          sh = pixels.height,\n          output = context.createImageData(sw, sh),\n          dst = output.data,\n          // go through the destination image pixels\n          alphaFac = this.opaque ? 1 : 0,\n          r, g, b, a, dstOff,\n          scx, scy, srcOff, wt;\n\n      for (var y = 0; y < sh; y++) {\n        for (var x = 0; x < sw; x++) {\n          dstOff = (y * sw + x) * 4;\n          // calculate the weighed sum of the source image pixels that\n          // fall under the convolution matrix\n          r = 0; g = 0; b = 0; a = 0;\n\n          for (var cy = 0; cy < side; cy++) {\n            for (var cx = 0; cx < side; cx++) {\n              scy = y + cy - halfSide;\n              scx = x + cx - halfSide;\n\n              // eslint-disable-next-line max-depth\n              if (scy < 0 || scy > sh || scx < 0 || scx > sw) {\n                continue;\n              }\n\n              srcOff = (scy * sw + scx) * 4;\n              wt = weights[cy * side + cx];\n\n              r += src[srcOff] * wt;\n              g += src[srcOff + 1] * wt;\n              b += src[srcOff + 2] * wt;\n              a += src[srcOff + 3] * wt;\n            }\n          }\n          dst[dstOff] = r;\n          dst[dstOff + 1] = g;\n          dst[dstOff + 2] = b;\n          dst[dstOff + 3] = a + alphaFac * (255 - a);\n        }\n      }\n\n      context.putImageData(output, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        opaque: this.opaque,\n        matrix: this.matrix\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Convolute} Instance of fabric.Image.filters.Convolute\n   */\n  fabric.Image.filters.Convolute.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * GradientTransparency filter class\n   * @class fabric.Image.filters.GradientTransparency\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.GradientTransparency#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.GradientTransparency({\n   *   threshold: 200\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n   // eslint-disable-next-line max-len\n  filters.GradientTransparency = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.GradientTransparency.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'GradientTransparency',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.GradientTransparency.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.threshold=100] Threshold value\n     */\n    initialize: function(options) {\n      options = options || { };\n      this.threshold = options.threshold || 100;\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          threshold = this.threshold,\n          total = data.length;\n\n      for (var i = 0, len = data.length; i < len; i += 4) {\n        data[i + 3] = threshold + 255 * (total - i) / total;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        threshold: this.threshold\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.GradientTransparency} Instance of fabric.Image.filters.GradientTransparency\n   */\n  fabric.Image.filters.GradientTransparency.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Grayscale image filter class\n   * @class fabric.Image.filters.Grayscale\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Grayscale();\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Grayscale = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Grayscale.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Grayscale',\n\n    /**\n     * Applies filter to canvas element\n     * @memberOf fabric.Image.filters.Grayscale.prototype\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          len = imageData.width * imageData.height * 4,\n          index = 0,\n          average;\n\n      while (index < len) {\n        average = (data[index] + data[index + 1] + data[index + 2]) / 3;\n        data[index]     = average;\n        data[index + 1] = average;\n        data[index + 2] = average;\n        index += 4;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Grayscale} Instance of fabric.Image.filters.Grayscale\n   */\n  fabric.Image.filters.Grayscale.fromObject = function(object, callback) {\n    object = object || { };\n    object.type = 'Grayscale';\n    return fabric.Image.filters.BaseFilter.fromObject(object, callback);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Invert filter class\n   * @class fabric.Image.filters.Invert\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Invert();\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Invert = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Invert.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Invert',\n\n    /**\n     * Applies filter to canvas element\n     * @memberOf fabric.Image.filters.Invert.prototype\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          iLen = data.length, i;\n\n      for (i = 0; i < iLen; i += 4) {\n        data[i] = 255 - data[i];\n        data[i + 1] = 255 - data[i + 1];\n        data[i + 2] = 255 - data[i + 2];\n      }\n\n      context.putImageData(imageData, 0, 0);\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Invert} Instance of fabric.Image.filters.Invert\n   */\n  fabric.Image.filters.Invert.fromObject = function(object, callback) {\n    object = object || { };\n    object.type = 'Invert';\n    return fabric.Image.filters.BaseFilter.fromObject(object, callback);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Mask filter class\n   * See http://resources.aleph-1.com/mask/\n   * @class fabric.Image.filters.Mask\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Mask#initialize} for constructor definition\n   */\n  filters.Mask = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Mask.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Mask',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Mask.prototype\n     * @param {Object} [options] Options object\n     * @param {fabric.Image} [options.mask] Mask image object\n     * @param {Number} [options.channel=0] Rgb channel (0, 1, 2 or 3)\n     */\n    initialize: function(options) {\n      options = options || { };\n\n      this.mask = options.mask;\n      this.channel = [0, 1, 2, 3].indexOf(options.channel) > -1 ? options.channel : 0;\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      if (!this.mask) {\n        return;\n      }\n\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          maskEl = this.mask.getElement(),\n          maskCanvasEl = fabric.util.createCanvasElement(),\n          channel = this.channel,\n          i,\n          iLen = imageData.width * imageData.height * 4;\n\n      maskCanvasEl.width = canvasEl.width;\n      maskCanvasEl.height = canvasEl.height;\n\n      maskCanvasEl.getContext('2d').drawImage(maskEl, 0, 0, canvasEl.width, canvasEl.height);\n\n      var maskImageData = maskCanvasEl.getContext('2d').getImageData(0, 0, canvasEl.width, canvasEl.height),\n          maskData = maskImageData.data;\n\n      for (i = 0; i < iLen; i += 4) {\n        data[i + 3] = maskData[i + channel];\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        mask: this.mask.toObject(),\n        channel: this.channel\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when a mask filter instance is created\n   */\n  fabric.Image.filters.Mask.fromObject = function(object, callback) {\n    fabric.util.loadImage(object.mask.src, function(img) {\n      object.mask = new fabric.Image(img, object.mask);\n      return fabric.Image.filters.BaseFilter.fromObject(object, callback);\n    });\n  };\n\n  /**\n   * Indicates that instances of this type are async\n   * @static\n   * @type Boolean\n   * @default\n   */\n  fabric.Image.filters.Mask.async = true;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Noise filter class\n   * @class fabric.Image.filters.Noise\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Noise#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Noise({\n   *   noise: 700\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Noise = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Noise.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Noise',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Noise.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.noise=0] Noise value\n     */\n    initialize: function(options) {\n      options = options || { };\n      this.noise = options.noise || 0;\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          noise = this.noise, rand;\n\n      for (var i = 0, len = data.length; i < len; i += 4) {\n\n        rand = (0.5 - Math.random()) * noise;\n\n        data[i] += rand;\n        data[i + 1] += rand;\n        data[i + 2] += rand;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        noise: this.noise\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Noise} Instance of fabric.Image.filters.Noise\n   */\n  fabric.Image.filters.Noise.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Pixelate filter class\n   * @class fabric.Image.filters.Pixelate\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Pixelate#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Pixelate({\n   *   blocksize: 8\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Pixelate = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Pixelate.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Pixelate',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Pixelate.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.blocksize=4] Blocksize for pixelate\n     */\n    initialize: function(options) {\n      options = options || { };\n      this.blocksize = options.blocksize || 4;\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          iLen = imageData.height,\n          jLen = imageData.width,\n          index, i, j, r, g, b, a;\n\n      for (i = 0; i < iLen; i += this.blocksize) {\n        for (j = 0; j < jLen; j += this.blocksize) {\n\n          index = (i * 4) * jLen + (j * 4);\n\n          r = data[index];\n          g = data[index + 1];\n          b = data[index + 2];\n          a = data[index + 3];\n\n          /*\n           blocksize: 4\n\n           [1,x,x,x,1]\n           [x,x,x,x,1]\n           [x,x,x,x,1]\n           [x,x,x,x,1]\n           [1,1,1,1,1]\n           */\n\n          for (var _i = i, _ilen = i + this.blocksize; _i < _ilen; _i++) {\n            for (var _j = j, _jlen = j + this.blocksize; _j < _jlen; _j++) {\n              index = (_i * 4) * jLen + (_j * 4);\n              data[index] = r;\n              data[index + 1] = g;\n              data[index + 2] = b;\n              data[index + 3] = a;\n            }\n          }\n        }\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        blocksize: this.blocksize\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Pixelate} Instance of fabric.Image.filters.Pixelate\n   */\n  fabric.Image.filters.Pixelate.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Remove white filter class\n   * @class fabric.Image.filters.RemoveWhite\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.RemoveWhite#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.RemoveWhite({\n   *   threshold: 40,\n   *   distance: 140\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.RemoveWhite = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.RemoveWhite.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'RemoveWhite',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.RemoveWhite.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.threshold=30] Threshold value\n     * @param {Number} [options.distance=20] Distance value\n     */\n    initialize: function(options) {\n      options = options || { };\n      this.threshold = options.threshold || 30;\n      this.distance = options.distance || 20;\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          threshold = this.threshold,\n          distance = this.distance,\n          limit = 255 - threshold,\n          abs = Math.abs,\n          r, g, b;\n\n      for (var i = 0, len = data.length; i < len; i += 4) {\n        r = data[i];\n        g = data[i + 1];\n        b = data[i + 2];\n\n        if (r > limit &&\n            g > limit &&\n            b > limit &&\n            abs(r - g) < distance &&\n            abs(r - b) < distance &&\n            abs(g - b) < distance\n        ) {\n          data[i + 3] = 0;\n        }\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        threshold: this.threshold,\n        distance: this.distance\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.RemoveWhite} Instance of fabric.Image.filters.RemoveWhite\n   */\n  fabric.Image.filters.RemoveWhite.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Sepia filter class\n   * @class fabric.Image.filters.Sepia\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Sepia();\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Sepia = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Sepia.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Sepia',\n\n    /**\n     * Applies filter to canvas element\n     * @memberOf fabric.Image.filters.Sepia.prototype\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          iLen = data.length, i, avg;\n\n      for (i = 0; i < iLen; i += 4) {\n        avg = 0.3  * data[i] + 0.59 * data[i + 1] + 0.11 * data[i + 2];\n        data[i] = avg + 100;\n        data[i + 1] = avg + 50;\n        data[i + 2] = avg + 255;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Sepia} Instance of fabric.Image.filters.Sepia\n   */\n  fabric.Image.filters.Sepia.fromObject = function(object, callback) {\n    object = object || { };\n    object.type = 'Sepia';\n    return new fabric.Image.filters.BaseFilter.fromObject(object, callback);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Sepia2 filter class\n   * @class fabric.Image.filters.Sepia2\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Sepia2();\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Sepia2 = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Sepia2.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Sepia2',\n\n    /**\n     * Applies filter to canvas element\n     * @memberOf fabric.Image.filters.Sepia.prototype\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          iLen = data.length, i, r, g, b;\n\n      for (i = 0; i < iLen; i += 4) {\n        r = data[i];\n        g = data[i + 1];\n        b = data[i + 2];\n\n        data[i] = (r * 0.393 + g * 0.769 + b * 0.189 ) / 1.351;\n        data[i + 1] = (r * 0.349 + g * 0.686 + b * 0.168 ) / 1.203;\n        data[i + 2] = (r * 0.272 + g * 0.534 + b * 0.131 ) / 2.140;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Sepia2} Instance of fabric.Image.filters.Sepia2\n   */\n  fabric.Image.filters.Sepia2.fromObject = function(object, callback) {\n    object = object || { };\n    object.type = 'Sepia2';\n    return new fabric.Image.filters.BaseFilter.fromObject(object, callback);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Tint filter class\n   * Adapted from <a href=\"https://github.com/mezzoblue/PaintbrushJS\">https://github.com/mezzoblue/PaintbrushJS</a>\n   * @class fabric.Image.filters.Tint\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Tint#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example <caption>Tint filter with hex color and opacity</caption>\n   * var filter = new fabric.Image.filters.Tint({\n   *   color: '#3513B0',\n   *   opacity: 0.5\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   * @example <caption>Tint filter with rgba color</caption>\n   * var filter = new fabric.Image.filters.Tint({\n   *   color: 'rgba(53, 21, 176, 0.5)'\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Tint = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Tint.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Tint',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Tint.prototype\n     * @param {Object} [options] Options object\n     * @param {String} [options.color=#000000] Color to tint the image with\n     * @param {Number} [options.opacity] Opacity value that controls the tint effect's transparency (0..1)\n     */\n    initialize: function(options) {\n      options = options || { };\n\n      this.color = options.color || '#000000';\n      this.opacity = typeof options.opacity !== 'undefined'\n                      ? options.opacity\n                      : new fabric.Color(this.color).getAlpha();\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          iLen = data.length, i,\n          tintR, tintG, tintB,\n          r, g, b, alpha1,\n          source;\n\n      source = new fabric.Color(this.color).getSource();\n\n      tintR = source[0] * this.opacity;\n      tintG = source[1] * this.opacity;\n      tintB = source[2] * this.opacity;\n\n      alpha1 = 1 - this.opacity;\n\n      for (i = 0; i < iLen; i += 4) {\n        r = data[i];\n        g = data[i + 1];\n        b = data[i + 2];\n\n        // alpha compositing\n        data[i] = tintR + r * alpha1;\n        data[i + 1] = tintG + g * alpha1;\n        data[i + 2] = tintB + b * alpha1;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        color: this.color,\n        opacity: this.opacity\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Tint} Instance of fabric.Image.filters.Tint\n   */\n  fabric.Image.filters.Tint.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Multiply filter class\n   * Adapted from <a href=\"http://www.laurenscorijn.com/articles/colormath-basics\">http://www.laurenscorijn.com/articles/colormath-basics</a>\n   * @class fabric.Image.filters.Multiply\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @example <caption>Multiply filter with hex color</caption>\n   * var filter = new fabric.Image.filters.Multiply({\n   *   color: '#F0F'\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   * @example <caption>Multiply filter with rgb color</caption>\n   * var filter = new fabric.Image.filters.Multiply({\n   *   color: 'rgb(53, 21, 176)'\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Multiply = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Multiply.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Multiply',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Multiply.prototype\n     * @param {Object} [options] Options object\n     * @param {String} [options.color=#000000] Color to multiply the image pixels with\n     */\n    initialize: function(options) {\n      options = options || { };\n\n      this.color = options.color || '#000000';\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          iLen = data.length, i,\n          source;\n\n      source = new fabric.Color(this.color).getSource();\n\n      for (i = 0; i < iLen; i += 4) {\n        data[i] *= source[0] / 255;\n        data[i + 1] *= source[1] / 255;\n        data[i + 2] *= source[2] / 255;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        color: this.color\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Multiply} Instance of fabric.Image.filters.Multiply\n   */\n  fabric.Image.filters.Multiply.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n  'use strict';\n\n  var fabric = global.fabric,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Color Blend filter class\n   * @class fabric.Image.filter.Blend\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @example\n   * var filter = new fabric.Image.filters.Blend({\n   *  color: '#000',\n   *  mode: 'multiply'\n   * });\n   *\n   * var filter = new fabric.Image.filters.Blend({\n   *  image: fabricImageObject,\n   *  mode: 'multiply',\n   *  alpha: 0.5\n   * });\n\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n\n  filters.Blend = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Blend.prototype */ {\n    type: 'Blend',\n\n    initialize: function(options) {\n      options = options || {};\n      this.color = options.color || '#000';\n      this.image = options.image || false;\n      this.mode = options.mode || 'multiply';\n      this.alpha = options.alpha || 1;\n    },\n\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          tr, tg, tb,\n          r, g, b,\n          _r, _g, _b,\n          source,\n          isImage = false;\n\n      if (this.image) {\n        // Blend images\n        isImage = true;\n\n        var _el = fabric.util.createCanvasElement();\n        _el.width = this.image.width;\n        _el.height = this.image.height;\n\n        var tmpCanvas = new fabric.StaticCanvas(_el);\n        tmpCanvas.add(this.image);\n        var context2 =  tmpCanvas.getContext('2d');\n        source = context2.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height).data;\n      }\n      else {\n        // Blend color\n        source = new fabric.Color(this.color).getSource();\n\n        tr = source[0] * this.alpha;\n        tg = source[1] * this.alpha;\n        tb = source[2] * this.alpha;\n      }\n\n      for (var i = 0, len = data.length; i < len; i += 4) {\n\n        r = data[i];\n        g = data[i + 1];\n        b = data[i + 2];\n\n        if (isImage) {\n          tr = source[i] * this.alpha;\n          tg = source[i + 1] * this.alpha;\n          tb = source[i + 2] * this.alpha;\n        }\n\n        switch (this.mode) {\n          case 'multiply':\n            data[i] = r * tr / 255;\n            data[i + 1] = g * tg / 255;\n            data[i + 2] = b * tb / 255;\n            break;\n          case 'screen':\n            data[i] = 1 - (1 - r) * (1 - tr);\n            data[i + 1] = 1 - (1 - g) * (1 - tg);\n            data[i + 2] = 1 - (1 - b) * (1 - tb);\n            break;\n          case 'add':\n            data[i] = Math.min(255, r + tr);\n            data[i + 1] = Math.min(255, g + tg);\n            data[i + 2] = Math.min(255, b + tb);\n            break;\n          case 'diff':\n          case 'difference':\n            data[i] = Math.abs(r - tr);\n            data[i + 1] = Math.abs(g - tg);\n            data[i + 2] = Math.abs(b - tb);\n            break;\n          case 'subtract':\n            _r = r - tr;\n            _g = g - tg;\n            _b = b - tb;\n\n            data[i] = (_r < 0) ? 0 : _r;\n            data[i + 1] = (_g < 0) ? 0 : _g;\n            data[i + 2] = (_b < 0) ? 0 : _b;\n            break;\n          case 'darken':\n            data[i] = Math.min(r, tr);\n            data[i + 1] = Math.min(g, tg);\n            data[i + 2] = Math.min(b, tb);\n            break;\n          case 'lighten':\n            data[i] = Math.max(r, tr);\n            data[i + 1] = Math.max(g, tg);\n            data[i + 2] = Math.max(b, tb);\n            break;\n        }\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return {\n        color: this.color,\n        image: this.image,\n        mode: this.mode,\n        alpha: this.alpha\n      };\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Blend} Instance of fabric.Image.filters.Blend\n   */\n  fabric.Image.filters.Blend.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }), pow = Math.pow, floor = Math.floor,\n      sqrt = Math.sqrt, abs = Math.abs, max = Math.max, round = Math.round, sin = Math.sin,\n      ceil = Math.ceil,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Resize image filter class\n   * @class fabric.Image.filters.Resize\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Resize();\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Resize = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Resize.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Resize',\n\n    /**\n     * Resize type\n     * @param {String} resizeType\n     * @default\n     */\n    resizeType: 'hermite',\n\n    /**\n     * Scale factor for resizing, x axis\n     * @param {Number} scaleX\n     * @default\n     */\n    scaleX: 0,\n\n    /**\n     * Scale factor for resizing, y axis\n     * @param {Number} scaleY\n     * @default\n     */\n    scaleY: 0,\n\n    /**\n     * LanczosLobes parameter for lanczos filter\n     * @param {Number} lanczosLobes\n     * @default\n     */\n    lanczosLobes: 3,\n\n    /**\n     * Applies filter to canvas element\n     * @memberOf fabric.Image.filters.Resize.prototype\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} scaleX\n     * @param {Number} scaleY\n     */\n    applyTo: function(canvasEl, scaleX, scaleY) {\n      if (scaleX === 1 && scaleY === 1) {\n        return;\n      }\n\n      this.rcpScaleX = 1 / scaleX;\n      this.rcpScaleY = 1 / scaleY;\n\n      var oW = canvasEl.width, oH = canvasEl.height,\n          dW = round(oW * scaleX), dH = round(oH * scaleY),\n          imageData;\n\n      if (this.resizeType === 'sliceHack') {\n        imageData = this.sliceByTwo(canvasEl, oW, oH, dW, dH);\n      }\n      if (this.resizeType === 'hermite') {\n        imageData = this.hermiteFastResize(canvasEl, oW, oH, dW, dH);\n      }\n      if (this.resizeType === 'bilinear') {\n        imageData = this.bilinearFiltering(canvasEl, oW, oH, dW, dH);\n      }\n      if (this.resizeType === 'lanczos') {\n        imageData = this.lanczosResize(canvasEl, oW, oH, dW, dH);\n      }\n      canvasEl.width = dW;\n      canvasEl.height = dH;\n      canvasEl.getContext('2d').putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Filter sliceByTwo\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} oW Original Width\n     * @param {Number} oH Original Height\n     * @param {Number} dW Destination Width\n     * @param {Number} dH Destination Height\n     * @returns {ImageData}\n     */\n    sliceByTwo: function(canvasEl, oW, oH, dW, dH) {\n      var context = canvasEl.getContext('2d'), imageData,\n          multW = 0.5, multH = 0.5, signW = 1, signH = 1,\n          doneW = false, doneH = false, stepW = oW, stepH = oH,\n          tmpCanvas = fabric.util.createCanvasElement(),\n          tmpCtx = tmpCanvas.getContext('2d');\n      dW = floor(dW);\n      dH = floor(dH);\n      tmpCanvas.width = max(dW, oW);\n      tmpCanvas.height = max(dH, oH);\n\n      if (dW > oW) {\n        multW = 2;\n        signW = -1;\n      }\n      if (dH > oH) {\n        multH = 2;\n        signH = -1;\n      }\n      imageData = context.getImageData(0, 0, oW, oH);\n      canvasEl.width = max(dW, oW);\n      canvasEl.height = max(dH, oH);\n      context.putImageData(imageData, 0, 0);\n\n      while (!doneW || !doneH) {\n        oW = stepW;\n        oH = stepH;\n        if (dW * signW < floor(stepW * multW * signW)) {\n          stepW = floor(stepW * multW);\n        }\n        else {\n          stepW = dW;\n          doneW = true;\n        }\n        if (dH * signH < floor(stepH * multH * signH)) {\n          stepH = floor(stepH * multH);\n        }\n        else {\n          stepH = dH;\n          doneH = true;\n        }\n        imageData = context.getImageData(0, 0, oW, oH);\n        tmpCtx.putImageData(imageData, 0, 0);\n        context.clearRect(0, 0, stepW, stepH);\n        context.drawImage(tmpCanvas, 0, 0, oW, oH, 0, 0, stepW, stepH);\n      }\n      return context.getImageData(0, 0, dW, dH);\n    },\n\n    /**\n     * Filter lanczosResize\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} oW Original Width\n     * @param {Number} oH Original Height\n     * @param {Number} dW Destination Width\n     * @param {Number} dH Destination Height\n     * @returns {ImageData}\n     */\n    lanczosResize: function(canvasEl, oW, oH, dW, dH) {\n\n      function lanczosCreate(lobes) {\n        return function(x) {\n          if (x > lobes) {\n            return 0;\n          }\n          x *= Math.PI;\n          if (abs(x) < 1e-16) {\n            return 1;\n          }\n          var xx = x / lobes;\n          return sin(x) * sin(xx) / x / xx;\n        };\n      }\n\n      function process(u) {\n        var v, i, weight, idx, a, red, green,\n            blue, alpha, fX, fY;\n        center.x = (u + 0.5) * ratioX;\n        icenter.x = floor(center.x);\n        for (v = 0; v < dH; v++) {\n          center.y = (v + 0.5) * ratioY;\n          icenter.y = floor(center.y);\n          a = 0; red = 0; green = 0; blue = 0; alpha = 0;\n          for (i = icenter.x - range2X; i <= icenter.x + range2X; i++) {\n            if (i < 0 || i >= oW) {\n              continue;\n            }\n            fX = floor(1000 * abs(i - center.x));\n            if (!cacheLanc[fX]) {\n              cacheLanc[fX] = { };\n            }\n            for (var j = icenter.y - range2Y; j <= icenter.y + range2Y; j++) {\n              if (j < 0 || j >= oH) {\n                continue;\n              }\n              fY = floor(1000 * abs(j - center.y));\n              if (!cacheLanc[fX][fY]) {\n                cacheLanc[fX][fY] = lanczos(sqrt(pow(fX * rcpRatioX, 2) + pow(fY * rcpRatioY, 2)) / 1000);\n              }\n              weight = cacheLanc[fX][fY];\n              if (weight > 0) {\n                idx = (j * oW + i) * 4;\n                a += weight;\n                red += weight * srcData[idx];\n                green += weight * srcData[idx + 1];\n                blue += weight * srcData[idx + 2];\n                alpha += weight * srcData[idx + 3];\n              }\n            }\n          }\n          idx = (v * dW + u) * 4;\n          destData[idx] = red / a;\n          destData[idx + 1] = green / a;\n          destData[idx + 2] = blue / a;\n          destData[idx + 3] = alpha / a;\n        }\n\n        if (++u < dW) {\n          return process(u);\n        }\n        else {\n          return destImg;\n        }\n      }\n\n      var context = canvasEl.getContext('2d'),\n          srcImg = context.getImageData(0, 0, oW, oH),\n          destImg = context.getImageData(0, 0, dW, dH),\n          srcData = srcImg.data, destData = destImg.data,\n          lanczos = lanczosCreate(this.lanczosLobes),\n          ratioX = this.rcpScaleX, ratioY = this.rcpScaleY,\n          rcpRatioX = 2 / this.rcpScaleX, rcpRatioY = 2 / this.rcpScaleY,\n          range2X = ceil(ratioX * this.lanczosLobes / 2),\n          range2Y = ceil(ratioY * this.lanczosLobes / 2),\n          cacheLanc = { }, center = { }, icenter = { };\n\n      return process(0);\n    },\n\n    /**\n     * bilinearFiltering\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} oW Original Width\n     * @param {Number} oH Original Height\n     * @param {Number} dW Destination Width\n     * @param {Number} dH Destination Height\n     * @returns {ImageData}\n     */\n    bilinearFiltering: function(canvasEl, oW, oH, dW, dH) {\n      var a, b, c, d, x, y, i, j, xDiff, yDiff, chnl,\n          color, offset = 0, origPix, ratioX = this.rcpScaleX,\n          ratioY = this.rcpScaleY, context = canvasEl.getContext('2d'),\n          w4 = 4 * (oW - 1), img = context.getImageData(0, 0, oW, oH),\n          pixels = img.data, destImage = context.getImageData(0, 0, dW, dH),\n          destPixels = destImage.data;\n      for (i = 0; i < dH; i++) {\n        for (j = 0; j < dW; j++) {\n          x = floor(ratioX * j);\n          y = floor(ratioY * i);\n          xDiff = ratioX * j - x;\n          yDiff = ratioY * i - y;\n          origPix = 4 * (y * oW + x);\n\n          for (chnl = 0; chnl < 4; chnl++) {\n            a = pixels[origPix + chnl];\n            b = pixels[origPix + 4 + chnl];\n            c = pixels[origPix + w4 + chnl];\n            d = pixels[origPix + w4 + 4 + chnl];\n            color = a * (1 - xDiff) * (1 - yDiff) + b * xDiff * (1 - yDiff) +\n                    c * yDiff * (1 - xDiff) + d * xDiff * yDiff;\n            destPixels[offset++] = color;\n          }\n        }\n      }\n      return destImage;\n    },\n\n    /**\n     * hermiteFastResize\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} oW Original Width\n     * @param {Number} oH Original Height\n     * @param {Number} dW Destination Width\n     * @param {Number} dH Destination Height\n     * @returns {ImageData}\n     */\n    hermiteFastResize: function(canvasEl, oW, oH, dW, dH) {\n      var ratioW = this.rcpScaleX, ratioH = this.rcpScaleY,\n          ratioWHalf = ceil(ratioW / 2),\n          ratioHHalf = ceil(ratioH / 2),\n          context = canvasEl.getContext('2d'),\n          img = context.getImageData(0, 0, oW, oH), data = img.data,\n          img2 = context.getImageData(0, 0, dW, dH), data2 = img2.data;\n      for (var j = 0; j < dH; j++) {\n        for (var i = 0; i < dW; i++) {\n          var x2 = (i + j * dW) * 4, weight = 0, weights = 0, weightsAlpha = 0,\n              gxR = 0, gxG = 0, gxB = 0, gxA = 0, centerY = (j + 0.5) * ratioH;\n          for (var yy = floor(j * ratioH); yy < (j + 1) * ratioH; yy++) {\n            var dy = abs(centerY - (yy + 0.5)) / ratioHHalf,\n                centerX = (i + 0.5) * ratioW, w0 = dy * dy;\n            for (var xx = floor(i * ratioW); xx < (i + 1) * ratioW; xx++) {\n              var dx = abs(centerX - (xx + 0.5)) / ratioWHalf,\n                  w = sqrt(w0 + dx * dx);\n              /* eslint-disable max-depth */\n              if (w > 1 && w < -1) {\n                continue;\n              }\n              //hermite filter\n              weight = 2 * w * w * w - 3 * w * w + 1;\n              if (weight > 0) {\n                dx = 4 * (xx + yy * oW);\n                //alpha\n                gxA += weight * data[dx + 3];\n                weightsAlpha += weight;\n                //colors\n                if (data[dx + 3] < 255) {\n                  weight = weight * data[dx + 3] / 250;\n                }\n                gxR += weight * data[dx];\n                gxG += weight * data[dx + 1];\n                gxB += weight * data[dx + 2];\n                weights += weight;\n              }\n              /* eslint-enable max-depth */\n            }\n          }\n          data2[x2] = gxR / weights;\n          data2[x2 + 1] = gxG / weights;\n          data2[x2 + 2] = gxB / weights;\n          data2[x2 + 3] = gxA / weightsAlpha;\n        }\n      }\n      return img2;\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return {\n        type: this.type,\n        scaleX: this.scaleX,\n        scaleY: this.scaleY,\n        resizeType: this.resizeType,\n        lanczosLobes: this.lanczosLobes\n      };\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Resize} Instance of fabric.Image.filters.Resize\n   */\n  fabric.Image.filters.Resize.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Color Matrix filter class\n   * @class fabric.Image.filters.ColorMatrix\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.ColorMatrix#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @see {@Link http://www.webwasp.co.uk/tutorials/219/Color_Matrix_Filter.php}\n   * @see {@Link http://phoboslab.org/log/2013/11/fast-image-filters-with-webgl}\n   * @example <caption>Kodachrome filter</caption>\n   * var filter = new fabric.Image.filters.ColorMatrix({\n   *  matrix: [\n       1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502,\n       -0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203,\n       -0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946,\n       0, 0, 0, 1, 0\n      ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.ColorMatrix = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.ColorMatrix.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'ColorMatrix',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.ColorMatrix.prototype\n     * @param {Object} [options] Options object\n     * @param {Array} [options.matrix] Color Matrix to modify the image data with\n     */\n    initialize: function( options ) {\n      options || ( options = {} );\n      this.matrix = options.matrix || [\n        1, 0, 0, 0, 0,\n        0, 1, 0, 0, 0,\n        0, 0, 1, 0, 0,\n        0, 0, 0, 1, 0\n      ];\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function( canvasEl ) {\n      var context = canvasEl.getContext( '2d' ),\n          imageData = context.getImageData( 0, 0, canvasEl.width, canvasEl.height ),\n          data = imageData.data,\n          iLen = data.length,\n          i,\n          r,\n          g,\n          b,\n          a,\n          m = this.matrix;\n\n      for ( i = 0; i < iLen; i += 4 ) {\n        r = data[ i ];\n        g = data[ i + 1 ];\n        b = data[ i + 2 ];\n        a = data[ i + 3 ];\n\n        data[ i ] = r * m[ 0 ] + g * m[ 1 ] + b * m[ 2 ] + a * m[ 3 ] + m[ 4 ];\n        data[ i + 1 ] = r * m[ 5 ] + g * m[ 6 ] + b * m[ 7 ] + a * m[ 8 ] + m[ 9 ];\n        data[ i + 2 ] = r * m[ 10 ] + g * m[ 11 ] + b * m[ 12 ] + a * m[ 13 ] + m[ 14 ];\n        data[ i + 3 ] = r * m[ 15 ] + g * m[ 16 ] + b * m[ 17 ] + a * m[ 18 ] + m[ 19 ];\n      }\n\n      context.putImageData( imageData, 0, 0 );\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        type: this.type,\n        matrix: this.matrix\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] function to invoke after filter creation\n   * @return {fabric.Image.filters.ColorMatrix} Instance of fabric.Image.filters.ColorMatrix\n   */\n  fabric.Image.filters.ColorMatrix.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Contrast filter class\n   * @class fabric.Image.filters.Contrast\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Contrast#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Contrast({\n   *   contrast: 40\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Contrast = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Contrast.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Contrast',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Contrast.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.contrast=0] Value to contrast the image up (-255...255)\n     */\n    initialize: function(options) {\n      options = options || { };\n      this.contrast = options.contrast || 0;\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          contrastF = 259 * (this.contrast + 255) / (255 * (259 - this.contrast));\n\n      for (var i = 0, len = data.length; i < len; i += 4) {\n        data[i] = contrastF * (data[i] - 128) + 128;\n        data[i + 1] = contrastF * (data[i + 1] - 128) + 128;\n        data[i + 2] = contrastF * (data[i + 2] - 128) + 128;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        contrast: this.contrast\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Contrast} Instance of fabric.Image.filters.Contrast\n   */\n  fabric.Image.filters.Contrast.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Saturate filter class\n   * @class fabric.Image.filters.Saturate\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Saturate#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Saturate({\n   *   saturate: 100\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Saturate = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Saturate.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Saturate',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Saturate.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.saturate=0] Value to saturate the image (-100...100)\n     */\n    initialize: function(options) {\n      options = options || { };\n      this.saturate = options.saturate || 0;\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo: function(canvasEl) {\n      var context = canvasEl.getContext('2d'),\n          imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),\n          data = imageData.data,\n          max, adjust = -this.saturate * 0.01;\n\n      for (var i = 0, len = data.length; i < len; i += 4) {\n        max = Math.max(data[i], data[i + 1], data[i + 2]);\n        data[i] += max !== data[i] ? (max - data[i]) * adjust : 0;\n        data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * adjust : 0;\n        data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * adjust : 0;\n      }\n\n      context.putImageData(imageData, 0, 0);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        saturate: this.saturate\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Saturate} Instance of fabric.Image.filters.Saturate\n   */\n  fabric.Image.filters.Saturate.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      toFixed = fabric.util.toFixed,\n      NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n      MIN_TEXT_WIDTH = 2;\n\n  if (fabric.Text) {\n    fabric.warn('fabric.Text is already defined');\n    return;\n  }\n\n  /**\n   * Text class\n   * @class fabric.Text\n   * @extends fabric.Object\n   * @return {fabric.Text} thisArg\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#text}\n   * @see {@link fabric.Text#initialize} for constructor definition\n   */\n  fabric.Text = fabric.util.createClass(fabric.Object, /** @lends fabric.Text.prototype */ {\n\n    /**\n     * Properties which when set cause object to change dimensions\n     * @type Object\n     * @private\n     */\n    _dimensionAffectingProps: [\n      'fontSize',\n      'fontWeight',\n      'fontFamily',\n      'fontStyle',\n      'lineHeight',\n      'text',\n      'charSpacing',\n      'textAlign'\n    ],\n\n    /**\n     * @private\n     */\n    _reNewline: /\\r?\\n/,\n\n    /**\n     * Use this regular expression to filter for whitespace that is not a new line.\n     * Mostly used when text is 'justify' aligned.\n     * @private\n     */\n    _reSpacesAndTabs: /[ \\t\\r]+/g,\n\n    /**\n     * Retrieves object's fontSize\n     * @method getFontSize\n     * @memberOf fabric.Text.prototype\n     * @return {String} Font size (in pixels)\n     */\n\n    /**\n     * Sets object's fontSize\n     * Does not update the object .width and .height,\n     * call ._initDimensions() to update the values.\n     * @method setFontSize\n     * @memberOf fabric.Text.prototype\n     * @param {Number} fontSize Font size (in pixels)\n     * @return {fabric.Text}\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's fontWeight\n     * @method getFontWeight\n     * @memberOf fabric.Text.prototype\n     * @return {(String|Number)} Font weight\n     */\n\n    /**\n     * Sets object's fontWeight\n     * Does not update the object .width and .height,\n     * call ._initDimensions() to update the values.\n     * @method setFontWeight\n     * @memberOf fabric.Text.prototype\n     * @param {(Number|String)} fontWeight Font weight\n     * @return {fabric.Text}\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's fontFamily\n     * @method getFontFamily\n     * @memberOf fabric.Text.prototype\n     * @return {String} Font family\n     */\n\n    /**\n     * Sets object's fontFamily\n     * Does not update the object .width and .height,\n     * call ._initDimensions() to update the values.\n     * @method setFontFamily\n     * @memberOf fabric.Text.prototype\n     * @param {String} fontFamily Font family\n     * @return {fabric.Text}\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's text\n     * @method getText\n     * @memberOf fabric.Text.prototype\n     * @return {String} text\n     */\n\n    /**\n     * Sets object's text\n     * Does not update the object .width and .height,\n     * call ._initDimensions() to update the values.\n     * @method setText\n     * @memberOf fabric.Text.prototype\n     * @param {String} text Text\n     * @return {fabric.Text}\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's textDecoration\n     * @method getTextDecoration\n     * @memberOf fabric.Text.prototype\n     * @return {String} Text decoration\n     */\n\n    /**\n     * Sets object's textDecoration\n     * @method setTextDecoration\n     * @memberOf fabric.Text.prototype\n     * @param {String} textDecoration Text decoration\n     * @return {fabric.Text}\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's fontStyle\n     * @method getFontStyle\n     * @memberOf fabric.Text.prototype\n     * @return {String} Font style\n     */\n\n    /**\n     * Sets object's fontStyle\n     * Does not update the object .width and .height,\n     * call ._initDimensions() to update the values.\n     * @method setFontStyle\n     * @memberOf fabric.Text.prototype\n     * @param {String} fontStyle Font style\n     * @return {fabric.Text}\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's lineHeight\n     * @method getLineHeight\n     * @memberOf fabric.Text.prototype\n     * @return {Number} Line height\n     */\n\n    /**\n     * Sets object's lineHeight\n     * @method setLineHeight\n     * @memberOf fabric.Text.prototype\n     * @param {Number} lineHeight Line height\n     * @return {fabric.Text}\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's textAlign\n     * @method getTextAlign\n     * @memberOf fabric.Text.prototype\n     * @return {String} Text alignment\n     */\n\n    /**\n     * Sets object's textAlign\n     * @method setTextAlign\n     * @memberOf fabric.Text.prototype\n     * @param {String} textAlign Text alignment\n     * @return {fabric.Text}\n     * @chainable\n     */\n\n    /**\n     * Retrieves object's textBackgroundColor\n     * @method getTextBackgroundColor\n     * @memberOf fabric.Text.prototype\n     * @return {String} Text background color\n     */\n\n    /**\n     * Sets object's textBackgroundColor\n     * @method setTextBackgroundColor\n     * @memberOf fabric.Text.prototype\n     * @param {String} textBackgroundColor Text background color\n     * @return {fabric.Text}\n     * @chainable\n     */\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type:                 'text',\n\n    /**\n     * Font size (in pixels)\n     * @type Number\n     * @default\n     */\n    fontSize:             40,\n\n    /**\n     * Font weight (e.g. bold, normal, 400, 600, 800)\n     * @type {(Number|String)}\n     * @default\n     */\n    fontWeight:           'normal',\n\n    /**\n     * Font family\n     * @type String\n     * @default\n     */\n    fontFamily:           'Times New Roman',\n\n    /**\n     * Text decoration Possible values: \"\", \"underline\", \"overline\" or \"line-through\".\n     * @type String\n     * @default\n     */\n    textDecoration:       '',\n\n    /**\n     * Text alignment. Possible values: \"left\", \"center\", \"right\" or \"justify\".\n     * @type String\n     * @default\n     */\n    textAlign:            'left',\n\n    /**\n     * Font style . Possible values: \"\", \"normal\", \"italic\" or \"oblique\".\n     * @type String\n     * @default\n     */\n    fontStyle:            '',\n\n    /**\n     * Line height\n     * @type Number\n     * @default\n     */\n    lineHeight:           1.16,\n\n    /**\n     * Background color of text lines\n     * @type String\n     * @default\n     */\n    textBackgroundColor:  '',\n\n    /**\n     * List of properties to consider when checking if\n     * state of an object is changed ({@link fabric.Object#hasStateChanged})\n     * as well as for history (undo/redo) purposes\n     * @type Array\n     */\n    stateProperties: fabric.Object.prototype.stateProperties.concat(\n      'fontFamily',\n      'fontWeight',\n      'fontSize',\n      'text',\n      'textDecoration',\n      'textAlign',\n      'fontStyle',\n      'lineHeight',\n      'textBackgroundColor',\n      'charSpacing'),\n\n    /**\n     * List of properties to consider when checking if cache needs refresh\n     * @type Array\n     */\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat(\n      'fontFamily',\n      'fontWeight',\n      'fontSize',\n      'text',\n      'textDecoration',\n      'textAlign',\n      'fontStyle',\n      'lineHeight',\n      'textBackgroundColor',\n      'charSpacing',\n      'styles'),\n\n    /**\n     * When defined, an object is rendered via stroke and this property specifies its color.\n     * <b>Backwards incompatibility note:</b> This property was named \"strokeStyle\" until v1.1.6\n     * @type String\n     * @default\n     */\n    stroke:               null,\n\n    /**\n     * Shadow object representing shadow of this shape.\n     * <b>Backwards incompatibility note:</b> This property was named \"textShadow\" (String) until v1.2.11\n     * @type fabric.Shadow\n     * @default\n     */\n    shadow:               null,\n\n    /**\n     * @private\n     */\n    _fontSizeFraction: 0.25,\n\n    /**\n     * Text Line proportion to font Size (in pixels)\n     * @type Number\n     * @default\n     */\n    _fontSizeMult:             1.13,\n\n    /**\n     * additional space between characters\n     * expressed in thousands of em unit\n     * @type Number\n     * @default\n     */\n    charSpacing:             0,\n\n    /**\n     * Constructor\n     * @param {String} text Text string\n     * @param {Object} [options] Options object\n     * @return {fabric.Text} thisArg\n     */\n    initialize: function(text, options) {\n      options = options || { };\n      this.text = text;\n      this.__skipDimension = true;\n      this.callSuper('initialize', options);\n      this.__skipDimension = false;\n      this._initDimensions();\n      this.setCoords();\n      this.setupState({ propertySet: '_dimensionAffectingProps' });\n    },\n\n    /**\n     * Initialize text dimensions. Render all text on given context\n     * or on a offscreen canvas to get the text width with measureText.\n     * Updates this.width and this.height with the proper values.\n     * Does not return dimensions.\n     * @param {CanvasRenderingContext2D} [ctx] Context to render on\n     * @private\n     */\n    _initDimensions: function(ctx) {\n      if (this.__skipDimension) {\n        return;\n      }\n      if (!ctx) {\n        ctx = fabric.util.createCanvasElement().getContext('2d');\n        this._setTextStyles(ctx);\n      }\n      this._textLines = this._splitTextIntoLines();\n      this._clearCache();\n      this.width = this._getTextWidth(ctx) || this.cursorWidth || MIN_TEXT_WIDTH;\n      this.height = this._getTextHeight(ctx);\n      this.setCoords();\n    },\n\n    /**\n     * Returns string representation of an instance\n     * @return {String} String representation of text object\n     */\n    toString: function() {\n      return '#<fabric.Text (' + this.complexity() +\n        '): { \"text\": \"' + this.text + '\", \"fontFamily\": \"' + this.fontFamily + '\" }>';\n    },\n\n    /**\n     * Return the dimension and the zoom level needed to create a cache canvas\n     * big enough to host the object to be cached.\n     * @private\n     * @param {Object} dim.x width of object to be cached\n     * @param {Object} dim.y height of object to be cached\n     * @return {Object}.width width of canvas\n     * @return {Object}.height height of canvas\n     * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n     * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n     */\n    _getCacheCanvasDimensions: function() {\n      var dims = this.callSuper('_getCacheCanvasDimensions');\n      var fontSize = this.fontSize;\n      dims.width += fontSize * dims.zoomX;\n      dims.height += fontSize * dims.zoomY;\n      return dims;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      this._setTextStyles(ctx);\n      if (this.group && this.group.type === 'path-group') {\n        ctx.translate(this.left, this.top);\n      }\n      this._renderTextLinesBackground(ctx);\n      this._renderText(ctx);\n      this._renderTextDecoration(ctx);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderText: function(ctx) {\n      this._renderTextFill(ctx);\n      this._renderTextStroke(ctx);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _setTextStyles: function(ctx) {\n      ctx.textBaseline = 'alphabetic';\n      ctx.font = this._getFontDeclaration();\n    },\n\n    /**\n     * @private\n     * @return {Number} Height of fabric.Text object\n     */\n    _getTextHeight: function() {\n      return this._getHeightOfSingleLine() + (this._textLines.length - 1) * this._getHeightOfLine();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @return {Number} Maximum width of fabric.Text object\n     */\n    _getTextWidth: function(ctx) {\n      var maxWidth = this._getLineWidth(ctx, 0);\n\n      for (var i = 1, len = this._textLines.length; i < len; i++) {\n        var currentLineWidth = this._getLineWidth(ctx, i);\n        if (currentLineWidth > maxWidth) {\n          maxWidth = currentLineWidth;\n        }\n      }\n      return maxWidth;\n    },\n\n    /**\n     * @private\n     * @param {String} method Method name (\"fillText\" or \"strokeText\")\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} chars Chars to render\n     * @param {Number} left Left position of text\n     * @param {Number} top Top position of text\n     */\n    _renderChars: function(method, ctx, chars, left, top) {\n      // remove Text word from method var\n      var shortM = method.slice(0, -4), _char, width;\n      if (this[shortM].toLive) {\n        var offsetX = -this.width / 2 + this[shortM].offsetX || 0,\n            offsetY = -this.height / 2 + this[shortM].offsetY || 0;\n        ctx.save();\n        ctx.translate(offsetX, offsetY);\n        left -= offsetX;\n        top -= offsetY;\n      }\n      if (this.charSpacing !== 0) {\n        var additionalSpace = this._getWidthOfCharSpacing();\n        chars = chars.split('');\n        for (var i = 0, len = chars.length; i < len; i++) {\n          _char = chars[i];\n          width = ctx.measureText(_char).width + additionalSpace;\n          ctx[method](_char, left, top);\n          left += width > 0 ? width : 0;\n        }\n      }\n      else {\n        ctx[method](chars, left, top);\n      }\n      this[shortM].toLive && ctx.restore();\n    },\n\n    /**\n     * @private\n     * @param {String} method Method name (\"fillText\" or \"strokeText\")\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} line Text to render\n     * @param {Number} left Left position of text\n     * @param {Number} top Top position of text\n     * @param {Number} lineIndex Index of a line in a text\n     */\n    _renderTextLine: function(method, ctx, line, left, top, lineIndex) {\n      // lift the line by quarter of fontSize\n      top -= this.fontSize * this._fontSizeFraction;\n\n      // short-circuit\n      var lineWidth = this._getLineWidth(ctx, lineIndex);\n      if (this.textAlign !== 'justify' || this.width < lineWidth) {\n        this._renderChars(method, ctx, line, left, top, lineIndex);\n        return;\n      }\n\n      // stretch the line\n      var words = line.split(/\\s+/),\n          charOffset = 0,\n          wordsWidth = this._getWidthOfWords(ctx, words.join(' '), lineIndex, 0),\n          widthDiff = this.width - wordsWidth,\n          numSpaces = words.length - 1,\n          spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0,\n          leftOffset = 0, word;\n\n      for (var i = 0, len = words.length; i < len; i++) {\n        while (line[charOffset] === ' ' && charOffset < line.length) {\n          charOffset++;\n        }\n        word = words[i];\n        this._renderChars(method, ctx, word, left + leftOffset, top, lineIndex, charOffset);\n        leftOffset += this._getWidthOfWords(ctx, word, lineIndex, charOffset) + spaceWidth;\n        charOffset += word.length;\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} word\n     */\n    _getWidthOfWords: function (ctx, word) {\n      var width = ctx.measureText(word).width, charCount, additionalSpace;\n      if (this.charSpacing !== 0) {\n        charCount = word.split('').length;\n        additionalSpace = charCount * this._getWidthOfCharSpacing();\n        width += additionalSpace;\n      }\n      return width > 0 ? width : 0;\n    },\n\n    /**\n     * @private\n     * @return {Number} Left offset\n     */\n    _getLeftOffset: function() {\n      return -this.width / 2;\n    },\n\n    /**\n     * @private\n     * @return {Number} Top offset\n     */\n    _getTopOffset: function() {\n      return -this.height / 2;\n    },\n\n    /**\n     * Returns true because text has no style\n     */\n    isEmptyStyles: function() {\n      return true;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} method Method name (\"fillText\" or \"strokeText\")\n     */\n    _renderTextCommon: function(ctx, method) {\n\n      var lineHeights = 0, left = this._getLeftOffset(), top = this._getTopOffset();\n\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        var heightOfLine = this._getHeightOfLine(ctx, i),\n            maxHeight = heightOfLine / this.lineHeight,\n            lineWidth = this._getLineWidth(ctx, i),\n            leftOffset = this._getLineLeftOffset(lineWidth);\n        this._renderTextLine(\n          method,\n          ctx,\n          this._textLines[i],\n          left + leftOffset,\n          top + lineHeights + maxHeight,\n          i\n        );\n        lineHeights += heightOfLine;\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextFill: function(ctx) {\n      if (!this.fill && this.isEmptyStyles()) {\n        return;\n      }\n\n      this._renderTextCommon(ctx, 'fillText');\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextStroke: function(ctx) {\n      if ((!this.stroke || this.strokeWidth === 0) && this.isEmptyStyles()) {\n        return;\n      }\n\n      if (this.shadow && !this.shadow.affectStroke) {\n        this._removeShadow(ctx);\n      }\n\n      ctx.save();\n      this._setLineDash(ctx, this.strokeDashArray);\n      ctx.beginPath();\n      this._renderTextCommon(ctx, 'strokeText');\n      ctx.closePath();\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     * @return {Number} height of line\n     */\n    _getHeightOfLine: function() {\n      return this._getHeightOfSingleLine() * this.lineHeight;\n    },\n\n    /**\n     * @private\n     * @return {Number} height of line without lineHeight\n     */\n    _getHeightOfSingleLine: function() {\n      return this.fontSize * this._fontSizeMult;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextLinesBackground: function(ctx) {\n      if (!this.textBackgroundColor) {\n        return;\n      }\n      var lineTopOffset = 0, heightOfLine,\n          lineWidth, lineLeftOffset, originalFill = ctx.fillStyle;\n\n      ctx.fillStyle = this.textBackgroundColor;\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        heightOfLine = this._getHeightOfLine(ctx, i);\n        lineWidth = this._getLineWidth(ctx, i);\n        if (lineWidth > 0) {\n          lineLeftOffset = this._getLineLeftOffset(lineWidth);\n          ctx.fillRect(\n            this._getLeftOffset() + lineLeftOffset,\n            this._getTopOffset() + lineTopOffset,\n            lineWidth,\n            heightOfLine / this.lineHeight\n          );\n        }\n        lineTopOffset += heightOfLine;\n      }\n      ctx.fillStyle = originalFill;\n      // if there is text background color no\n      // other shadows should be casted\n      this._removeShadow(ctx);\n    },\n\n    /**\n     * @private\n     * @param {Number} lineWidth Width of text line\n     * @return {Number} Line left offset\n     */\n    _getLineLeftOffset: function(lineWidth) {\n      if (this.textAlign === 'center') {\n        return (this.width - lineWidth) / 2;\n      }\n      if (this.textAlign === 'right') {\n        return this.width - lineWidth;\n      }\n      return 0;\n    },\n\n    /**\n     * @private\n     */\n    _clearCache: function() {\n      this.__lineWidths = [];\n      this.__lineHeights = [];\n    },\n\n    /**\n     * @private\n     */\n    _shouldClearDimensionCache: function() {\n      var shouldClear = this._forceClearCache;\n      shouldClear || (shouldClear = this.hasStateChanged('_dimensionAffectingProps'));\n      if (shouldClear) {\n        this.saveState({ propertySet: '_dimensionAffectingProps' });\n        this.dirty = true;\n      }\n      return shouldClear;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Number} lineIndex line number\n     * @return {Number} Line width\n     */\n    _getLineWidth: function(ctx, lineIndex) {\n      if (this.__lineWidths[lineIndex]) {\n        return this.__lineWidths[lineIndex] === -1 ? this.width : this.__lineWidths[lineIndex];\n      }\n\n      var width, wordCount, line = this._textLines[lineIndex];\n\n      if (line === '') {\n        width = 0;\n      }\n      else {\n        width = this._measureLine(ctx, lineIndex);\n      }\n      this.__lineWidths[lineIndex] = width;\n\n      if (width && this.textAlign === 'justify') {\n        wordCount = line.split(/\\s+/);\n        if (wordCount.length > 1) {\n          this.__lineWidths[lineIndex] = -1;\n        }\n      }\n      return width;\n    },\n\n    _getWidthOfCharSpacing: function() {\n      if (this.charSpacing !== 0) {\n        return this.fontSize * this.charSpacing / 1000;\n      }\n      return 0;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Number} lineIndex line number\n     * @return {Number} Line width\n     */\n    _measureLine: function(ctx, lineIndex) {\n      var line = this._textLines[lineIndex],\n          width = ctx.measureText(line).width,\n          additionalSpace = 0, charCount, finalWidth;\n      if (this.charSpacing !== 0) {\n        charCount = line.split('').length;\n        additionalSpace = (charCount - 1) * this._getWidthOfCharSpacing();\n      }\n      finalWidth = width + additionalSpace;\n      return finalWidth > 0 ? finalWidth : 0;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextDecoration: function(ctx) {\n      if (!this.textDecoration) {\n        return;\n      }\n      var halfOfVerticalBox = this.height / 2,\n          _this = this, offsets = [];\n\n      /** @ignore */\n      function renderLinesAtOffset(offsets) {\n        var i, lineHeight = 0, len, j, oLen, lineWidth,\n            lineLeftOffset, heightOfLine;\n\n        for (i = 0, len = _this._textLines.length; i < len; i++) {\n\n          lineWidth = _this._getLineWidth(ctx, i);\n          lineLeftOffset = _this._getLineLeftOffset(lineWidth);\n          heightOfLine = _this._getHeightOfLine(ctx, i);\n\n          for (j = 0, oLen = offsets.length; j < oLen; j++) {\n            ctx.fillRect(\n              _this._getLeftOffset() + lineLeftOffset,\n              lineHeight + (_this._fontSizeMult - 1 + offsets[j] ) * _this.fontSize - halfOfVerticalBox,\n              lineWidth,\n              _this.fontSize / 15);\n          }\n          lineHeight += heightOfLine;\n        }\n      }\n\n      if (this.textDecoration.indexOf('underline') > -1) {\n        offsets.push(0.85); // 1 - 3/16\n      }\n      if (this.textDecoration.indexOf('line-through') > -1) {\n        offsets.push(0.43);\n      }\n      if (this.textDecoration.indexOf('overline') > -1) {\n        offsets.push(-0.12);\n      }\n      if (offsets.length > 0) {\n        renderLinesAtOffset(offsets);\n      }\n    },\n\n    /**\n     * return font declaration string for canvas context\n     * @returns {String} font declaration formatted for canvas context.\n     */\n    _getFontDeclaration: function() {\n      return [\n        // node-canvas needs \"weight style\", while browsers need \"style weight\"\n        (fabric.isLikelyNode ? this.fontWeight : this.fontStyle),\n        (fabric.isLikelyNode ? this.fontStyle : this.fontWeight),\n        this.fontSize + 'px',\n        (fabric.isLikelyNode ? ('\"' + this.fontFamily + '\"') : this.fontFamily)\n      ].join(' ');\n    },\n\n    /**\n     * Renders text instance on a specified context\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} noTransform\n     */\n    render: function(ctx, noTransform) {\n      // do not render if object is not visible\n      if (!this.visible) {\n        return;\n      }\n      if (this.canvas && this.canvas.skipOffscreen && !this.group && !this.isOnScreen()) {\n        return;\n      }\n      if (this._shouldClearDimensionCache()) {\n        this._setTextStyles(ctx);\n        this._initDimensions(ctx);\n      }\n      this.callSuper('render', ctx, noTransform);\n    },\n\n    /**\n     * Returns the text as an array of lines.\n     * @returns {Array} Lines in the text\n     */\n    _splitTextIntoLines: function() {\n      return this.text.split(this._reNewline);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var additionalProperties = [\n        'text',\n        'fontSize',\n        'fontWeight',\n        'fontFamily',\n        'fontStyle',\n        'lineHeight',\n        'textDecoration',\n        'textAlign',\n        'textBackgroundColor',\n        'charSpacing'\n      ].concat(propertiesToInclude);\n      return this.callSuper('toObject', additionalProperties);\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      if (!this.ctx) {\n        this.ctx = fabric.util.createCanvasElement().getContext('2d');\n      }\n      var markup = this._createBaseSVGMarkup(),\n          offsets = this._getSVGLeftTopOffsets(this.ctx),\n          textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);\n      this._wrapSVGTextAndBg(markup, textAndBg);\n\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n\n    /**\n     * @private\n     */\n    _getSVGLeftTopOffsets: function(ctx) {\n      var lineTop = this._getHeightOfLine(ctx, 0),\n          textLeft = -this.width / 2,\n          textTop = 0;\n\n      return {\n        textLeft: textLeft + (this.group && this.group.type === 'path-group' ? this.left : 0),\n        textTop: textTop + (this.group && this.group.type === 'path-group' ? -this.top : 0),\n        lineTop: lineTop\n      };\n    },\n\n    /**\n     * @private\n     */\n    _wrapSVGTextAndBg: function(markup, textAndBg) {\n      var noShadow = true, filter = this.getSvgFilter(),\n          style = filter === '' ? '' : ' style=\"' + filter + '\"';\n\n      markup.push(\n        '\\t<g ', this.getSvgId(), 'transform=\"', this.getSvgTransform(), this.getSvgTransformMatrix(), '\"',\n          style, '>\\n',\n          textAndBg.textBgRects.join(''),\n          '\\t\\t<text xml:space=\"preserve\" ',\n            (this.fontFamily ? 'font-family=\"' + this.fontFamily.replace(/\"/g, '\\'') + '\" ' : ''),\n            (this.fontSize ? 'font-size=\"' + this.fontSize + '\" ' : ''),\n            (this.fontStyle ? 'font-style=\"' + this.fontStyle + '\" ' : ''),\n            (this.fontWeight ? 'font-weight=\"' + this.fontWeight + '\" ' : ''),\n            (this.textDecoration ? 'text-decoration=\"' + this.textDecoration + '\" ' : ''),\n            'style=\"', this.getSvgStyles(noShadow), '\" >\\n',\n            textAndBg.textSpans.join(''),\n          '\\t\\t</text>\\n',\n        '\\t</g>\\n'\n      );\n    },\n\n    getSvgStyles: function(skipShadow) {\n      var svgStyle = fabric.Object.prototype.getSvgStyles.call(this, skipShadow);\n      return svgStyle + ' white-space: pre;';\n    },\n\n    /**\n     * @private\n     * @param {Number} textTopOffset Text top offset\n     * @param {Number} textLeftOffset Text left offset\n     * @return {Object}\n     */\n    _getSVGTextAndBg: function(textTopOffset, textLeftOffset) {\n      var textSpans = [],\n          textBgRects = [],\n          height = 0;\n      // bounding-box background\n      this._setSVGBg(textBgRects);\n\n      // text and text-background\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        if (this.textBackgroundColor) {\n          this._setSVGTextLineBg(textBgRects, i, textLeftOffset, textTopOffset, height);\n        }\n        this._setSVGTextLineText(i, textSpans, height, textLeftOffset, textTopOffset, textBgRects);\n        height += this._getHeightOfLine(this.ctx, i);\n      }\n\n      return {\n        textSpans: textSpans,\n        textBgRects: textBgRects\n      };\n    },\n\n    _setSVGTextLineText: function(i, textSpans, height, textLeftOffset, textTopOffset) {\n      var yPos = this.fontSize * (this._fontSizeMult - this._fontSizeFraction)\n        - textTopOffset + height - this.height / 2;\n      if (this.textAlign === 'justify') {\n        // i call from here to do not intefere with IText\n        this._setSVGTextLineJustifed(i, textSpans, yPos, textLeftOffset);\n        return;\n      }\n      textSpans.push(\n        '\\t\\t\\t<tspan x=\"',\n          toFixed(textLeftOffset + this._getLineLeftOffset(this._getLineWidth(this.ctx, i)), NUM_FRACTION_DIGITS), '\" ',\n          'y=\"',\n          toFixed(yPos, NUM_FRACTION_DIGITS),\n          '\" ',\n          // doing this on <tspan> elements since setting opacity\n          // on containing <text> one doesn't work in Illustrator\n          this._getFillAttributes(this.fill), '>',\n          fabric.util.string.escapeXml(this._textLines[i]),\n        '</tspan>\\n'\n      );\n    },\n\n    _setSVGTextLineJustifed: function(i, textSpans, yPos, textLeftOffset) {\n      var ctx = fabric.util.createCanvasElement().getContext('2d');\n\n      this._setTextStyles(ctx);\n\n      var line = this._textLines[i],\n          words = line.split(/\\s+/),\n          wordsWidth = this._getWidthOfWords(ctx, words.join('')),\n          widthDiff = this.width - wordsWidth,\n          numSpaces = words.length - 1,\n          spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0,\n          word, attributes = this._getFillAttributes(this.fill),\n          len;\n\n      textLeftOffset += this._getLineLeftOffset(this._getLineWidth(ctx, i));\n\n      for (i = 0, len = words.length; i < len; i++) {\n        word = words[i];\n        textSpans.push(\n          '\\t\\t\\t<tspan x=\"',\n            toFixed(textLeftOffset, NUM_FRACTION_DIGITS), '\" ',\n            'y=\"',\n            toFixed(yPos, NUM_FRACTION_DIGITS),\n            '\" ',\n            // doing this on <tspan> elements since setting opacity\n            // on containing <text> one doesn't work in Illustrator\n            attributes, '>',\n            fabric.util.string.escapeXml(word),\n          '</tspan>\\n'\n        );\n        textLeftOffset += this._getWidthOfWords(ctx, word) + spaceWidth;\n      }\n    },\n\n    _setSVGTextLineBg: function(textBgRects, i, textLeftOffset, textTopOffset, height) {\n      textBgRects.push(\n        '\\t\\t<rect ',\n          this._getFillAttributes(this.textBackgroundColor),\n          ' x=\"',\n          toFixed(textLeftOffset + this._getLineLeftOffset(this._getLineWidth(this.ctx, i)), NUM_FRACTION_DIGITS),\n          '\" y=\"',\n          toFixed(height - this.height / 2, NUM_FRACTION_DIGITS),\n          '\" width=\"',\n          toFixed(this._getLineWidth(this.ctx, i), NUM_FRACTION_DIGITS),\n          '\" height=\"',\n          toFixed(this._getHeightOfLine(this.ctx, i) / this.lineHeight, NUM_FRACTION_DIGITS),\n        '\"></rect>\\n');\n    },\n\n    _setSVGBg: function(textBgRects) {\n      if (this.backgroundColor) {\n        textBgRects.push(\n          '\\t\\t<rect ',\n            this._getFillAttributes(this.backgroundColor),\n            ' x=\"',\n            toFixed(-this.width / 2, NUM_FRACTION_DIGITS),\n            '\" y=\"',\n            toFixed(-this.height / 2, NUM_FRACTION_DIGITS),\n            '\" width=\"',\n            toFixed(this.width, NUM_FRACTION_DIGITS),\n            '\" height=\"',\n            toFixed(this.height, NUM_FRACTION_DIGITS),\n          '\"></rect>\\n');\n      }\n    },\n\n    /**\n     * Adobe Illustrator (at least CS5) is unable to render rgba()-based fill values\n     * we work around it by \"moving\" alpha channel into opacity attribute and setting fill's alpha to 1\n     *\n     * @private\n     * @param {*} value\n     * @return {String}\n     */\n    _getFillAttributes: function(value) {\n      var fillColor = (value && typeof value === 'string') ? new fabric.Color(value) : '';\n      if (!fillColor || !fillColor.getSource() || fillColor.getAlpha() === 1) {\n        return 'fill=\"' + value + '\"';\n      }\n      return 'opacity=\"' + fillColor.getAlpha() + '\" fill=\"' + fillColor.setAlpha(1).toRgb() + '\"';\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Sets specified property to a specified value\n     * @param {String} key\n     * @param {*} value\n     * @return {fabric.Text} thisArg\n     * @chainable\n     */\n    _set: function(key, value) {\n      this.callSuper('_set', key, value);\n\n      if (this._dimensionAffectingProps.indexOf(key) > -1) {\n        this._initDimensions();\n        this.setCoords();\n      }\n    },\n\n    /**\n     * Returns complexity of an instance\n     * @return {Number} complexity\n     */\n    complexity: function() {\n      return 1;\n    }\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Text.fromElement})\n   * @static\n   * @memberOf fabric.Text\n   * @see: http://www.w3.org/TR/SVG/text.html#TextElement\n   */\n  fabric.Text.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(\n    'x y dx dy font-family font-style font-weight font-size text-decoration text-anchor'.split(' '));\n\n  /**\n   * Default SVG font size\n   * @static\n   * @memberOf fabric.Text\n   */\n  fabric.Text.DEFAULT_SVG_FONT_SIZE = 16;\n\n  /**\n   * Returns fabric.Text instance from an SVG element (<b>not yet implemented</b>)\n   * @static\n   * @memberOf fabric.Text\n   * @param {SVGElement} element Element to parse\n   * @param {Object} [options] Options object\n   * @return {fabric.Text} Instance of fabric.Text\n   */\n  fabric.Text.fromElement = function(element, options) {\n    if (!element) {\n      return null;\n    }\n\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Text.ATTRIBUTE_NAMES);\n    options = fabric.util.object.extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes);\n\n    options.top = options.top || 0;\n    options.left = options.left || 0;\n    if ('dx' in parsedAttributes) {\n      options.left += parsedAttributes.dx;\n    }\n    if ('dy' in parsedAttributes) {\n      options.top += parsedAttributes.dy;\n    }\n    if (!('fontSize' in options)) {\n      options.fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;\n    }\n\n    if (!options.originX) {\n      options.originX = 'left';\n    }\n\n    var textContent = '';\n\n    // The XML is not properly parsed in IE9 so a workaround to get\n    // textContent is through firstChild.data. Another workaround would be\n    // to convert XML loaded from a file to be converted using DOMParser (same way loadSVGFromString() does)\n    if (!('textContent' in element)) {\n      if ('firstChild' in element && element.firstChild !== null) {\n        if ('data' in element.firstChild && element.firstChild.data !== null) {\n          textContent = element.firstChild.data;\n        }\n      }\n    }\n    else {\n      textContent = element.textContent;\n    }\n\n    textContent = textContent.replace(/^\\s+|\\s+$|\\n+/g, '').replace(/\\s+/g, ' ');\n\n    var text = new fabric.Text(textContent, options),\n        textHeightScaleFactor = text.getHeight() / text.height,\n        lineHeightDiff = (text.height + text.strokeWidth) * text.lineHeight - text.height,\n        scaledDiff = lineHeightDiff * textHeightScaleFactor,\n        textHeight = text.getHeight() + scaledDiff,\n        offX = 0;\n    /*\n      Adjust positioning:\n        x/y attributes in SVG correspond to the bottom-left corner of text bounding box\n        top/left properties in Fabric correspond to center point of text bounding box\n    */\n    if (text.originX === 'left') {\n      offX = text.getWidth() / 2;\n    }\n    if (text.originX === 'right') {\n      offX = -text.getWidth() / 2;\n    }\n    text.set({\n      left: text.getLeft() + offX,\n      top: text.getTop() - textHeight / 2 + text.fontSize * (0.18 + text._fontSizeFraction) / text.lineHeight /* 0.3 is the old lineHeight */\n    });\n\n    return text;\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns fabric.Text instance from an object representation\n   * @static\n   * @memberOf fabric.Text\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Text instance is created\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {fabric.Text} Instance of fabric.Text\n   */\n  fabric.Text.fromObject = function(object, callback, forceAsync) {\n    return fabric.Object._fromObject('Text', object, callback, forceAsync, 'text');\n  };\n\n  fabric.util.createAccessors(fabric.Text);\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n  var clone = fabric.util.object.clone;\n\n  /**\n   * IText class (introduced in <b>v1.4</b>) Events are also fired with \"text:\"\n   * prefix when observing canvas.\n   * @class fabric.IText\n   * @extends fabric.Text\n   * @mixes fabric.Observable\n   *\n   * @fires changed\n   * @fires selection:changed\n   * @fires editing:entered\n   * @fires editing:exited\n   *\n   * @return {fabric.IText} thisArg\n   * @see {@link fabric.IText#initialize} for constructor definition\n   *\n   * <p>Supported key combinations:</p>\n   * <pre>\n   *   Move cursor:                    left, right, up, down\n   *   Select character:               shift + left, shift + right\n   *   Select text vertically:         shift + up, shift + down\n   *   Move cursor by word:            alt + left, alt + right\n   *   Select words:                   shift + alt + left, shift + alt + right\n   *   Move cursor to line start/end:  cmd + left, cmd + right or home, end\n   *   Select till start/end of line:  cmd + shift + left, cmd + shift + right or shift + home, shift + end\n   *   Jump to start/end of text:      cmd + up, cmd + down\n   *   Select till start/end of text:  cmd + shift + up, cmd + shift + down or shift + pgUp, shift + pgDown\n   *   Delete character:               backspace\n   *   Delete word:                    alt + backspace\n   *   Delete line:                    cmd + backspace\n   *   Forward delete:                 delete\n   *   Copy text:                      ctrl/cmd + c\n   *   Paste text:                     ctrl/cmd + v\n   *   Cut text:                       ctrl/cmd + x\n   *   Select entire text:             ctrl/cmd + a\n   *   Quit editing                    tab or esc\n   * </pre>\n   *\n   * <p>Supported mouse/touch combination</p>\n   * <pre>\n   *   Position cursor:                click/touch\n   *   Create selection:               click/touch & drag\n   *   Create selection:               click & shift + click\n   *   Select word:                    double click\n   *   Select line:                    triple click\n   * </pre>\n   */\n  fabric.IText = fabric.util.createClass(fabric.Text, fabric.Observable, /** @lends fabric.IText.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'i-text',\n\n    /**\n     * Index where text selection starts (or where cursor is when there is no selection)\n     * @type Number\n     * @default\n     */\n    selectionStart: 0,\n\n    /**\n     * Index where text selection ends\n     * @type Number\n     * @default\n     */\n    selectionEnd: 0,\n\n    /**\n     * Color of text selection\n     * @type String\n     * @default\n     */\n    selectionColor: 'rgba(17,119,255,0.3)',\n\n    /**\n     * Indicates whether text is in editing mode\n     * @type Boolean\n     * @default\n     */\n    isEditing: false,\n\n    /**\n     * Indicates whether a text can be edited\n     * @type Boolean\n     * @default\n     */\n    editable: true,\n\n    /**\n     * Border color of text object while it's in editing mode\n     * @type String\n     * @default\n     */\n    editingBorderColor: 'rgba(102,153,255,0.25)',\n\n    /**\n     * Width of cursor (in px)\n     * @type Number\n     * @default\n     */\n    cursorWidth: 2,\n\n    /**\n     * Color of default cursor (when not overwritten by character style)\n     * @type String\n     * @default\n     */\n    cursorColor: '#333',\n\n    /**\n     * Delay between cursor blink (in ms)\n     * @type Number\n     * @default\n     */\n    cursorDelay: 1000,\n\n    /**\n     * Duration of cursor fadein (in ms)\n     * @type Number\n     * @default\n     */\n    cursorDuration: 600,\n\n    /**\n     * Object containing character styles\n     * (where top-level properties corresponds to line number and 2nd-level properties -- to char number in a line)\n     * @type Object\n     * @default\n     */\n    styles: null,\n\n    /**\n     * Indicates whether internal text char widths can be cached\n     * @type Boolean\n     * @default\n     */\n    caching: true,\n\n    /**\n     * @private\n     */\n    _reSpace: /\\s|\\n/,\n\n    /**\n     * @private\n     */\n    _currentCursorOpacity: 0,\n\n    /**\n     * @private\n     */\n    _selectionDirection: null,\n\n    /**\n     * @private\n     */\n    _abortCursorAnimation: false,\n\n    /**\n     * @private\n     */\n    __widthOfSpace: [],\n\n    /**\n     * Constructor\n     * @param {String} text Text string\n     * @param {Object} [options] Options object\n     * @return {fabric.IText} thisArg\n     */\n    initialize: function(text, options) {\n      this.styles = options ? (options.styles || { }) : { };\n      this.callSuper('initialize', text, options);\n      this.initBehavior();\n    },\n\n    /**\n     * @private\n     */\n    _clearCache: function() {\n      this.callSuper('_clearCache');\n      this.__widthOfSpace = [];\n    },\n\n    /**\n     * Returns true if object has no styling\n     */\n    isEmptyStyles: function() {\n      if (!this.styles) {\n        return true;\n      }\n      var obj = this.styles;\n\n      for (var p1 in obj) {\n        for (var p2 in obj[p1]) {\n          // eslint-disable-next-line no-unused-vars\n          for (var p3 in obj[p1][p2]) {\n            return false;\n          }\n        }\n      }\n      return true;\n    },\n\n    /**\n     * Sets selection start (left boundary of a selection)\n     * @param {Number} index Index to set selection start to\n     */\n    setSelectionStart: function(index) {\n      index = Math.max(index, 0);\n      this._updateAndFire('selectionStart', index);\n    },\n\n    /**\n     * Sets selection end (right boundary of a selection)\n     * @param {Number} index Index to set selection end to\n     */\n    setSelectionEnd: function(index) {\n      index = Math.min(index, this.text.length);\n      this._updateAndFire('selectionEnd', index);\n    },\n\n    /**\n     * @private\n     * @param {String} property 'selectionStart' or 'selectionEnd'\n     * @param {Number} index new position of property\n     */\n    _updateAndFire: function(property, index) {\n      if (this[property] !== index) {\n        this._fireSelectionChanged();\n        this[property] = index;\n      }\n      this._updateTextarea();\n    },\n\n    /**\n     * Fires the even of selection changed\n     * @private\n     */\n    _fireSelectionChanged: function() {\n      this.fire('selection:changed');\n      this.canvas && this.canvas.fire('text:selection:changed', { target: this });\n    },\n\n    /**\n     * Gets style of a current selection/cursor (at the start position)\n     * @param {Number} [startIndex] Start index to get styles at\n     * @param {Number} [endIndex] End index to get styles at\n     * @return {Object} styles Style object at a specified (or current) index\n     */\n    getSelectionStyles: function(startIndex, endIndex) {\n\n      if (arguments.length === 2) {\n        var styles = [];\n        for (var i = startIndex; i < endIndex; i++) {\n          styles.push(this.getSelectionStyles(i));\n        }\n        return styles;\n      }\n\n      var loc = this.get2DCursorLocation(startIndex),\n          style = this._getStyleDeclaration(loc.lineIndex, loc.charIndex);\n\n      return style || {};\n    },\n\n    /**\n     * Sets style of a current selection\n     * @param {Object} [styles] Styles object\n     * @return {fabric.IText} thisArg\n     * @chainable\n     */\n    setSelectionStyles: function(styles) {\n      if (this.selectionStart === this.selectionEnd) {\n        this._extendStyles(this.selectionStart, styles);\n      }\n      else {\n        for (var i = this.selectionStart; i < this.selectionEnd; i++) {\n          this._extendStyles(i, styles);\n        }\n      }\n      /* not included in _extendStyles to avoid clearing cache more than once */\n      this._forceClearCache = true;\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _extendStyles: function(index, styles) {\n      var loc = this.get2DCursorLocation(index);\n\n      if (!this._getLineStyle(loc.lineIndex)) {\n        this._setLineStyle(loc.lineIndex, {});\n      }\n\n      if (!this._getStyleDeclaration(loc.lineIndex, loc.charIndex)) {\n        this._setStyleDeclaration(loc.lineIndex, loc.charIndex, {});\n      }\n\n      fabric.util.object.extend(this._getStyleDeclaration(loc.lineIndex, loc.charIndex), styles);\n    },\n\n    /**\n     * Initialize text dimensions. Render all text on given context\n     * or on a offscreen canvas to get the text width with measureText.\n     * Updates this.width and this.height with the proper values.\n     * Does not return dimensions.\n     * @param {CanvasRenderingContext2D} [ctx] Context to render on\n     * @private\n     */\n    _initDimensions: function(ctx) {\n      if (!ctx) {\n        this.clearContextTop();\n      }\n      this.callSuper('_initDimensions', ctx);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Boolean} noTransform\n     */\n    render: function(ctx, noTransform) {\n      this.clearContextTop();\n      this.callSuper('render', ctx, noTransform);\n      // clear the cursorOffsetCache, so we ensure to calculate once per renderCursor\n      // the correct position but not at every cursor animation.\n      this.cursorOffsetCache = { };\n      this.renderCursorOrSelection();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      this.callSuper('_render', ctx);\n      this.ctx = ctx;\n    },\n\n    /**\n     * Prepare and clean the contextTop\n     */\n    clearContextTop: function() {\n      if (!this.active || !this.isEditing) {\n        return;\n      }\n      if (this.canvas && this.canvas.contextTop) {\n        var ctx = this.canvas.contextTop;\n        ctx.save();\n        ctx.transform.apply(ctx, this.canvas.viewportTransform);\n        this.transform(ctx);\n        this.transformMatrix && ctx.transform.apply(ctx, this.transformMatrix);\n        this._clearTextArea(ctx);\n        ctx.restore();\n      }\n    },\n\n    /**\n     * Renders cursor or selection (depending on what exists)\n     */\n    renderCursorOrSelection: function() {\n      if (!this.active || !this.isEditing) {\n        return;\n      }\n      var chars = this.text.split(''),\n          boundaries, ctx;\n      if (this.canvas && this.canvas.contextTop) {\n        ctx = this.canvas.contextTop;\n        ctx.save();\n        ctx.transform.apply(ctx, this.canvas.viewportTransform);\n        this.transform(ctx);\n        this.transformMatrix && ctx.transform.apply(ctx, this.transformMatrix);\n        this._clearTextArea(ctx);\n      }\n      else {\n        ctx = this.ctx;\n        ctx.save();\n      }\n      if (this.selectionStart === this.selectionEnd) {\n        boundaries = this._getCursorBoundaries(chars, 'cursor');\n        this.renderCursor(boundaries, ctx);\n      }\n      else {\n        boundaries = this._getCursorBoundaries(chars, 'selection');\n        this.renderSelection(chars, boundaries, ctx);\n      }\n      ctx.restore();\n    },\n\n    _clearTextArea: function(ctx) {\n      // we add 4 pixel, to be sure to do not leave any pixel out\n      var width = this.width + 4, height = this.height + 4;\n      ctx.clearRect(-width / 2, -height / 2, width, height);\n    },\n    /**\n     * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start)\n     * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.\n     */\n    get2DCursorLocation: function(selectionStart) {\n      if (typeof selectionStart === 'undefined') {\n        selectionStart = this.selectionStart;\n      }\n      var len = this._textLines.length;\n      for (var i = 0; i < len; i++) {\n        if (selectionStart <= this._textLines[i].length) {\n          return {\n            lineIndex: i,\n            charIndex: selectionStart\n          };\n        }\n        selectionStart -= this._textLines[i].length + 1;\n      }\n      return {\n        lineIndex: i - 1,\n        charIndex: this._textLines[i - 1].length < selectionStart ? this._textLines[i - 1].length : selectionStart\n      };\n    },\n\n    /**\n     * Returns complete style of char at the current cursor\n     * @param {Number} lineIndex Line index\n     * @param {Number} charIndex Char index\n     * @return {Object} Character style\n     */\n    getCurrentCharStyle: function(lineIndex, charIndex) {\n      var style = this._getStyleDeclaration(lineIndex, charIndex === 0 ? 0 : charIndex - 1);\n\n      return {\n        fontSize: style && style.fontSize || this.fontSize,\n        fill: style && style.fill || this.fill,\n        textBackgroundColor: style && style.textBackgroundColor || this.textBackgroundColor,\n        textDecoration: style && style.textDecoration || this.textDecoration,\n        fontFamily: style && style.fontFamily || this.fontFamily,\n        fontWeight: style && style.fontWeight || this.fontWeight,\n        fontStyle: style && style.fontStyle || this.fontStyle,\n        stroke: style && style.stroke || this.stroke,\n        strokeWidth: style && style.strokeWidth || this.strokeWidth\n      };\n    },\n\n    /**\n     * Returns fontSize of char at the current cursor\n     * @param {Number} lineIndex Line index\n     * @param {Number} charIndex Char index\n     * @return {Number} Character font size\n     */\n    getCurrentCharFontSize: function(lineIndex, charIndex) {\n      var style = this._getStyleDeclaration(lineIndex, charIndex === 0 ? 0 : charIndex - 1);\n      return style && style.fontSize ? style.fontSize : this.fontSize;\n    },\n\n    /**\n     * Returns color (fill) of char at the current cursor\n     * @param {Number} lineIndex Line index\n     * @param {Number} charIndex Char index\n     * @return {String} Character color (fill)\n     */\n    getCurrentCharColor: function(lineIndex, charIndex) {\n      var style = this._getStyleDeclaration(lineIndex, charIndex === 0 ? 0 : charIndex - 1);\n      return style && style.fill ? style.fill : this.cursorColor;\n    },\n\n    /**\n     * Returns cursor boundaries (left, top, leftOffset, topOffset)\n     * @private\n     * @param {Array} chars Array of characters\n     * @param {String} typeOfBoundaries\n     */\n    _getCursorBoundaries: function(chars, typeOfBoundaries) {\n\n      // left/top are left/top of entire text box\n      // leftOffset/topOffset are offset from that left/top point of a text box\n\n      var left = Math.round(this._getLeftOffset()),\n          top = this._getTopOffset(),\n\n          offsets = this._getCursorBoundariesOffsets(\n                      chars, typeOfBoundaries);\n\n      return {\n        left: left,\n        top: top,\n        leftOffset: offsets.left + offsets.lineLeft,\n        topOffset: offsets.top\n      };\n    },\n\n    /**\n     * @private\n     */\n    _getCursorBoundariesOffsets: function(chars, typeOfBoundaries) {\n      if (this.cursorOffsetCache && 'top' in this.cursorOffsetCache) {\n        return this.cursorOffsetCache;\n      }\n      var lineLeftOffset = 0,\n          lineIndex = 0,\n          charIndex = 0,\n          topOffset = 0,\n          leftOffset = 0,\n          boundaries;\n\n      for (var i = 0; i < this.selectionStart; i++) {\n        if (chars[i] === '\\n') {\n          leftOffset = 0;\n          topOffset += this._getHeightOfLine(this.ctx, lineIndex);\n\n          lineIndex++;\n          charIndex = 0;\n        }\n        else {\n          leftOffset += this._getWidthOfChar(this.ctx, chars[i], lineIndex, charIndex);\n          charIndex++;\n        }\n\n        lineLeftOffset = this._getLineLeftOffset(this._getLineWidth(this.ctx, lineIndex));\n      }\n      if (typeOfBoundaries === 'cursor') {\n        topOffset += (1 - this._fontSizeFraction) * this._getHeightOfLine(this.ctx, lineIndex) / this.lineHeight\n          - this.getCurrentCharFontSize(lineIndex, charIndex) * (1 - this._fontSizeFraction);\n      }\n      if (this.charSpacing !== 0 && charIndex === this._textLines[lineIndex].length) {\n        leftOffset -= this._getWidthOfCharSpacing();\n      }\n      boundaries = {\n        top: topOffset,\n        left: leftOffset > 0 ? leftOffset : 0,\n        lineLeft: lineLeftOffset\n      };\n      this.cursorOffsetCache = boundaries;\n      return this.cursorOffsetCache;\n    },\n\n    /**\n     * Renders cursor\n     * @param {Object} boundaries\n     * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n     */\n    renderCursor: function(boundaries, ctx) {\n\n      var cursorLocation = this.get2DCursorLocation(),\n          lineIndex = cursorLocation.lineIndex,\n          charIndex = cursorLocation.charIndex,\n          charHeight = this.getCurrentCharFontSize(lineIndex, charIndex),\n          leftOffset = boundaries.leftOffset,\n          multiplier = this.scaleX * this.canvas.getZoom(),\n          cursorWidth = this.cursorWidth / multiplier;\n\n      ctx.fillStyle = this.getCurrentCharColor(lineIndex, charIndex);\n      ctx.globalAlpha = this.__isMousedown ? 1 : this._currentCursorOpacity;\n\n      ctx.fillRect(\n        boundaries.left + leftOffset - cursorWidth / 2,\n        boundaries.top + boundaries.topOffset,\n        cursorWidth,\n        charHeight);\n    },\n\n    /**\n     * Renders text selection\n     * @param {Array} chars Array of characters\n     * @param {Object} boundaries Object with left/top/leftOffset/topOffset\n     * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n     */\n    renderSelection: function(chars, boundaries, ctx) {\n\n      ctx.fillStyle = this.selectionColor;\n\n      var start = this.get2DCursorLocation(this.selectionStart),\n          end = this.get2DCursorLocation(this.selectionEnd),\n          startLine = start.lineIndex,\n          endLine = end.lineIndex;\n      for (var i = startLine; i <= endLine; i++) {\n        var lineOffset = this._getLineLeftOffset(this._getLineWidth(ctx, i)) || 0,\n            lineHeight = this._getHeightOfLine(this.ctx, i),\n            realLineHeight = 0, boxWidth = 0, line = this._textLines[i];\n\n        if (i === startLine) {\n          for (var j = 0, len = line.length; j < len; j++) {\n            if (j >= start.charIndex && (i !== endLine || j < end.charIndex)) {\n              boxWidth += this._getWidthOfChar(ctx, line[j], i, j);\n            }\n            if (j < start.charIndex) {\n              lineOffset += this._getWidthOfChar(ctx, line[j], i, j);\n            }\n          }\n          if (j === line.length) {\n            boxWidth -= this._getWidthOfCharSpacing();\n          }\n        }\n        else if (i > startLine && i < endLine) {\n          boxWidth += this._getLineWidth(ctx, i) || 5;\n        }\n        else if (i === endLine) {\n          for (var j2 = 0, j2len = end.charIndex; j2 < j2len; j2++) {\n            boxWidth += this._getWidthOfChar(ctx, line[j2], i, j2);\n          }\n          if (end.charIndex === line.length) {\n            boxWidth -= this._getWidthOfCharSpacing();\n          }\n        }\n        realLineHeight = lineHeight;\n        if (this.lineHeight < 1 || (i === endLine && this.lineHeight > 1)) {\n          lineHeight /= this.lineHeight;\n        }\n        ctx.fillRect(\n          boundaries.left + lineOffset,\n          boundaries.top + boundaries.topOffset,\n          boxWidth > 0 ? boxWidth : 0,\n          lineHeight);\n\n        boundaries.topOffset += realLineHeight;\n      }\n    },\n\n    /**\n     * @private\n     * @param {String} method\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} line Content of the line\n     * @param {Number} left\n     * @param {Number} top\n     * @param {Number} lineIndex\n     * @param {Number} charOffset\n     */\n    _renderChars: function(method, ctx, line, left, top, lineIndex, charOffset) {\n\n      if (this.isEmptyStyles()) {\n        return this._renderCharsFast(method, ctx, line, left, top);\n      }\n\n      charOffset = charOffset || 0;\n\n      // set proper line offset\n      var lineHeight = this._getHeightOfLine(ctx, lineIndex),\n          prevStyle,\n          thisStyle,\n          charsToRender = '';\n\n      ctx.save();\n      top -= lineHeight / this.lineHeight * this._fontSizeFraction;\n      for (var i = charOffset, len = line.length + charOffset; i <= len; i++) {\n        prevStyle = prevStyle || this.getCurrentCharStyle(lineIndex, i);\n        thisStyle = this.getCurrentCharStyle(lineIndex, i + 1);\n\n        if (this._hasStyleChanged(prevStyle, thisStyle) || i === len) {\n          this._renderChar(method, ctx, lineIndex, i - 1, charsToRender, left, top, lineHeight);\n          charsToRender = '';\n          prevStyle = thisStyle;\n        }\n        charsToRender += line[i - charOffset];\n      }\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     * @param {String} method\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} line Content of the line\n     * @param {Number} left Left coordinate\n     * @param {Number} top Top coordinate\n     */\n    _renderCharsFast: function(method, ctx, line, left, top) {\n\n      if (method === 'fillText' && this.fill) {\n        this.callSuper('_renderChars', method, ctx, line, left, top);\n      }\n      if (method === 'strokeText' && ((this.stroke && this.strokeWidth > 0) || this.skipFillStrokeCheck)) {\n        this.callSuper('_renderChars', method, ctx, line, left, top);\n      }\n    },\n\n    /**\n     * @private\n     * @param {String} method\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Number} lineIndex\n     * @param {Number} i\n     * @param {String} _char\n     * @param {Number} left Left coordinate\n     * @param {Number} top Top coordinate\n     * @param {Number} lineHeight Height of the line\n     */\n    _renderChar: function(method, ctx, lineIndex, i, _char, left, top, lineHeight) {\n      var charWidth, charHeight, shouldFill, shouldStroke,\n          decl = this._getStyleDeclaration(lineIndex, i),\n          offset, textDecoration, chars, additionalSpace, _charWidth;\n\n      if (decl) {\n        charHeight = this._getHeightOfChar(ctx, _char, lineIndex, i);\n        shouldStroke = decl.stroke;\n        shouldFill = decl.fill;\n        textDecoration = decl.textDecoration;\n      }\n      else {\n        charHeight = this.fontSize;\n      }\n\n      shouldStroke = (shouldStroke || this.stroke) && method === 'strokeText';\n      shouldFill = (shouldFill || this.fill) && method === 'fillText';\n\n      decl && ctx.save();\n\n      charWidth = this._applyCharStylesGetWidth(ctx, _char, lineIndex, i, decl || null);\n      textDecoration = textDecoration || this.textDecoration;\n\n      if (decl && decl.textBackgroundColor) {\n        this._removeShadow(ctx);\n      }\n      if (this.charSpacing !== 0) {\n        additionalSpace = this._getWidthOfCharSpacing();\n        chars = _char.split('');\n        charWidth = 0;\n        for (var j = 0, len = chars.length, jChar; j < len; j++) {\n          jChar = chars[j];\n          shouldFill && ctx.fillText(jChar, left + charWidth, top);\n          shouldStroke && ctx.strokeText(jChar, left + charWidth, top);\n          _charWidth = ctx.measureText(jChar).width + additionalSpace;\n          charWidth += _charWidth > 0 ? _charWidth : 0;\n        }\n      }\n      else {\n        shouldFill && ctx.fillText(_char, left, top);\n        shouldStroke && ctx.strokeText(_char, left, top);\n      }\n\n      if (textDecoration || textDecoration !== '') {\n        offset = this._fontSizeFraction * lineHeight / this.lineHeight;\n        this._renderCharDecoration(ctx, textDecoration, left, top, offset, charWidth, charHeight);\n      }\n\n      decl && ctx.restore();\n      ctx.translate(charWidth, 0);\n    },\n\n    /**\n     * @private\n     * @param {Object} prevStyle\n     * @param {Object} thisStyle\n     */\n    _hasStyleChanged: function(prevStyle, thisStyle) {\n      return (prevStyle.fill !== thisStyle.fill ||\n              prevStyle.fontSize !== thisStyle.fontSize ||\n              prevStyle.textBackgroundColor !== thisStyle.textBackgroundColor ||\n              prevStyle.textDecoration !== thisStyle.textDecoration ||\n              prevStyle.fontFamily !== thisStyle.fontFamily ||\n              prevStyle.fontWeight !== thisStyle.fontWeight ||\n              prevStyle.fontStyle !== thisStyle.fontStyle ||\n              prevStyle.stroke !== thisStyle.stroke ||\n              prevStyle.strokeWidth !== thisStyle.strokeWidth\n      );\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderCharDecoration: function(ctx, textDecoration, left, top, offset, charWidth, charHeight) {\n\n      if (!textDecoration) {\n        return;\n      }\n\n      var decorationWeight = charHeight / 15,\n          positions = {\n            underline: top + charHeight / 10,\n            'line-through': top - charHeight * (this._fontSizeFraction + this._fontSizeMult - 1) + decorationWeight,\n            overline: top - (this._fontSizeMult - this._fontSizeFraction) * charHeight\n          },\n          decorations = ['underline', 'line-through', 'overline'], i, decoration;\n\n      for (i = 0; i < decorations.length; i++) {\n        decoration = decorations[i];\n        if (textDecoration.indexOf(decoration) > -1) {\n          ctx.fillRect(left, positions[decoration], charWidth , decorationWeight);\n        }\n      }\n    },\n\n    /**\n     * @private\n     * @param {String} method\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} line\n     * @param {Number} left\n     * @param {Number} top\n     * @param {Number} lineIndex\n     */\n    _renderTextLine: function(method, ctx, line, left, top, lineIndex) {\n      // to \"cancel\" this.fontSize subtraction in fabric.Text#_renderTextLine\n      // the adding 0.03 is just to align text with itext by overlap test\n      if (!this.isEmptyStyles()) {\n        top += this.fontSize * (this._fontSizeFraction + 0.03);\n      }\n      this.callSuper('_renderTextLine', method, ctx, line, left, top, lineIndex);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextDecoration: function(ctx) {\n      if (this.isEmptyStyles()) {\n        return this.callSuper('_renderTextDecoration', ctx);\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextLinesBackground: function(ctx) {\n      this.callSuper('_renderTextLinesBackground', ctx);\n\n      var lineTopOffset = 0, heightOfLine,\n          lineWidth, lineLeftOffset,\n          leftOffset = this._getLeftOffset(),\n          topOffset = this._getTopOffset(),\n          colorCache = '',\n          line, _char, style, leftCache,\n          topCache, widthCache, heightCache;\n      ctx.save();\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        heightOfLine = this._getHeightOfLine(ctx, i);\n        line = this._textLines[i];\n\n        if (line === '' || !this.styles || !this._getLineStyle(i)) {\n          lineTopOffset += heightOfLine;\n          continue;\n        }\n\n        lineWidth = this._getLineWidth(ctx, i);\n        lineLeftOffset = this._getLineLeftOffset(lineWidth);\n        leftCache = topCache = widthCache = heightCache = 0;\n        for (var j = 0, jlen = line.length; j < jlen; j++) {\n          style = this._getStyleDeclaration(i, j) || {};\n\n          if (colorCache !== style.textBackgroundColor) {\n            if (heightCache && widthCache) {\n              ctx.fillStyle = colorCache;\n              ctx.fillRect(leftCache, topCache, widthCache, heightCache);\n            }\n            leftCache = topCache = widthCache = heightCache = 0;\n            colorCache = style.textBackgroundColor || '';\n          }\n\n          if (!style.textBackgroundColor) {\n            colorCache = '';\n            continue;\n          }\n          _char = line[j];\n\n          if (colorCache === style.textBackgroundColor) {\n            colorCache = style.textBackgroundColor;\n            if (!leftCache) {\n              leftCache = leftOffset + lineLeftOffset + this._getWidthOfCharsAt(ctx, i, j);\n            }\n            topCache = topOffset + lineTopOffset;\n            widthCache += this._getWidthOfChar(ctx, _char, i, j);\n            heightCache = heightOfLine / this.lineHeight;\n          }\n        }\n        // if a textBackgroundColor ends on the last character of a line\n        if (heightCache && widthCache) {\n          ctx.fillStyle = colorCache;\n          ctx.fillRect(leftCache, topCache, widthCache, heightCache);\n          leftCache = topCache = widthCache = heightCache = 0;\n        }\n        lineTopOffset += heightOfLine;\n      }\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     */\n    _getCacheProp: function(_char, styleDeclaration) {\n      return _char +\n             styleDeclaration.fontSize +\n             styleDeclaration.fontWeight +\n             styleDeclaration.fontStyle;\n    },\n\n    /**\n     * @private\n     * @param {String} fontFamily name\n     * @return {Object} reference to cache\n     */\n    _getFontCache: function(fontFamily) {\n      if (!fabric.charWidthsCache[fontFamily]) {\n        fabric.charWidthsCache[fontFamily] = { };\n      }\n      return fabric.charWidthsCache[fontFamily];\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} _char\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @param {Object} [decl]\n     */\n    _applyCharStylesGetWidth: function(ctx, _char, lineIndex, charIndex, decl) {\n      var charDecl = decl || this._getStyleDeclaration(lineIndex, charIndex),\n          styleDeclaration = clone(charDecl),\n          width, cacheProp, charWidthsCache;\n\n      this._applyFontStyles(styleDeclaration);\n      charWidthsCache = this._getFontCache(styleDeclaration.fontFamily);\n      cacheProp = this._getCacheProp(_char, styleDeclaration);\n\n      // short-circuit if no styles for this char\n      // global style from object is always applyed and handled by save and restore\n      if (!charDecl && charWidthsCache[cacheProp] && this.caching) {\n        return charWidthsCache[cacheProp];\n      }\n\n      if (typeof styleDeclaration.shadow === 'string') {\n        styleDeclaration.shadow = new fabric.Shadow(styleDeclaration.shadow);\n      }\n\n      var fill = styleDeclaration.fill || this.fill;\n      ctx.fillStyle = fill.toLive\n        ? fill.toLive(ctx, this)\n        : fill;\n\n      if (styleDeclaration.stroke) {\n        ctx.strokeStyle = (styleDeclaration.stroke && styleDeclaration.stroke.toLive)\n          ? styleDeclaration.stroke.toLive(ctx, this)\n          : styleDeclaration.stroke;\n      }\n\n      ctx.lineWidth = styleDeclaration.strokeWidth || this.strokeWidth;\n      ctx.font = this._getFontDeclaration.call(styleDeclaration);\n\n      //if we want this._setShadow.call to work with styleDeclarion\n      //we have to add those references\n      if (styleDeclaration.shadow) {\n        styleDeclaration.scaleX = this.scaleX;\n        styleDeclaration.scaleY = this.scaleY;\n        styleDeclaration.canvas = this.canvas;\n        styleDeclaration.getObjectScaling = this.getObjectScaling;\n        this._setShadow.call(styleDeclaration, ctx);\n      }\n\n      if (!this.caching || !charWidthsCache[cacheProp]) {\n        width = ctx.measureText(_char).width;\n        this.caching && (charWidthsCache[cacheProp] = width);\n        return width;\n      }\n\n      return charWidthsCache[cacheProp];\n    },\n\n    /**\n     * @private\n     * @param {Object} styleDeclaration\n     */\n    _applyFontStyles: function(styleDeclaration) {\n      if (!styleDeclaration.fontFamily) {\n        styleDeclaration.fontFamily = this.fontFamily;\n      }\n      if (!styleDeclaration.fontSize) {\n        styleDeclaration.fontSize = this.fontSize;\n      }\n      if (!styleDeclaration.fontWeight) {\n        styleDeclaration.fontWeight = this.fontWeight;\n      }\n      if (!styleDeclaration.fontStyle) {\n        styleDeclaration.fontStyle = this.fontStyle;\n      }\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @param {Boolean} [returnCloneOrEmpty=false]\n     * @private\n     */\n    _getStyleDeclaration: function(lineIndex, charIndex, returnCloneOrEmpty) {\n      if (returnCloneOrEmpty) {\n        return (this.styles[lineIndex] && this.styles[lineIndex][charIndex])\n          ? clone(this.styles[lineIndex][charIndex])\n          : { };\n      }\n\n      return this.styles[lineIndex] && this.styles[lineIndex][charIndex] ? this.styles[lineIndex][charIndex] : null;\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @param {Object} style\n     * @private\n     */\n    _setStyleDeclaration: function(lineIndex, charIndex, style) {\n      this.styles[lineIndex][charIndex] = style;\n    },\n\n    /**\n     *\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @private\n     */\n    _deleteStyleDeclaration: function(lineIndex, charIndex) {\n      delete this.styles[lineIndex][charIndex];\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @private\n     */\n    _getLineStyle: function(lineIndex) {\n      return this.styles[lineIndex];\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Object} style\n     * @private\n     */\n    _setLineStyle: function(lineIndex, style) {\n      this.styles[lineIndex] = style;\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @private\n     */\n    _deleteLineStyle: function(lineIndex) {\n      delete this.styles[lineIndex];\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _getWidthOfChar: function(ctx, _char, lineIndex, charIndex) {\n      if (!this._isMeasuring && this.textAlign === 'justify' && this._reSpacesAndTabs.test(_char)) {\n        return this._getWidthOfSpace(ctx, lineIndex);\n      }\n      ctx.save();\n      var width = this._applyCharStylesGetWidth(ctx, _char, lineIndex, charIndex);\n      if (this.charSpacing !== 0) {\n        width += this._getWidthOfCharSpacing();\n      }\n      ctx.restore();\n      return width > 0 ? width : 0;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     */\n    _getHeightOfChar: function(ctx, lineIndex, charIndex) {\n      var style = this._getStyleDeclaration(lineIndex, charIndex);\n      return style && style.fontSize ? style.fontSize : this.fontSize;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     */\n    _getWidthOfCharsAt: function(ctx, lineIndex, charIndex) {\n      var width = 0, i, _char;\n      for (i = 0; i < charIndex; i++) {\n        _char = this._textLines[lineIndex][i];\n        width += this._getWidthOfChar(ctx, _char, lineIndex, i);\n      }\n      return width;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Number} lineIndex line number\n     * @return {Number} Line width\n     */\n    _measureLine: function(ctx, lineIndex) {\n      this._isMeasuring = true;\n      var width = this._getWidthOfCharsAt(ctx, lineIndex, this._textLines[lineIndex].length);\n      if (this.charSpacing !== 0) {\n        width -= this._getWidthOfCharSpacing();\n      }\n      this._isMeasuring = false;\n      return width > 0 ? width : 0;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Number} lineIndex\n     */\n    _getWidthOfSpace: function (ctx, lineIndex) {\n      if (this.__widthOfSpace[lineIndex]) {\n        return this.__widthOfSpace[lineIndex];\n      }\n      var line = this._textLines[lineIndex],\n          wordsWidth = this._getWidthOfWords(ctx, line, lineIndex, 0),\n          widthDiff = this.width - wordsWidth,\n          numSpaces = line.length - line.replace(this._reSpacesAndTabs, '').length,\n          width = Math.max(widthDiff / numSpaces, ctx.measureText(' ').width);\n      this.__widthOfSpace[lineIndex] = width;\n      return width;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} line\n     * @param {Number} lineIndex\n     * @param {Number} charOffset\n     */\n    _getWidthOfWords: function (ctx, line, lineIndex, charOffset) {\n      var width = 0;\n\n      for (var charIndex = 0; charIndex < line.length; charIndex++) {\n        var _char = line[charIndex];\n\n        if (!_char.match(/\\s/)) {\n          width += this._getWidthOfChar(ctx, _char, lineIndex, charIndex + charOffset);\n        }\n      }\n\n      return width;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _getHeightOfLine: function(ctx, lineIndex) {\n      if (this.__lineHeights[lineIndex]) {\n        return this.__lineHeights[lineIndex];\n      }\n\n      var line = this._textLines[lineIndex],\n          maxHeight = this._getHeightOfChar(ctx, lineIndex, 0);\n\n      for (var i = 1, len = line.length; i < len; i++) {\n        var currentCharHeight = this._getHeightOfChar(ctx, lineIndex, i);\n        if (currentCharHeight > maxHeight) {\n          maxHeight = currentCharHeight;\n        }\n      }\n      this.__lineHeights[lineIndex] = maxHeight * this.lineHeight * this._fontSizeMult;\n      return this.__lineHeights[lineIndex];\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _getTextHeight: function(ctx) {\n      var lineHeight, height = 0;\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        lineHeight = this._getHeightOfLine(ctx, i);\n        height += (i === len - 1 ? lineHeight / this.lineHeight : lineHeight);\n      }\n      return height;\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @method toObject\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), {\n        styles: clone(this.styles, true)\n      });\n    }\n  });\n\n  /**\n   * Returns fabric.IText instance from an object representation\n   * @static\n   * @memberOf fabric.IText\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as argument\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {fabric.IText} instance of fabric.IText\n   */\n  fabric.IText.fromObject = function(object, callback, forceAsync) {\n    return fabric.Object._fromObject('IText', object, callback, forceAsync, 'text');\n  };\n})();\n\n\n(function() {\n\n  var clone = fabric.util.object.clone;\n\n  fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n    /**\n     * Initializes all the interactive behavior of IText\n     */\n    initBehavior: function() {\n      this.initAddedHandler();\n      this.initRemovedHandler();\n      this.initCursorSelectionHandlers();\n      this.initDoubleClickSimulation();\n      this.mouseMoveHandler = this.mouseMoveHandler.bind(this);\n    },\n\n    onDeselect: function() {\n      this.isEditing && this.exitEditing();\n      this.selected = false;\n      this.callSuper('onDeselect');\n    },\n\n    /**\n     * Initializes \"added\" event handler\n     */\n    initAddedHandler: function() {\n      var _this = this;\n      this.on('added', function() {\n        var canvas = _this.canvas;\n        if (canvas) {\n          if (!canvas._hasITextHandlers) {\n            canvas._hasITextHandlers = true;\n            _this._initCanvasHandlers(canvas);\n          }\n          canvas._iTextInstances = canvas._iTextInstances || [];\n          canvas._iTextInstances.push(_this);\n        }\n      });\n    },\n\n    initRemovedHandler: function() {\n      var _this = this;\n      this.on('removed', function() {\n        var canvas = _this.canvas;\n        if (canvas) {\n          canvas._iTextInstances = canvas._iTextInstances || [];\n          fabric.util.removeFromArray(canvas._iTextInstances, _this);\n          if (canvas._iTextInstances.length === 0) {\n            canvas._hasITextHandlers = false;\n            _this._removeCanvasHandlers(canvas);\n          }\n        }\n      });\n    },\n\n    /**\n     * register canvas event to manage exiting on other instances\n     * @private\n     */\n    _initCanvasHandlers: function(canvas) {\n      canvas._mouseUpITextHandler = (function() {\n        if (canvas._iTextInstances) {\n          canvas._iTextInstances.forEach(function(obj) {\n            obj.__isMousedown = false;\n          });\n        }\n      }).bind(this);\n      canvas.on('mouse:up', canvas._mouseUpITextHandler);\n    },\n\n    /**\n     * remove canvas event to manage exiting on other instances\n     * @private\n     */\n    _removeCanvasHandlers: function(canvas) {\n      canvas.off('mouse:up', canvas._mouseUpITextHandler);\n    },\n\n    /**\n     * @private\n     */\n    _tick: function() {\n      this._currentTickState = this._animateCursor(this, 1, this.cursorDuration, '_onTickComplete');\n    },\n\n    /**\n     * @private\n     */\n    _animateCursor: function(obj, targetOpacity, duration, completeMethod) {\n\n      var tickState;\n\n      tickState = {\n        isAborted: false,\n        abort: function() {\n          this.isAborted = true;\n        },\n      };\n\n      obj.animate('_currentCursorOpacity', targetOpacity, {\n        duration: duration,\n        onComplete: function() {\n          if (!tickState.isAborted) {\n            obj[completeMethod]();\n          }\n        },\n        onChange: function() {\n          // we do not want to animate a selection, only cursor\n          if (obj.canvas && obj.selectionStart === obj.selectionEnd) {\n            obj.renderCursorOrSelection();\n          }\n        },\n        abort: function() {\n          return tickState.isAborted;\n        }\n      });\n      return tickState;\n    },\n\n    /**\n     * @private\n     */\n    _onTickComplete: function() {\n\n      var _this = this;\n\n      if (this._cursorTimeout1) {\n        clearTimeout(this._cursorTimeout1);\n      }\n      this._cursorTimeout1 = setTimeout(function() {\n        _this._currentTickCompleteState = _this._animateCursor(_this, 0, this.cursorDuration / 2, '_tick');\n      }, 100);\n    },\n\n    /**\n     * Initializes delayed cursor\n     */\n    initDelayedCursor: function(restart) {\n      var _this = this,\n          delay = restart ? 0 : this.cursorDelay;\n\n      this.abortCursorAnimation();\n      this._currentCursorOpacity = 1;\n      this._cursorTimeout2 = setTimeout(function() {\n        _this._tick();\n      }, delay);\n    },\n\n    /**\n     * Aborts cursor animation and clears all timeouts\n     */\n    abortCursorAnimation: function() {\n      var shouldClear = this._currentTickState || this._currentTickCompleteState;\n      this._currentTickState && this._currentTickState.abort();\n      this._currentTickCompleteState && this._currentTickCompleteState.abort();\n\n      clearTimeout(this._cursorTimeout1);\n      clearTimeout(this._cursorTimeout2);\n\n      this._currentCursorOpacity = 0;\n      // to clear just itext area we need to transform the context\n      // it may not be worth it\n      if (shouldClear) {\n        this.canvas && this.canvas.clearContext(this.canvas.contextTop || this.ctx);\n      }\n\n    },\n\n    /**\n     * Selects entire text\n     */\n    selectAll: function() {\n      this.selectionStart = 0;\n      this.selectionEnd = this.text.length;\n      this._fireSelectionChanged();\n      this._updateTextarea();\n    },\n\n    /**\n     * Returns selected text\n     * @return {String}\n     */\n    getSelectedText: function() {\n      return this.text.slice(this.selectionStart, this.selectionEnd);\n    },\n\n    /**\n     * Find new selection index representing start of current word according to current selection index\n     * @param {Number} startFrom Surrent selection index\n     * @return {Number} New selection index\n     */\n    findWordBoundaryLeft: function(startFrom) {\n      var offset = 0, index = startFrom - 1;\n\n      // remove space before cursor first\n      if (this._reSpace.test(this.text.charAt(index))) {\n        while (this._reSpace.test(this.text.charAt(index))) {\n          offset++;\n          index--;\n        }\n      }\n      while (/\\S/.test(this.text.charAt(index)) && index > -1) {\n        offset++;\n        index--;\n      }\n\n      return startFrom - offset;\n    },\n\n    /**\n     * Find new selection index representing end of current word according to current selection index\n     * @param {Number} startFrom Current selection index\n     * @return {Number} New selection index\n     */\n    findWordBoundaryRight: function(startFrom) {\n      var offset = 0, index = startFrom;\n\n      // remove space after cursor first\n      if (this._reSpace.test(this.text.charAt(index))) {\n        while (this._reSpace.test(this.text.charAt(index))) {\n          offset++;\n          index++;\n        }\n      }\n      while (/\\S/.test(this.text.charAt(index)) && index < this.text.length) {\n        offset++;\n        index++;\n      }\n\n      return startFrom + offset;\n    },\n\n    /**\n     * Find new selection index representing start of current line according to current selection index\n     * @param {Number} startFrom Current selection index\n     * @return {Number} New selection index\n     */\n    findLineBoundaryLeft: function(startFrom) {\n      var offset = 0, index = startFrom - 1;\n\n      while (!/\\n/.test(this.text.charAt(index)) && index > -1) {\n        offset++;\n        index--;\n      }\n\n      return startFrom - offset;\n    },\n\n    /**\n     * Find new selection index representing end of current line according to current selection index\n     * @param {Number} startFrom Current selection index\n     * @return {Number} New selection index\n     */\n    findLineBoundaryRight: function(startFrom) {\n      var offset = 0, index = startFrom;\n\n      while (!/\\n/.test(this.text.charAt(index)) && index < this.text.length) {\n        offset++;\n        index++;\n      }\n\n      return startFrom + offset;\n    },\n\n    /**\n     * Returns number of newlines in selected text\n     * @return {Number} Number of newlines in selected text\n     */\n    getNumNewLinesInSelectedText: function() {\n      var selectedText = this.getSelectedText(),\n          numNewLines  = 0;\n\n      for (var i = 0, len = selectedText.length; i < len; i++) {\n        if (selectedText[i] === '\\n') {\n          numNewLines++;\n        }\n      }\n      return numNewLines;\n    },\n\n    /**\n     * Finds index corresponding to beginning or end of a word\n     * @param {Number} selectionStart Index of a character\n     * @param {Number} direction 1 or -1\n     * @return {Number} Index of the beginning or end of a word\n     */\n    searchWordBoundary: function(selectionStart, direction) {\n      var index     = this._reSpace.test(this.text.charAt(selectionStart)) ? selectionStart - 1 : selectionStart,\n          _char     = this.text.charAt(index),\n          reNonWord = /[ \\n\\.,;!\\?\\-]/;\n\n      while (!reNonWord.test(_char) && index > 0 && index < this.text.length) {\n        index += direction;\n        _char = this.text.charAt(index);\n      }\n      if (reNonWord.test(_char) && _char !== '\\n') {\n        index += direction === 1 ? 0 : 1;\n      }\n      return index;\n    },\n\n    /**\n     * Selects a word based on the index\n     * @param {Number} selectionStart Index of a character\n     */\n    selectWord: function(selectionStart) {\n      selectionStart = selectionStart || this.selectionStart;\n      var newSelectionStart = this.searchWordBoundary(selectionStart, -1), /* search backwards */\n          newSelectionEnd = this.searchWordBoundary(selectionStart, 1); /* search forward */\n\n      this.selectionStart = newSelectionStart;\n      this.selectionEnd = newSelectionEnd;\n      this._fireSelectionChanged();\n      this._updateTextarea();\n      this.renderCursorOrSelection();\n    },\n\n    /**\n     * Selects a line based on the index\n     * @param {Number} selectionStart Index of a character\n     */\n    selectLine: function(selectionStart) {\n      selectionStart = selectionStart || this.selectionStart;\n      var newSelectionStart = this.findLineBoundaryLeft(selectionStart),\n          newSelectionEnd = this.findLineBoundaryRight(selectionStart);\n\n      this.selectionStart = newSelectionStart;\n      this.selectionEnd = newSelectionEnd;\n      this._fireSelectionChanged();\n      this._updateTextarea();\n    },\n\n    /**\n     * Enters editing state\n     * @return {fabric.IText} thisArg\n     * @chainable\n     */\n    enterEditing: function(e) {\n      if (this.isEditing || !this.editable) {\n        return;\n      }\n\n      if (this.canvas) {\n        this.exitEditingOnOthers(this.canvas);\n      }\n\n      this.isEditing = true;\n      this.selected = true;\n      this.initHiddenTextarea(e);\n      this.hiddenTextarea.focus();\n      this._updateTextarea();\n      this._saveEditingProps();\n      this._setEditingProps();\n      this._textBeforeEdit = this.text;\n\n      this._tick();\n      this.fire('editing:entered');\n      this._fireSelectionChanged();\n      if (!this.canvas) {\n        return this;\n      }\n      this.canvas.fire('text:editing:entered', { target: this });\n      this.initMouseMoveHandler();\n      this.canvas.renderAll();\n      return this;\n    },\n\n    exitEditingOnOthers: function(canvas) {\n      if (canvas._iTextInstances) {\n        canvas._iTextInstances.forEach(function(obj) {\n          obj.selected = false;\n          if (obj.isEditing) {\n            obj.exitEditing();\n          }\n        });\n      }\n    },\n\n    /**\n     * Initializes \"mousemove\" event handler\n     */\n    initMouseMoveHandler: function() {\n      this.canvas.on('mouse:move', this.mouseMoveHandler);\n    },\n\n    /**\n     * @private\n     */\n    mouseMoveHandler: function(options) {\n      if (!this.__isMousedown || !this.isEditing) {\n        return;\n      }\n\n      var newSelectionStart = this.getSelectionStartFromPointer(options.e),\n          currentStart = this.selectionStart,\n          currentEnd = this.selectionEnd;\n      if (\n        (newSelectionStart !== this.__selectionStartOnMouseDown || currentStart === currentEnd)\n        &&\n        (currentStart === newSelectionStart || currentEnd === newSelectionStart)\n      ) {\n        return;\n      }\n      if (newSelectionStart > this.__selectionStartOnMouseDown) {\n        this.selectionStart = this.__selectionStartOnMouseDown;\n        this.selectionEnd = newSelectionStart;\n      }\n      else {\n        this.selectionStart = newSelectionStart;\n        this.selectionEnd = this.__selectionStartOnMouseDown;\n      }\n      if (this.selectionStart !== currentStart || this.selectionEnd !== currentEnd) {\n        this.restartCursorIfNeeded();\n        this._fireSelectionChanged();\n        this._updateTextarea();\n        this.renderCursorOrSelection();\n      }\n    },\n\n    /**\n     * @private\n     */\n    _setEditingProps: function() {\n      this.hoverCursor = 'text';\n\n      if (this.canvas) {\n        this.canvas.defaultCursor = this.canvas.moveCursor = 'text';\n      }\n\n      this.borderColor = this.editingBorderColor;\n\n      this.hasControls = this.selectable = false;\n      this.lockMovementX = this.lockMovementY = true;\n    },\n\n    /**\n     * @private\n     */\n    _updateTextarea: function() {\n      if (!this.hiddenTextarea || this.inCompositionMode) {\n        return;\n      }\n      this.cursorOffsetCache = { };\n      this.hiddenTextarea.value = this.text;\n      this.hiddenTextarea.selectionStart = this.selectionStart;\n      this.hiddenTextarea.selectionEnd = this.selectionEnd;\n      if (this.selectionStart === this.selectionEnd) {\n        var style = this._calcTextareaPosition();\n        this.hiddenTextarea.style.left = style.left;\n        this.hiddenTextarea.style.top = style.top;\n        this.hiddenTextarea.style.fontSize = style.fontSize;\n      }\n    },\n\n    /**\n     * @private\n     * @return {Object} style contains style for hiddenTextarea\n     */\n    _calcTextareaPosition: function() {\n      if (!this.canvas) {\n        return { x: 1, y: 1 };\n      }\n      var chars = this.text.split(''),\n          boundaries = this._getCursorBoundaries(chars, 'cursor'),\n          cursorLocation = this.get2DCursorLocation(),\n          lineIndex = cursorLocation.lineIndex,\n          charIndex = cursorLocation.charIndex,\n          charHeight = this.getCurrentCharFontSize(lineIndex, charIndex),\n          leftOffset = boundaries.leftOffset,\n          m = this.calcTransformMatrix(),\n          p = {\n            x: boundaries.left + leftOffset,\n            y: boundaries.top + boundaries.topOffset + charHeight\n          },\n          upperCanvas = this.canvas.upperCanvasEl,\n          maxWidth = upperCanvas.width - charHeight,\n          maxHeight = upperCanvas.height - charHeight;\n\n      p = fabric.util.transformPoint(p, m);\n      p = fabric.util.transformPoint(p, this.canvas.viewportTransform);\n\n      if (p.x < 0) {\n        p.x = 0;\n      }\n      if (p.x > maxWidth) {\n        p.x = maxWidth;\n      }\n      if (p.y < 0) {\n        p.y = 0;\n      }\n      if (p.y > maxHeight) {\n        p.y = maxHeight;\n      }\n\n      // add canvas offset on document\n      p.x += this.canvas._offset.left;\n      p.y += this.canvas._offset.top;\n\n      return { left: p.x + 'px', top: p.y + 'px', fontSize: charHeight };\n    },\n\n    /**\n     * @private\n     */\n    _saveEditingProps: function() {\n      this._savedProps = {\n        hasControls: this.hasControls,\n        borderColor: this.borderColor,\n        lockMovementX: this.lockMovementX,\n        lockMovementY: this.lockMovementY,\n        hoverCursor: this.hoverCursor,\n        defaultCursor: this.canvas && this.canvas.defaultCursor,\n        moveCursor: this.canvas && this.canvas.moveCursor\n      };\n    },\n\n    /**\n     * @private\n     */\n    _restoreEditingProps: function() {\n      if (!this._savedProps) {\n        return;\n      }\n\n      this.hoverCursor = this._savedProps.overCursor;\n      this.hasControls = this._savedProps.hasControls;\n      this.borderColor = this._savedProps.borderColor;\n      this.lockMovementX = this._savedProps.lockMovementX;\n      this.lockMovementY = this._savedProps.lockMovementY;\n\n      if (this.canvas) {\n        this.canvas.defaultCursor = this._savedProps.defaultCursor;\n        this.canvas.moveCursor = this._savedProps.moveCursor;\n      }\n    },\n\n    /**\n     * Exits from editing state\n     * @return {fabric.IText} thisArg\n     * @chainable\n     */\n    exitEditing: function() {\n      var isTextChanged = (this._textBeforeEdit !== this.text);\n      this.selected = false;\n      this.isEditing = false;\n      this.selectable = true;\n\n      this.selectionEnd = this.selectionStart;\n\n      if (this.hiddenTextarea) {\n        this.hiddenTextarea.blur && this.hiddenTextarea.blur();\n        this.canvas && this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea);\n        this.hiddenTextarea = null;\n      }\n\n      this.abortCursorAnimation();\n      this._restoreEditingProps();\n      this._currentCursorOpacity = 0;\n\n      this.fire('editing:exited');\n      isTextChanged && this.fire('modified');\n      if (this.canvas) {\n        this.canvas.off('mouse:move', this.mouseMoveHandler);\n        this.canvas.fire('text:editing:exited', { target: this });\n        isTextChanged && this.canvas.fire('object:modified', { target: this });\n      }\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _removeExtraneousStyles: function() {\n      for (var prop in this.styles) {\n        if (!this._textLines[prop]) {\n          delete this.styles[prop];\n        }\n      }\n    },\n\n    /**\n     * @private\n     */\n    _removeCharsFromTo: function(start, end) {\n      while (end !== start) {\n        this._removeSingleCharAndStyle(start + 1);\n        end--;\n      }\n      this.selectionStart = start;\n      this.selectionEnd = start;\n    },\n\n    _removeSingleCharAndStyle: function(index) {\n      var isBeginningOfLine = this.text[index - 1] === '\\n',\n          indexStyle        = isBeginningOfLine ? index : index - 1;\n      this.removeStyleObject(isBeginningOfLine, indexStyle);\n      this.text = this.text.slice(0, index - 1) +\n        this.text.slice(index);\n\n      this._textLines = this._splitTextIntoLines();\n    },\n\n    /**\n     * Inserts characters where cursor is (replacing selection if one exists)\n     * @param {String} _chars Characters to insert\n     * @param {Boolean} useCopiedStyle use fabric.copiedTextStyle\n     */\n    insertChars: function(_chars, useCopiedStyle) {\n      var style;\n\n      if (this.selectionEnd - this.selectionStart > 1) {\n        this._removeCharsFromTo(this.selectionStart, this.selectionEnd);\n      }\n      //short circuit for block paste\n      if (!useCopiedStyle && this.isEmptyStyles()) {\n        this.insertChar(_chars, false);\n        return;\n      }\n      for (var i = 0, len = _chars.length; i < len; i++) {\n        if (useCopiedStyle) {\n          style = fabric.util.object.clone(fabric.copiedTextStyle[i], true);\n        }\n        this.insertChar(_chars[i], i < len - 1, style);\n      }\n    },\n\n    /**\n     * Inserts a character where cursor is\n     * @param {String} _char Characters to insert\n     * @param {Boolean} skipUpdate trigger rendering and updates at the end of text insert\n     * @param {Object} styleObject Style to be inserted for the new char\n     */\n    insertChar: function(_char, skipUpdate, styleObject) {\n      var isEndOfLine = this.text[this.selectionStart] === '\\n';\n      this.text = this.text.slice(0, this.selectionStart) +\n        _char + this.text.slice(this.selectionEnd);\n      this._textLines = this._splitTextIntoLines();\n      this.insertStyleObjects(_char, isEndOfLine, styleObject);\n      this.selectionStart += _char.length;\n      this.selectionEnd = this.selectionStart;\n      if (skipUpdate) {\n        return;\n      }\n      this._updateTextarea();\n      this.setCoords();\n      this._fireSelectionChanged();\n      this.fire('changed');\n      this.restartCursorIfNeeded();\n      if (this.canvas) {\n        this.canvas.fire('text:changed', { target: this });\n        this.canvas.renderAll();\n      }\n    },\n\n    restartCursorIfNeeded: function() {\n      if (!this._currentTickState || this._currentTickState.isAborted\n        || !this._currentTickCompleteState || this._currentTickCompleteState.isAborted\n      ) {\n        this.initDelayedCursor();\n      }\n    },\n\n    /**\n     * Inserts new style object\n     * @param {Number} lineIndex Index of a line\n     * @param {Number} charIndex Index of a char\n     * @param {Boolean} isEndOfLine True if it's end of line\n     */\n    insertNewlineStyleObject: function(lineIndex, charIndex, isEndOfLine) {\n\n      this.shiftLineStyles(lineIndex, +1);\n\n      var currentCharStyle = {},\n          newLineStyles    = {};\n\n      if (this.styles[lineIndex] && this.styles[lineIndex][charIndex - 1]) {\n        currentCharStyle = this.styles[lineIndex][charIndex - 1];\n      }\n\n      // if there's nothing after cursor,\n      // we clone current char style onto the next (otherwise empty) line\n      if (isEndOfLine && currentCharStyle) {\n        newLineStyles[0] = clone(currentCharStyle);\n        this.styles[lineIndex + 1] = newLineStyles;\n      }\n      // otherwise we clone styles of all chars\n      // after cursor onto the next line, from the beginning\n      else {\n        var somethingAdded = false;\n        for (var index in this.styles[lineIndex]) {\n          var numIndex = parseInt(index, 10);\n          if (numIndex >= charIndex) {\n            somethingAdded = true;\n            newLineStyles[numIndex - charIndex] = this.styles[lineIndex][index];\n            // remove lines from the previous line since they're on a new line now\n            delete this.styles[lineIndex][index];\n          }\n        }\n        somethingAdded && (this.styles[lineIndex + 1] = newLineStyles);\n      }\n      this._forceClearCache = true;\n    },\n\n    /**\n     * Inserts style object for a given line/char index\n     * @param {Number} lineIndex Index of a line\n     * @param {Number} charIndex Index of a char\n     * @param {Object} [style] Style object to insert, if given\n     */\n    insertCharStyleObject: function(lineIndex, charIndex, style) {\n\n      var currentLineStyles       = this.styles[lineIndex],\n          currentLineStylesCloned = clone(currentLineStyles);\n\n      if (charIndex === 0 && !style) {\n        charIndex = 1;\n      }\n\n      // shift all char styles by 1 forward\n      // 0,1,2,3 -> (charIndex=2) -> 0,1,3,4 -> (insert 2) -> 0,1,2,3,4\n      for (var index in currentLineStylesCloned) {\n        var numericIndex = parseInt(index, 10);\n\n        if (numericIndex >= charIndex) {\n          currentLineStyles[numericIndex + 1] = currentLineStylesCloned[numericIndex];\n\n          // only delete the style if there was nothing moved there\n          if (!currentLineStylesCloned[numericIndex - 1]) {\n            delete currentLineStyles[numericIndex];\n          }\n        }\n      }\n      var newStyle = style || clone(currentLineStyles[charIndex - 1]);\n      newStyle && (this.styles[lineIndex][charIndex] = newStyle);\n      this._forceClearCache = true;\n    },\n\n    /**\n     * Inserts style object(s)\n     * @param {String} _chars Characters at the location where style is inserted\n     * @param {Boolean} isEndOfLine True if it's end of line\n     * @param {Object} [styleObject] Style to insert\n     */\n    insertStyleObjects: function(_chars, isEndOfLine, styleObject) {\n      // removed shortcircuit over isEmptyStyles\n\n      var cursorLocation = this.get2DCursorLocation(),\n          lineIndex      = cursorLocation.lineIndex,\n          charIndex      = cursorLocation.charIndex;\n\n      if (!this._getLineStyle(lineIndex)) {\n        this._setLineStyle(lineIndex, {});\n      }\n\n      if (_chars === '\\n') {\n        this.insertNewlineStyleObject(lineIndex, charIndex, isEndOfLine);\n      }\n      else {\n        this.insertCharStyleObject(lineIndex, charIndex, styleObject);\n      }\n    },\n\n    /**\n     * Shifts line styles up or down\n     * @param {Number} lineIndex Index of a line\n     * @param {Number} offset Can be -1 or +1\n     */\n    shiftLineStyles: function(lineIndex, offset) {\n      // shift all line styles by 1 upward or downward\n      var clonedStyles = clone(this.styles);\n      for (var line in clonedStyles) {\n        var numericLine = parseInt(line, 10);\n        if (numericLine <= lineIndex) {\n          delete clonedStyles[numericLine];\n        }\n      }\n      for (var line in this.styles) {\n        var numericLine = parseInt(line, 10);\n        if (numericLine > lineIndex) {\n          this.styles[numericLine + offset] = clonedStyles[numericLine];\n          if (!clonedStyles[numericLine - offset]) {\n            delete this.styles[numericLine];\n          }\n        }\n      }\n      //TODO: evaluate if delete old style lines with offset -1\n    },\n\n    /**\n     * Removes style object\n     * @param {Boolean} isBeginningOfLine True if cursor is at the beginning of line\n     * @param {Number} [index] Optional index. When not given, current selectionStart is used.\n     */\n    removeStyleObject: function(isBeginningOfLine, index) {\n\n      var cursorLocation = this.get2DCursorLocation(index),\n          lineIndex      = cursorLocation.lineIndex,\n          charIndex      = cursorLocation.charIndex;\n\n      this._removeStyleObject(isBeginningOfLine, cursorLocation, lineIndex, charIndex);\n    },\n\n    _getTextOnPreviousLine: function(lIndex) {\n      return this._textLines[lIndex - 1];\n    },\n\n    _removeStyleObject: function(isBeginningOfLine, cursorLocation, lineIndex, charIndex) {\n\n      if (isBeginningOfLine) {\n        var textOnPreviousLine     = this._getTextOnPreviousLine(cursorLocation.lineIndex),\n            newCharIndexOnPrevLine = textOnPreviousLine ? textOnPreviousLine.length : 0;\n\n        if (!this.styles[lineIndex - 1]) {\n          this.styles[lineIndex - 1] = {};\n        }\n        for (charIndex in this.styles[lineIndex]) {\n          this.styles[lineIndex - 1][parseInt(charIndex, 10) + newCharIndexOnPrevLine]\n            = this.styles[lineIndex][charIndex];\n        }\n        this.shiftLineStyles(cursorLocation.lineIndex, -1);\n      }\n      else {\n        var currentLineStyles = this.styles[lineIndex];\n\n        if (currentLineStyles) {\n          delete currentLineStyles[charIndex];\n        }\n        var currentLineStylesCloned = clone(currentLineStyles);\n        // shift all styles by 1 backwards\n        for (var i in currentLineStylesCloned) {\n          var numericIndex = parseInt(i, 10);\n          if (numericIndex >= charIndex && numericIndex !== 0) {\n            currentLineStyles[numericIndex - 1] = currentLineStylesCloned[numericIndex];\n            delete currentLineStyles[numericIndex];\n          }\n        }\n      }\n    },\n\n    /**\n     * Inserts new line\n     */\n    insertNewline: function() {\n      this.insertChars('\\n');\n    },\n\n    /**\n     * Set the selectionStart and selectionEnd according to the ne postion of cursor\n     * mimic the key - mouse navigation when shift is pressed.\n     */\n    setSelectionStartEndWithShift: function(start, end, newSelection) {\n      if (newSelection <= start) {\n        if (end === start) {\n          this._selectionDirection = 'left';\n        }\n        else if (this._selectionDirection === 'right') {\n          this._selectionDirection = 'left';\n          this.selectionEnd = start;\n        }\n        this.selectionStart = newSelection;\n      }\n      else if (newSelection > start && newSelection < end) {\n        if (this._selectionDirection === 'right') {\n          this.selectionEnd = newSelection;\n        }\n        else {\n          this.selectionStart = newSelection;\n        }\n      }\n      else {\n        // newSelection is > selection start and end\n        if (end === start) {\n          this._selectionDirection = 'right';\n        }\n        else if (this._selectionDirection === 'left') {\n          this._selectionDirection = 'right';\n          this.selectionStart = end;\n        }\n        this.selectionEnd = newSelection;\n      }\n    },\n\n    setSelectionInBoundaries: function() {\n      var length = this.text.length;\n      if (this.selectionStart > length) {\n        this.selectionStart = length;\n      }\n      else if (this.selectionStart < 0) {\n        this.selectionStart = 0;\n      }\n      if (this.selectionEnd > length) {\n        this.selectionEnd = length;\n      }\n      else if (this.selectionEnd < 0) {\n        this.selectionEnd = 0;\n      }\n    }\n  });\n})();\n\n\nfabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n  /**\n   * Initializes \"dbclick\" event handler\n   */\n  initDoubleClickSimulation: function() {\n\n    // for double click\n    this.__lastClickTime = +new Date();\n\n    // for triple click\n    this.__lastLastClickTime = +new Date();\n\n    this.__lastPointer = { };\n\n    this.on('mousedown', this.onMouseDown.bind(this));\n  },\n\n  onMouseDown: function(options) {\n\n    this.__newClickTime = +new Date();\n    var newPointer = this.canvas.getPointer(options.e);\n\n    if (this.isTripleClick(newPointer, options.e)) {\n      this.fire('tripleclick', options);\n      this._stopEvent(options.e);\n    }\n    else if (this.isDoubleClick(newPointer)) {\n      this.fire('dblclick', options);\n      this._stopEvent(options.e);\n    }\n\n    this.__lastLastClickTime = this.__lastClickTime;\n    this.__lastClickTime = this.__newClickTime;\n    this.__lastPointer = newPointer;\n    this.__lastIsEditing = this.isEditing;\n    this.__lastSelected = this.selected;\n  },\n\n  isDoubleClick: function(newPointer) {\n    return this.__newClickTime - this.__lastClickTime < 500 &&\n        this.__lastPointer.x === newPointer.x &&\n        this.__lastPointer.y === newPointer.y && this.__lastIsEditing;\n  },\n\n  isTripleClick: function(newPointer) {\n    return this.__newClickTime - this.__lastClickTime < 500 &&\n        this.__lastClickTime - this.__lastLastClickTime < 500 &&\n        this.__lastPointer.x === newPointer.x &&\n        this.__lastPointer.y === newPointer.y;\n  },\n\n  /**\n   * @private\n   */\n  _stopEvent: function(e) {\n    e.preventDefault && e.preventDefault();\n    e.stopPropagation && e.stopPropagation();\n  },\n\n  /**\n   * Initializes event handlers related to cursor or selection\n   */\n  initCursorSelectionHandlers: function() {\n    this.initMousedownHandler();\n    this.initMouseupHandler();\n    this.initClicks();\n  },\n\n  /**\n   * Initializes double and triple click event handlers\n   */\n  initClicks: function() {\n    this.on('dblclick', function(options) {\n      this.selectWord(this.getSelectionStartFromPointer(options.e));\n    });\n    this.on('tripleclick', function(options) {\n      this.selectLine(this.getSelectionStartFromPointer(options.e));\n    });\n  },\n\n  /**\n   * Initializes \"mousedown\" event handler\n   */\n  initMousedownHandler: function() {\n    this.on('mousedown', function(options) {\n      if (!this.editable || (options.e.button && options.e.button !== 1)) {\n        return;\n      }\n      var pointer = this.canvas.getPointer(options.e);\n      this.__mousedownX = pointer.x;\n      this.__mousedownY = pointer.y;\n      this.__isMousedown = true;\n\n      if (this.selected) {\n        this.setCursorByClick(options.e);\n      }\n\n      if (this.isEditing) {\n        this.__selectionStartOnMouseDown = this.selectionStart;\n        if (this.selectionStart === this.selectionEnd) {\n          this.abortCursorAnimation();\n        }\n        this.renderCursorOrSelection();\n      }\n    });\n  },\n\n  /**\n   * @private\n   */\n  _isObjectMoved: function(e) {\n    var pointer = this.canvas.getPointer(e);\n\n    return this.__mousedownX !== pointer.x ||\n           this.__mousedownY !== pointer.y;\n  },\n\n  /**\n   * Initializes \"mouseup\" event handler\n   */\n  initMouseupHandler: function() {\n    this.on('mouseup', function(options) {\n      this.__isMousedown = false;\n      if (!this.editable || this._isObjectMoved(options.e) || (options.e.button && options.e.button !== 1)) {\n        return;\n      }\n\n      if (this.__lastSelected && !this.__corner) {\n        this.enterEditing(options.e);\n        if (this.selectionStart === this.selectionEnd) {\n          this.initDelayedCursor(true);\n        }\n        else {\n          this.renderCursorOrSelection();\n        }\n      }\n      this.selected = true;\n    });\n  },\n\n  /**\n   * Changes cursor location in a text depending on passed pointer (x/y) object\n   * @param {Event} e Event object\n   */\n  setCursorByClick: function(e) {\n    var newSelection = this.getSelectionStartFromPointer(e),\n        start = this.selectionStart, end = this.selectionEnd;\n    if (e.shiftKey) {\n      this.setSelectionStartEndWithShift(start, end, newSelection);\n    }\n    else {\n      this.selectionStart = newSelection;\n      this.selectionEnd = newSelection;\n    }\n    if (this.isEditing) {\n      this._fireSelectionChanged();\n      this._updateTextarea();\n    }\n  },\n\n  /**\n   * Returns index of a character corresponding to where an object was clicked\n   * @param {Event} e Event object\n   * @return {Number} Index of a character\n   */\n  getSelectionStartFromPointer: function(e) {\n    var mouseOffset = this.getLocalPointer(e),\n        prevWidth = 0,\n        width = 0,\n        height = 0,\n        charIndex = 0,\n        newSelectionStart,\n        line;\n\n    for (var i = 0, len = this._textLines.length; i < len; i++) {\n      line = this._textLines[i];\n      height += this._getHeightOfLine(this.ctx, i) * this.scaleY;\n\n      var widthOfLine = this._getLineWidth(this.ctx, i),\n          lineLeftOffset = this._getLineLeftOffset(widthOfLine);\n\n      width = lineLeftOffset * this.scaleX;\n\n      for (var j = 0, jlen = line.length; j < jlen; j++) {\n\n        prevWidth = width;\n\n        width += this._getWidthOfChar(this.ctx, line[j], i, this.flipX ? jlen - j : j) *\n                 this.scaleX;\n\n        if (height <= mouseOffset.y || width <= mouseOffset.x) {\n          charIndex++;\n          continue;\n        }\n\n        return this._getNewSelectionStartFromOffset(\n          mouseOffset, prevWidth, width, charIndex + i, jlen);\n      }\n\n      if (mouseOffset.y < height) {\n        //this happens just on end of lines.\n        return this._getNewSelectionStartFromOffset(\n          mouseOffset, prevWidth, width, charIndex + i - 1, jlen);\n      }\n    }\n\n    // clicked somewhere after all chars, so set at the end\n    if (typeof newSelectionStart === 'undefined') {\n      return this.text.length;\n    }\n  },\n\n  /**\n   * @private\n   */\n  _getNewSelectionStartFromOffset: function(mouseOffset, prevWidth, width, index, jlen) {\n\n    var distanceBtwLastCharAndCursor = mouseOffset.x - prevWidth,\n        distanceBtwNextCharAndCursor = width - mouseOffset.x,\n        offset = distanceBtwNextCharAndCursor > distanceBtwLastCharAndCursor ? 0 : 1,\n        newSelectionStart = index + offset;\n\n    // if object is horizontally flipped, mirror cursor location from the end\n    if (this.flipX) {\n      newSelectionStart = jlen - newSelectionStart;\n    }\n\n    if (newSelectionStart > this.text.length) {\n      newSelectionStart = this.text.length;\n    }\n\n    return newSelectionStart;\n  }\n});\n\n\nfabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n  /**\n   * Initializes hidden textarea (needed to bring up keyboard in iOS)\n   */\n  initHiddenTextarea: function() {\n    this.hiddenTextarea = fabric.document.createElement('textarea');\n    this.hiddenTextarea.setAttribute('autocapitalize', 'off');\n    this.hiddenTextarea.setAttribute('autocorrect', 'off');\n    this.hiddenTextarea.setAttribute('autocomplete', 'off');\n    this.hiddenTextarea.setAttribute('spellcheck', 'false');\n    this.hiddenTextarea.setAttribute('data-fabric-hiddentextarea', '');\n    this.hiddenTextarea.setAttribute('wrap', 'off');\n    var style = this._calcTextareaPosition();\n    this.hiddenTextarea.style.cssText = 'position: absolute; top: ' + style.top +\n    '; left: ' + style.left + '; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px;' +\n    ' line-height: 1px; paddingｰtop: ' + style.fontSize + ';';\n    fabric.document.body.appendChild(this.hiddenTextarea);\n\n    fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'keyup', this.onKeyUp.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'input', this.onInput.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'copy', this.copy.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'cut', this.cut.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'paste', this.paste.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'compositionstart', this.onCompositionStart.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'compositionupdate', this.onCompositionUpdate.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'compositionend', this.onCompositionEnd.bind(this));\n\n    if (!this._clickHandlerInitialized && this.canvas) {\n      fabric.util.addListener(this.canvas.upperCanvasEl, 'click', this.onClick.bind(this));\n      this._clickHandlerInitialized = true;\n    }\n  },\n\n  /**\n   * For functionalities on keyDown\n   * Map a special key to a function of the instance/prototype\n   * If you need different behaviour for ESC or TAB or arrows, you have to change\n   * this map setting the name of a function that you build on the fabric.Itext or\n   * your prototype.\n   * the map change will affect all Instances unless you need for only some text Instances\n   * in that case you have to clone this object and assign your Instance.\n   * this.keysMap = fabric.util.object.clone(this.keysMap);\n   * The function must be in fabric.Itext.prototype.myFunction And will receive event as args[0]\n   */\n  keysMap: {\n    8:  'removeChars',\n    9:  'exitEditing',\n    27: 'exitEditing',\n    13: 'insertNewline',\n    33: 'moveCursorUp',\n    34: 'moveCursorDown',\n    35: 'moveCursorRight',\n    36: 'moveCursorLeft',\n    37: 'moveCursorLeft',\n    38: 'moveCursorUp',\n    39: 'moveCursorRight',\n    40: 'moveCursorDown',\n    46: 'forwardDelete'\n  },\n\n  /**\n   * For functionalities on keyUp + ctrl || cmd\n   */\n  ctrlKeysMapUp: {\n    67: 'copy',\n    88: 'cut'\n  },\n\n  /**\n   * For functionalities on keyDown + ctrl || cmd\n   */\n  ctrlKeysMapDown: {\n    65: 'selectAll'\n  },\n\n  onClick: function() {\n    // No need to trigger click event here, focus is enough to have the keyboard appear on Android\n    this.hiddenTextarea && this.hiddenTextarea.focus();\n  },\n\n  /**\n   * Handles keyup event\n   * @param {Event} e Event object\n   */\n  onKeyDown: function(e) {\n    if (!this.isEditing) {\n      return;\n    }\n    if (e.keyCode in this.keysMap) {\n      this[this.keysMap[e.keyCode]](e);\n    }\n    else if ((e.keyCode in this.ctrlKeysMapDown) && (e.ctrlKey || e.metaKey)) {\n      this[this.ctrlKeysMapDown[e.keyCode]](e);\n    }\n    else {\n      return;\n    }\n    e.stopImmediatePropagation();\n    e.preventDefault();\n    if (e.keyCode >= 33 && e.keyCode <= 40) {\n      // if i press an arrow key just update selection\n      this.clearContextTop();\n      this.renderCursorOrSelection();\n    }\n    else {\n      this.canvas && this.canvas.renderAll();\n    }\n  },\n\n  /**\n   * Handles keyup event\n   * We handle KeyUp because ie11 and edge have difficulties copy/pasting\n   * if a copy/cut event fired, keyup is dismissed\n   * @param {Event} e Event object\n   */\n  onKeyUp: function(e) {\n    if (!this.isEditing || this._copyDone) {\n      this._copyDone = false;\n      return;\n    }\n    if ((e.keyCode in this.ctrlKeysMapUp) && (e.ctrlKey || e.metaKey)) {\n      this[this.ctrlKeysMapUp[e.keyCode]](e);\n    }\n    else {\n      return;\n    }\n    e.stopImmediatePropagation();\n    e.preventDefault();\n    this.canvas && this.canvas.renderAll();\n  },\n\n  /**\n   * Handles onInput event\n   * @param {Event} e Event object\n   */\n  onInput: function(e) {\n    if (!this.isEditing || this.inCompositionMode) {\n      return;\n    }\n    var offset = this.selectionStart || 0,\n        offsetEnd = this.selectionEnd || 0,\n        textLength = this.text.length,\n        newTextLength = this.hiddenTextarea.value.length,\n        diff, charsToInsert, start;\n    if (newTextLength > textLength) {\n      //we added some character\n      start = this._selectionDirection === 'left' ? offsetEnd : offset;\n      diff = newTextLength - textLength;\n      charsToInsert = this.hiddenTextarea.value.slice(start, start + diff);\n    }\n    else {\n      //we selected a portion of text and then input something else.\n      //Internet explorer does not trigger this else\n      diff = newTextLength - textLength + offsetEnd - offset;\n      charsToInsert = this.hiddenTextarea.value.slice(offset, offset + diff);\n    }\n    this.insertChars(charsToInsert);\n    e.stopPropagation();\n  },\n\n  /**\n   * Composition start\n   */\n  onCompositionStart: function() {\n    this.inCompositionMode = true;\n    this.prevCompositionLength = 0;\n    this.compositionStart = this.selectionStart;\n  },\n\n  /**\n   * Composition end\n   */\n  onCompositionEnd: function() {\n    this.inCompositionMode = false;\n  },\n\n  /**\n   * Composition update\n   */\n  onCompositionUpdate: function(e) {\n    var data = e.data;\n    this.selectionStart = this.compositionStart;\n    this.selectionEnd = this.selectionEnd === this.selectionStart ?\n      this.compositionStart + this.prevCompositionLength : this.selectionEnd;\n    this.insertChars(data, false);\n    this.prevCompositionLength = data.length;\n  },\n\n  /**\n   * Forward delete\n   */\n  forwardDelete: function(e) {\n    if (this.selectionStart === this.selectionEnd) {\n      if (this.selectionStart === this.text.length) {\n        return;\n      }\n      this.moveCursorRight(e);\n    }\n    this.removeChars(e);\n  },\n\n  /**\n   * Copies selected text\n   * @param {Event} e Event object\n   */\n  copy: function(e) {\n    if (this.selectionStart === this.selectionEnd) {\n      //do not cut-copy if no selection\n      return;\n    }\n    var selectedText = this.getSelectedText(),\n        clipboardData = this._getClipboardData(e);\n\n    // Check for backward compatibility with old browsers\n    if (clipboardData) {\n      clipboardData.setData('text', selectedText);\n    }\n\n    fabric.copiedText = selectedText;\n    fabric.copiedTextStyle = this.getSelectionStyles(this.selectionStart, this.selectionEnd);\n    e.stopImmediatePropagation();\n    e.preventDefault();\n    this._copyDone = true;\n  },\n\n  /**\n   * Pastes text\n   * @param {Event} e Event object\n   */\n  paste: function(e) {\n    var copiedText = null,\n        clipboardData = this._getClipboardData(e),\n        useCopiedStyle = true;\n\n    // Check for backward compatibility with old browsers\n    if (clipboardData) {\n      copiedText = clipboardData.getData('text').replace(/\\r/g, '');\n      if (!fabric.copiedTextStyle || fabric.copiedText !== copiedText) {\n        useCopiedStyle = false;\n      }\n    }\n    else {\n      copiedText = fabric.copiedText;\n    }\n\n    if (copiedText) {\n      this.insertChars(copiedText, useCopiedStyle);\n    }\n    e.stopImmediatePropagation();\n    e.preventDefault();\n  },\n\n  /**\n   * Cuts text\n   * @param {Event} e Event object\n   */\n  cut: function(e) {\n    if (this.selectionStart === this.selectionEnd) {\n      return;\n    }\n\n    this.copy(e);\n    this.removeChars(e);\n  },\n\n  /**\n   * @private\n   * @param {Event} e Event object\n   * @return {Object} Clipboard data object\n   */\n  _getClipboardData: function(e) {\n    return (e && e.clipboardData) || fabric.window.clipboardData;\n  },\n\n  /**\n   * Finds the width in pixels before the cursor on the same line\n   * @private\n   * @param {Number} lineIndex\n   * @param {Number} charIndex\n   * @return {Number} widthBeforeCursor width before cursor\n   */\n  _getWidthBeforeCursor: function(lineIndex, charIndex) {\n    var textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex),\n        widthOfLine = this._getLineWidth(this.ctx, lineIndex),\n        widthBeforeCursor = this._getLineLeftOffset(widthOfLine), _char;\n\n    for (var i = 0, len = textBeforeCursor.length; i < len; i++) {\n      _char = textBeforeCursor[i];\n      widthBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i);\n    }\n    return widthBeforeCursor;\n  },\n\n  /**\n   * Gets start offset of a selection\n   * @param {Event} e Event object\n   * @param {Boolean} isRight\n   * @return {Number}\n   */\n  getDownCursorOffset: function(e, isRight) {\n    var selectionProp = this._getSelectionForOffset(e, isRight),\n        cursorLocation = this.get2DCursorLocation(selectionProp),\n        lineIndex = cursorLocation.lineIndex;\n    // if on last line, down cursor goes to end of line\n    if (lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) {\n      // move to the end of a text\n      return this.text.length - selectionProp;\n    }\n    var charIndex = cursorLocation.charIndex,\n        widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),\n        indexOnOtherLine = this._getIndexOnLine(lineIndex + 1, widthBeforeCursor),\n        textAfterCursor = this._textLines[lineIndex].slice(charIndex);\n\n    return textAfterCursor.length + indexOnOtherLine + 2;\n  },\n\n  /**\n   * private\n   * Helps finding if the offset should be counted from Start or End\n   * @param {Event} e Event object\n   * @param {Boolean} isRight\n   * @return {Number}\n   */\n  _getSelectionForOffset: function(e, isRight) {\n    if (e.shiftKey && this.selectionStart !== this.selectionEnd && isRight) {\n      return this.selectionEnd;\n    }\n    else {\n      return this.selectionStart;\n    }\n  },\n\n  /**\n   * @param {Event} e Event object\n   * @param {Boolean} isRight\n   * @return {Number}\n   */\n  getUpCursorOffset: function(e, isRight) {\n    var selectionProp = this._getSelectionForOffset(e, isRight),\n        cursorLocation = this.get2DCursorLocation(selectionProp),\n        lineIndex = cursorLocation.lineIndex;\n    if (lineIndex === 0 || e.metaKey || e.keyCode === 33) {\n      // if on first line, up cursor goes to start of line\n      return -selectionProp;\n    }\n    var charIndex = cursorLocation.charIndex,\n        widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),\n        indexOnOtherLine = this._getIndexOnLine(lineIndex - 1, widthBeforeCursor),\n        textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex);\n    // return a negative offset\n    return -this._textLines[lineIndex - 1].length + indexOnOtherLine - textBeforeCursor.length;\n  },\n\n  /**\n   * find for a given width it founds the matching character.\n   * @private\n   */\n  _getIndexOnLine: function(lineIndex, width) {\n\n    var widthOfLine = this._getLineWidth(this.ctx, lineIndex),\n        textOnLine = this._textLines[lineIndex],\n        lineLeftOffset = this._getLineLeftOffset(widthOfLine),\n        widthOfCharsOnLine = lineLeftOffset,\n        indexOnLine = 0,\n        foundMatch;\n\n    for (var j = 0, jlen = textOnLine.length; j < jlen; j++) {\n\n      var _char = textOnLine[j],\n          widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j);\n\n      widthOfCharsOnLine += widthOfChar;\n\n      if (widthOfCharsOnLine > width) {\n\n        foundMatch = true;\n\n        var leftEdge = widthOfCharsOnLine - widthOfChar,\n            rightEdge = widthOfCharsOnLine,\n            offsetFromLeftEdge = Math.abs(leftEdge - width),\n            offsetFromRightEdge = Math.abs(rightEdge - width);\n\n        indexOnLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1);\n\n        break;\n      }\n    }\n\n    // reached end\n    if (!foundMatch) {\n      indexOnLine = textOnLine.length - 1;\n    }\n\n    return indexOnLine;\n  },\n\n\n  /**\n   * Moves cursor down\n   * @param {Event} e Event object\n   */\n  moveCursorDown: function(e) {\n    if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) {\n      return;\n    }\n    this._moveCursorUpOrDown('Down', e);\n  },\n\n  /**\n   * Moves cursor up\n   * @param {Event} e Event object\n   */\n  moveCursorUp: function(e) {\n    if (this.selectionStart === 0 && this.selectionEnd === 0) {\n      return;\n    }\n    this._moveCursorUpOrDown('Up', e);\n  },\n\n  /**\n   * Moves cursor up or down, fires the events\n   * @param {String} direction 'Up' or 'Down'\n   * @param {Event} e Event object\n   */\n  _moveCursorUpOrDown: function(direction, e) {\n    // getUpCursorOffset\n    // getDownCursorOffset\n    var action = 'get' + direction + 'CursorOffset',\n        offset = this[action](e, this._selectionDirection === 'right');\n    if (e.shiftKey) {\n      this.moveCursorWithShift(offset);\n    }\n    else {\n      this.moveCursorWithoutShift(offset);\n    }\n    if (offset !== 0) {\n      this.setSelectionInBoundaries();\n      this.abortCursorAnimation();\n      this._currentCursorOpacity = 1;\n      this.initDelayedCursor();\n      this._fireSelectionChanged();\n      this._updateTextarea();\n    }\n  },\n\n  /**\n   * Moves cursor with shift\n   * @param {Number} offset\n   */\n  moveCursorWithShift: function(offset) {\n    var newSelection = this._selectionDirection === 'left'\n    ? this.selectionStart + offset\n    : this.selectionEnd + offset;\n    this.setSelectionStartEndWithShift(this.selectionStart, this.selectionEnd, newSelection);\n    return offset !== 0;\n  },\n\n  /**\n   * Moves cursor up without shift\n   * @param {Number} offset\n   */\n  moveCursorWithoutShift: function(offset) {\n    if (offset < 0) {\n      this.selectionStart += offset;\n      this.selectionEnd = this.selectionStart;\n    }\n    else {\n      this.selectionEnd += offset;\n      this.selectionStart = this.selectionEnd;\n    }\n    return offset !== 0;\n  },\n\n  /**\n   * Moves cursor left\n   * @param {Event} e Event object\n   */\n  moveCursorLeft: function(e) {\n    if (this.selectionStart === 0 && this.selectionEnd === 0) {\n      return;\n    }\n    this._moveCursorLeftOrRight('Left', e);\n  },\n\n  /**\n   * @private\n   * @return {Boolean} true if a change happened\n   */\n  _move: function(e, prop, direction) {\n    var newValue;\n    if (e.altKey) {\n      newValue = this['findWordBoundary' + direction](this[prop]);\n    }\n    else if (e.metaKey || e.keyCode === 35 ||  e.keyCode === 36 ) {\n      newValue = this['findLineBoundary' + direction](this[prop]);\n    }\n    else {\n      this[prop] += direction === 'Left' ? -1 : 1;\n      return true;\n    }\n    if (typeof newValue !== undefined && this[prop] !== newValue) {\n      this[prop] = newValue;\n      return true;\n    }\n  },\n\n  /**\n   * @private\n   */\n  _moveLeft: function(e, prop) {\n    return this._move(e, prop, 'Left');\n  },\n\n  /**\n   * @private\n   */\n  _moveRight: function(e, prop) {\n    return this._move(e, prop, 'Right');\n  },\n\n  /**\n   * Moves cursor left without keeping selection\n   * @param {Event} e\n   */\n  moveCursorLeftWithoutShift: function(e) {\n    var change = true;\n    this._selectionDirection = 'left';\n\n    // only move cursor when there is no selection,\n    // otherwise we discard it, and leave cursor on same place\n    if (this.selectionEnd === this.selectionStart && this.selectionStart !== 0) {\n      change = this._moveLeft(e, 'selectionStart');\n\n    }\n    this.selectionEnd = this.selectionStart;\n    return change;\n  },\n\n  /**\n   * Moves cursor left while keeping selection\n   * @param {Event} e\n   */\n  moveCursorLeftWithShift: function(e) {\n    if (this._selectionDirection === 'right' && this.selectionStart !== this.selectionEnd) {\n      return this._moveLeft(e, 'selectionEnd');\n    }\n    else if (this.selectionStart !== 0){\n      this._selectionDirection = 'left';\n      return this._moveLeft(e, 'selectionStart');\n    }\n  },\n\n  /**\n   * Moves cursor right\n   * @param {Event} e Event object\n   */\n  moveCursorRight: function(e) {\n    if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) {\n      return;\n    }\n    this._moveCursorLeftOrRight('Right', e);\n  },\n\n  /**\n   * Moves cursor right or Left, fires event\n   * @param {String} direction 'Left', 'Right'\n   * @param {Event} e Event object\n   */\n  _moveCursorLeftOrRight: function(direction, e) {\n    var actionName = 'moveCursor' + direction + 'With';\n    this._currentCursorOpacity = 1;\n\n    if (e.shiftKey) {\n      actionName += 'Shift';\n    }\n    else {\n      actionName += 'outShift';\n    }\n    if (this[actionName](e)) {\n      this.abortCursorAnimation();\n      this.initDelayedCursor();\n      this._fireSelectionChanged();\n      this._updateTextarea();\n    }\n  },\n\n  /**\n   * Moves cursor right while keeping selection\n   * @param {Event} e\n   */\n  moveCursorRightWithShift: function(e) {\n    if (this._selectionDirection === 'left' && this.selectionStart !== this.selectionEnd) {\n      return this._moveRight(e, 'selectionStart');\n    }\n    else if (this.selectionEnd !== this.text.length) {\n      this._selectionDirection = 'right';\n      return this._moveRight(e, 'selectionEnd');\n    }\n  },\n\n  /**\n   * Moves cursor right without keeping selection\n   * @param {Event} e Event object\n   */\n  moveCursorRightWithoutShift: function(e) {\n    var changed = true;\n    this._selectionDirection = 'right';\n\n    if (this.selectionStart === this.selectionEnd) {\n      changed = this._moveRight(e, 'selectionStart');\n      this.selectionEnd = this.selectionStart;\n    }\n    else {\n      this.selectionStart = this.selectionEnd;\n    }\n    return changed;\n  },\n\n  /**\n   * Removes characters selected by selection\n   * @param {Event} e Event object\n   */\n  removeChars: function(e) {\n    if (this.selectionStart === this.selectionEnd) {\n      this._removeCharsNearCursor(e);\n    }\n    else {\n      this._removeCharsFromTo(this.selectionStart, this.selectionEnd);\n    }\n\n    this.set('dirty', true);\n    this.setSelectionEnd(this.selectionStart);\n\n    this._removeExtraneousStyles();\n\n    this.canvas && this.canvas.renderAll();\n\n    this.setCoords();\n    this.fire('changed');\n    this.canvas && this.canvas.fire('text:changed', { target: this });\n  },\n\n  /**\n   * @private\n   * @param {Event} e Event object\n   */\n  _removeCharsNearCursor: function(e) {\n    if (this.selectionStart === 0) {\n      return;\n    }\n    if (e.metaKey) {\n      // remove all till the start of current line\n      var leftLineBoundary = this.findLineBoundaryLeft(this.selectionStart);\n\n      this._removeCharsFromTo(leftLineBoundary, this.selectionStart);\n      this.setSelectionStart(leftLineBoundary);\n    }\n    else if (e.altKey) {\n      // remove all till the start of current word\n      var leftWordBoundary = this.findWordBoundaryLeft(this.selectionStart);\n\n      this._removeCharsFromTo(leftWordBoundary, this.selectionStart);\n      this.setSelectionStart(leftWordBoundary);\n    }\n    else {\n      this._removeSingleCharAndStyle(this.selectionStart);\n      this.setSelectionStart(this.selectionStart - 1);\n    }\n  }\n});\n\n\n/* _TO_SVG_START_ */\n(function() {\n  var toFixed = fabric.util.toFixed,\n      NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n\n  fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n    /**\n     * @private\n     */\n    _setSVGTextLineText: function(lineIndex, textSpans, height, textLeftOffset, textTopOffset, textBgRects) {\n      if (!this._getLineStyle(lineIndex)) {\n        fabric.Text.prototype._setSVGTextLineText.call(this,\n          lineIndex, textSpans, height, textLeftOffset, textTopOffset);\n      }\n      else {\n        this._setSVGTextLineChars(\n          lineIndex, textSpans, height, textLeftOffset, textBgRects);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _setSVGTextLineChars: function(lineIndex, textSpans, height, textLeftOffset, textBgRects) {\n\n      var chars = this._textLines[lineIndex],\n          charOffset = 0,\n          lineLeftOffset = this._getLineLeftOffset(this._getLineWidth(this.ctx, lineIndex)) - this.width / 2,\n          lineOffset = this._getSVGLineTopOffset(lineIndex),\n          heightOfLine = this._getHeightOfLine(this.ctx, lineIndex);\n\n      for (var i = 0, len = chars.length; i < len; i++) {\n        var styleDecl = this._getStyleDeclaration(lineIndex, i) || { };\n\n        textSpans.push(\n          this._createTextCharSpan(\n            chars[i], styleDecl, lineLeftOffset, lineOffset.lineTop + lineOffset.offset, charOffset));\n\n        var charWidth = this._getWidthOfChar(this.ctx, chars[i], lineIndex, i);\n\n        if (styleDecl.textBackgroundColor) {\n          textBgRects.push(\n            this._createTextCharBg(\n              styleDecl, lineLeftOffset, lineOffset.lineTop, heightOfLine, charWidth, charOffset));\n        }\n\n        charOffset += charWidth;\n      }\n    },\n\n    /**\n     * @private\n     */\n    _getSVGLineTopOffset: function(lineIndex) {\n      var lineTopOffset = 0, lastHeight = 0;\n      for (var j = 0; j < lineIndex; j++) {\n        lineTopOffset += this._getHeightOfLine(this.ctx, j);\n      }\n      lastHeight = this._getHeightOfLine(this.ctx, j);\n      return {\n        lineTop: lineTopOffset,\n        offset: (this._fontSizeMult - this._fontSizeFraction) * lastHeight / (this.lineHeight * this._fontSizeMult)\n      };\n    },\n\n    /**\n     * @private\n     */\n    _createTextCharBg: function(styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset) {\n      return [\n        '\\t\\t<rect fill=\"', styleDecl.textBackgroundColor,\n        '\" x=\"', toFixed(lineLeftOffset + charOffset, NUM_FRACTION_DIGITS),\n        '\" y=\"', toFixed(lineTopOffset - this.height / 2, NUM_FRACTION_DIGITS),\n        '\" width=\"', toFixed(charWidth, NUM_FRACTION_DIGITS),\n        '\" height=\"', toFixed(heightOfLine / this.lineHeight, NUM_FRACTION_DIGITS),\n        '\"></rect>\\n'\n      ].join('');\n    },\n\n    /**\n     * @private\n     */\n    _createTextCharSpan: function(_char, styleDecl, lineLeftOffset, lineTopOffset, charOffset) {\n\n      var fillStyles = this.getSvgStyles.call(fabric.util.object.extend({\n        visible: true,\n        fill: this.fill,\n        stroke: this.stroke,\n        type: 'text',\n        getSvgFilter: fabric.Object.prototype.getSvgFilter\n      }, styleDecl));\n\n      return [\n        '\\t\\t\\t<tspan x=\"', toFixed(lineLeftOffset + charOffset, NUM_FRACTION_DIGITS), '\" y=\"',\n        toFixed(lineTopOffset - this.height / 2, NUM_FRACTION_DIGITS), '\" ',\n          (styleDecl.fontFamily ? 'font-family=\"' + styleDecl.fontFamily.replace(/\"/g, '\\'') + '\" ' : ''),\n          (styleDecl.fontSize ? 'font-size=\"' + styleDecl.fontSize + '\" ' : ''),\n          (styleDecl.fontStyle ? 'font-style=\"' + styleDecl.fontStyle + '\" ' : ''),\n          (styleDecl.fontWeight ? 'font-weight=\"' + styleDecl.fontWeight + '\" ' : ''),\n          (styleDecl.textDecoration ? 'text-decoration=\"' + styleDecl.textDecoration + '\" ' : ''),\n        'style=\"', fillStyles, '\">',\n        fabric.util.string.escapeXml(_char),\n        '</tspan>\\n'\n      ].join('');\n    },\n  });\n})();\n/* _TO_SVG_END_ */\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = {});\n\n  /**\n   * Textbox class, based on IText, allows the user to resize the text rectangle\n   * and wraps lines automatically. Textboxes have their Y scaling locked, the\n   * user can only change width. Height is adjusted automatically based on the\n   * wrapping of lines.\n   * @class fabric.Textbox\n   * @extends fabric.IText\n   * @mixes fabric.Observable\n   * @return {fabric.Textbox} thisArg\n   * @see {@link fabric.Textbox#initialize} for constructor definition\n   */\n  fabric.Textbox = fabric.util.createClass(fabric.IText, fabric.Observable, {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'textbox',\n\n    /**\n     * Minimum width of textbox, in pixels.\n     * @type Number\n     * @default\n     */\n    minWidth: 20,\n\n    /**\n     * Minimum calculated width of a textbox, in pixels.\n     * fixed to 2 so that an empty textbox cannot go to 0\n     * and is still selectable without text.\n     * @type Number\n     * @default\n     */\n    dynamicMinWidth: 2,\n\n    /**\n     * Cached array of text wrapping.\n     * @type Array\n     */\n    __cachedLines: null,\n\n    /**\n     * Override standard Object class values\n     */\n    lockScalingY: true,\n\n    /**\n     * Override standard Object class values\n     */\n    lockScalingFlip: true,\n\n    /**\n     * Override standard Object class values\n     * Textbox needs this on false\n     */\n    noScaleCache: false,\n\n    /**\n     * Properties which when set cause object to change dimensions\n     * @type Object\n     * @private\n     */\n    _dimensionAffectingProps: fabric.Text.prototype._dimensionAffectingProps.concat('width'),\n\n    /**\n     * Constructor. Some scaling related property values are forced. Visibility\n     * of controls is also fixed; only the rotation and width controls are\n     * made available.\n     * @param {String} text Text string\n     * @param {Object} [options] Options object\n     * @return {fabric.Textbox} thisArg\n     */\n    initialize: function(text, options) {\n\n      this.callSuper('initialize', text, options);\n      this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility());\n      this.ctx = this.objectCaching ? this._cacheContext : fabric.util.createCanvasElement().getContext('2d');\n    },\n\n    /**\n     * Unlike superclass's version of this function, Textbox does not update\n     * its width.\n     * @param {CanvasRenderingContext2D} ctx Context to use for measurements\n     * @private\n     * @override\n     */\n    _initDimensions: function(ctx) {\n      if (this.__skipDimension) {\n        return;\n      }\n\n      if (!ctx) {\n        ctx = fabric.util.createCanvasElement().getContext('2d');\n        this._setTextStyles(ctx);\n        this.clearContextTop();\n      }\n\n      // clear dynamicMinWidth as it will be different after we re-wrap line\n      this.dynamicMinWidth = 0;\n\n      // wrap lines\n      this._textLines = this._splitTextIntoLines(ctx);\n      // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap\n      if (this.dynamicMinWidth > this.width) {\n        this._set('width', this.dynamicMinWidth);\n      }\n\n      // clear cache and re-calculate height\n      this._clearCache();\n      this.height = this._getTextHeight(ctx);\n      this.setCoords();\n    },\n\n    /**\n     * Generate an object that translates the style object so that it is\n     * broken up by visual lines (new lines and automatic wrapping).\n     * The original text styles object is broken up by actual lines (new lines only),\n     * which is only sufficient for Text / IText\n     * @private\n     */\n    _generateStyleMap: function() {\n      var realLineCount     = 0,\n          realLineCharCount = 0,\n          charCount         = 0,\n          map               = {};\n\n      for (var i = 0; i < this._textLines.length; i++) {\n        if (this.text[charCount] === '\\n' && i > 0) {\n          realLineCharCount = 0;\n          charCount++;\n          realLineCount++;\n        }\n        else if (this.text[charCount] === ' ' && i > 0) {\n          // this case deals with space's that are removed from end of lines when wrapping\n          realLineCharCount++;\n          charCount++;\n        }\n\n        map[i] = { line: realLineCount, offset: realLineCharCount };\n\n        charCount += this._textLines[i].length;\n        realLineCharCount += this._textLines[i].length;\n      }\n\n      return map;\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @param {Boolean} [returnCloneOrEmpty=false]\n     * @private\n     */\n    _getStyleDeclaration: function(lineIndex, charIndex, returnCloneOrEmpty) {\n      if (this._styleMap) {\n        var map = this._styleMap[lineIndex];\n        if (!map) {\n          return returnCloneOrEmpty ? { } : null;\n        }\n        lineIndex = map.line;\n        charIndex = map.offset + charIndex;\n      }\n      return this.callSuper('_getStyleDeclaration', lineIndex, charIndex, returnCloneOrEmpty);\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @param {Object} style\n     * @private\n     */\n    _setStyleDeclaration: function(lineIndex, charIndex, style) {\n      var map = this._styleMap[lineIndex];\n      lineIndex = map.line;\n      charIndex = map.offset + charIndex;\n\n      this.styles[lineIndex][charIndex] = style;\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @private\n     */\n    _deleteStyleDeclaration: function(lineIndex, charIndex) {\n      var map = this._styleMap[lineIndex];\n      lineIndex = map.line;\n      charIndex = map.offset + charIndex;\n\n      delete this.styles[lineIndex][charIndex];\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @private\n     */\n    _getLineStyle: function(lineIndex) {\n      var map = this._styleMap[lineIndex];\n      return this.styles[map.line];\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Object} style\n     * @private\n     */\n    _setLineStyle: function(lineIndex, style) {\n      var map = this._styleMap[lineIndex];\n      this.styles[map.line] = style;\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @private\n     */\n    _deleteLineStyle: function(lineIndex) {\n      var map = this._styleMap[lineIndex];\n      delete this.styles[map.line];\n    },\n\n    /**\n     * Wraps text using the 'width' property of Textbox. First this function\n     * splits text on newlines, so we preserve newlines entered by the user.\n     * Then it wraps each line using the width of the Textbox by calling\n     * _wrapLine().\n     * @param {CanvasRenderingContext2D} ctx Context to use for measurements\n     * @param {String} text The string of text that is split into lines\n     * @returns {Array} Array of lines\n     */\n    _wrapText: function(ctx, text) {\n      var lines = text.split(this._reNewline), wrapped = [], i;\n\n      for (i = 0; i < lines.length; i++) {\n        wrapped = wrapped.concat(this._wrapLine(ctx, lines[i], i));\n      }\n\n      return wrapped;\n    },\n\n    /**\n     * Helper function to measure a string of text, given its lineIndex and charIndex offset\n     *\n     * @param {CanvasRenderingContext2D} ctx\n     * @param {String} text\n     * @param {number} lineIndex\n     * @param {number} charOffset\n     * @returns {number}\n     * @private\n     */\n    _measureText: function(ctx, text, lineIndex, charOffset) {\n      var width = 0;\n      charOffset = charOffset || 0;\n      for (var i = 0, len = text.length; i < len; i++) {\n        width += this._getWidthOfChar(ctx, text[i], lineIndex, i + charOffset);\n      }\n      return width;\n    },\n\n    /**\n     * Wraps a line of text using the width of the Textbox and a context.\n     * @param {CanvasRenderingContext2D} ctx Context to use for measurements\n     * @param {String} text The string of text to split into lines\n     * @param {Number} lineIndex\n     * @returns {Array} Array of line(s) into which the given text is wrapped\n     * to.\n     */\n    _wrapLine: function(ctx, text, lineIndex) {\n      var lineWidth        = 0,\n          lines            = [],\n          line             = '',\n          words            = text.split(' '),\n          word             = '',\n          offset           = 0,\n          infix            = ' ',\n          wordWidth        = 0,\n          infixWidth       = 0,\n          largestWordWidth = 0,\n          lineJustStarted = true,\n          additionalSpace = this._getWidthOfCharSpacing();\n\n      for (var i = 0; i < words.length; i++) {\n        word = words[i];\n        wordWidth = this._measureText(ctx, word, lineIndex, offset);\n\n        offset += word.length;\n\n        lineWidth += infixWidth + wordWidth - additionalSpace;\n\n        if (lineWidth >= this.width && !lineJustStarted) {\n          lines.push(line);\n          line = '';\n          lineWidth = wordWidth;\n          lineJustStarted = true;\n        }\n        else {\n          lineWidth += additionalSpace;\n        }\n\n        if (!lineJustStarted) {\n          line += infix;\n        }\n        line += word;\n\n        infixWidth = this._measureText(ctx, infix, lineIndex, offset);\n        offset++;\n        lineJustStarted = false;\n        // keep track of largest word\n        if (wordWidth > largestWordWidth) {\n          largestWordWidth = wordWidth;\n        }\n      }\n\n      i && lines.push(line);\n\n      if (largestWordWidth > this.dynamicMinWidth) {\n        this.dynamicMinWidth = largestWordWidth - additionalSpace;\n      }\n\n      return lines;\n    },\n    /**\n     * Gets lines of text to render in the Textbox. This function calculates\n     * text wrapping on the fly everytime it is called.\n     * @returns {Array} Array of lines in the Textbox.\n     * @override\n     */\n    _splitTextIntoLines: function(ctx) {\n      ctx = ctx || this.ctx;\n      var originalAlign = this.textAlign;\n      this._styleMap = null;\n      ctx.save();\n      this._setTextStyles(ctx);\n      this.textAlign = 'left';\n      var lines = this._wrapText(ctx, this.text);\n      this.textAlign = originalAlign;\n      ctx.restore();\n      this._textLines = lines;\n      this._styleMap = this._generateStyleMap();\n      return lines;\n    },\n\n    /**\n     * When part of a group, we don't want the Textbox's scale to increase if\n     * the group's increases. That's why we reduce the scale of the Textbox by\n     * the amount that the group's increases. This is to maintain the effective\n     * scale of the Textbox at 1, so that font-size values make sense. Otherwise\n     * the same font-size value would result in different actual size depending\n     * on the value of the scale.\n     * @param {String} key\n     * @param {*} value\n     */\n    setOnGroup: function(key, value) {\n      if (key === 'scaleX') {\n        this.set('scaleX', Math.abs(1 / value));\n        this.set('width', (this.get('width') * value) /\n          (typeof this.__oldScaleX === 'undefined' ? 1 : this.__oldScaleX));\n        this.__oldScaleX = value;\n      }\n    },\n\n    /**\n     * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start).\n     * Overrides the superclass function to take into account text wrapping.\n     *\n     * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.\n     */\n    get2DCursorLocation: function(selectionStart) {\n      if (typeof selectionStart === 'undefined') {\n        selectionStart = this.selectionStart;\n      }\n\n      var numLines = this._textLines.length,\n          removed  = 0;\n\n      for (var i = 0; i < numLines; i++) {\n        var line    = this._textLines[i],\n            lineLen = line.length;\n\n        if (selectionStart <= removed + lineLen) {\n          return {\n            lineIndex: i,\n            charIndex: selectionStart - removed\n          };\n        }\n\n        removed += lineLen;\n\n        if (this.text[removed] === '\\n' || this.text[removed] === ' ') {\n          removed++;\n        }\n      }\n\n      return {\n        lineIndex: numLines - 1,\n        charIndex: this._textLines[numLines - 1].length\n      };\n    },\n\n    /**\n     * Overrides superclass function and uses text wrapping data to get cursor\n     * boundary offsets instead of the array of chars.\n     * @param {Array} chars Unused\n     * @param {String} typeOfBoundaries Can be 'cursor' or 'selection'\n     * @returns {Object} Object with 'top', 'left', and 'lineLeft' properties set.\n     */\n    _getCursorBoundariesOffsets: function(chars, typeOfBoundaries) {\n      var topOffset      = 0,\n          leftOffset     = 0,\n          cursorLocation = this.get2DCursorLocation(),\n          lineChars      = this._textLines[cursorLocation.lineIndex].split(''),\n          lineLeftOffset = this._getLineLeftOffset(this._getLineWidth(this.ctx, cursorLocation.lineIndex));\n\n      for (var i = 0; i < cursorLocation.charIndex; i++) {\n        leftOffset += this._getWidthOfChar(this.ctx, lineChars[i], cursorLocation.lineIndex, i);\n      }\n\n      for (i = 0; i < cursorLocation.lineIndex; i++) {\n        topOffset += this._getHeightOfLine(this.ctx, i);\n      }\n\n      if (typeOfBoundaries === 'cursor') {\n        topOffset += (1 - this._fontSizeFraction) * this._getHeightOfLine(this.ctx, cursorLocation.lineIndex)\n          / this.lineHeight - this.getCurrentCharFontSize(cursorLocation.lineIndex, cursorLocation.charIndex)\n          * (1 - this._fontSizeFraction);\n      }\n\n      return {\n        top: topOffset,\n        left: leftOffset,\n        lineLeft: lineLeftOffset\n      };\n    },\n\n    getMinWidth: function() {\n      return Math.max(this.minWidth, this.dynamicMinWidth);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @method toObject\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return this.callSuper('toObject', ['minWidth'].concat(propertiesToInclude));\n    }\n  });\n\n  /**\n   * Returns fabric.Textbox instance from an object representation\n   * @static\n   * @memberOf fabric.Textbox\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Textbox instance is created\n   * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first\n   * @return {fabric.Textbox} instance of fabric.Textbox\n   */\n  fabric.Textbox.fromObject = function(object, callback, forceAsync) {\n    return fabric.Object._fromObject('Textbox', object, callback, forceAsync, 'text');\n  };\n\n  /**\n   * Returns the default controls visibility required for Textboxes.\n   * @returns {Object}\n   */\n  fabric.Textbox.getTextboxControlVisibility = function() {\n    return {\n      tl: false,\n      tr: false,\n      br: false,\n      bl: false,\n      ml: true,\n      mt: false,\n      mr: true,\n      mb: false,\n      mtr: true\n    };\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n  /**\n   * Override _setObjectScale and add Textbox specific resizing behavior. Resizing\n   * a Textbox doesn't scale text, it only changes width and makes text wrap automatically.\n   */\n  var setObjectScaleOverridden = fabric.Canvas.prototype._setObjectScale;\n\n  fabric.Canvas.prototype._setObjectScale = function(localMouse, transform,\n                                                     lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {\n\n    var t = transform.target;\n    if (t instanceof fabric.Textbox) {\n      var w = t.width * ((localMouse.x / transform.scaleX) / (t.width + t.strokeWidth));\n      if (w >= t.getMinWidth()) {\n        t.set('width', w);\n        return true;\n      }\n    }\n    else {\n      return setObjectScaleOverridden.call(fabric.Canvas.prototype, localMouse, transform,\n        lockScalingX, lockScalingY, by, lockScalingFlip, _dim);\n    }\n  };\n\n  /**\n   * Sets controls of this group to the Textbox's special configuration if\n   * one is present in the group. Deletes _controlsVisibility otherwise, so that\n   * it gets initialized to default value at runtime.\n   */\n  fabric.Group.prototype._refreshControlsVisibility = function() {\n    if (typeof fabric.Textbox === 'undefined') {\n      return;\n    }\n    for (var i = this._objects.length; i--;) {\n      if (this._objects[i] instanceof fabric.Textbox) {\n        this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility());\n        return;\n      }\n    }\n  };\n\n  fabric.util.object.extend(fabric.Textbox.prototype, /** @lends fabric.IText.prototype */ {\n    /**\n     * @private\n     */\n    _removeExtraneousStyles: function() {\n      for (var prop in this._styleMap) {\n        if (!this._textLines[prop]) {\n          delete this.styles[this._styleMap[prop].line];\n        }\n      }\n    },\n\n    /**\n     * Inserts style object for a given line/char index\n     * @param {Number} lineIndex Index of a line\n     * @param {Number} charIndex Index of a char\n     * @param {Object} [style] Style object to insert, if given\n     */\n    insertCharStyleObject: function(lineIndex, charIndex, style) {\n      // adjust lineIndex and charIndex\n      var map = this._styleMap[lineIndex];\n      lineIndex = map.line;\n      charIndex = map.offset + charIndex;\n\n      fabric.IText.prototype.insertCharStyleObject.apply(this, [lineIndex, charIndex, style]);\n    },\n\n    /**\n     * Inserts new style object\n     * @param {Number} lineIndex Index of a line\n     * @param {Number} charIndex Index of a char\n     * @param {Boolean} isEndOfLine True if it's end of line\n     */\n    insertNewlineStyleObject: function(lineIndex, charIndex, isEndOfLine) {\n      // adjust lineIndex and charIndex\n      var map = this._styleMap[lineIndex];\n      lineIndex = map.line;\n      charIndex = map.offset + charIndex;\n\n      fabric.IText.prototype.insertNewlineStyleObject.apply(this, [lineIndex, charIndex, isEndOfLine]);\n    },\n\n    /**\n     * Shifts line styles up or down. This function is slightly different than the one in\n     * itext_behaviour as it takes into account the styleMap.\n     *\n     * @param {Number} lineIndex Index of a line\n     * @param {Number} offset Can be -1 or +1\n     */\n    shiftLineStyles: function(lineIndex, offset) {\n      // shift all line styles by 1 upward\n      var map = this._styleMap[lineIndex];\n      // adjust line index\n      lineIndex = map.line;\n      fabric.IText.prototype.shiftLineStyles.call(this, lineIndex, offset);\n    },\n\n    /**\n     * Figure out programatically the text on previous actual line (actual = separated by \\n);\n     *\n     * @param {Number} lIndex\n     * @returns {String}\n     * @private\n     */\n    _getTextOnPreviousLine: function(lIndex) {\n      var textOnPreviousLine = this._textLines[lIndex - 1];\n\n      while (this._styleMap[lIndex - 2] && this._styleMap[lIndex - 2].line === this._styleMap[lIndex - 1].line) {\n        textOnPreviousLine = this._textLines[lIndex - 2] + textOnPreviousLine;\n\n        lIndex--;\n      }\n\n      return textOnPreviousLine;\n    },\n\n    /**\n     * Removes style object\n     * @param {Boolean} isBeginningOfLine True if cursor is at the beginning of line\n     * @param {Number} [index] Optional index. When not given, current selectionStart is used.\n     */\n    removeStyleObject: function(isBeginningOfLine, index) {\n\n      var cursorLocation = this.get2DCursorLocation(index),\n          map            = this._styleMap[cursorLocation.lineIndex],\n          lineIndex      = map.line,\n          charIndex      = map.offset + cursorLocation.charIndex;\n      this._removeStyleObject(isBeginningOfLine, cursorLocation, lineIndex, charIndex);\n    }\n  });\n})();\n\n\n(function() {\n  var override = fabric.IText.prototype._getNewSelectionStartFromOffset;\n  /**\n   * Overrides the IText implementation and adjusts character index as there is not always a linebreak\n   *\n   * @param {Number} mouseOffset\n   * @param {Number} prevWidth\n   * @param {Number} width\n   * @param {Number} index\n   * @param {Number} jlen\n   * @returns {Number}\n   */\n  fabric.IText.prototype._getNewSelectionStartFromOffset = function(mouseOffset, prevWidth, width, index, jlen) {\n    index = override.call(this, mouseOffset, prevWidth, width, index, jlen);\n\n    // the index passed into the function is padded by the amount of lines from _textLines (to account for \\n)\n    // we need to remove this padding, and pad it by actual lines, and / or spaces that are meant to be there\n    var tmp     = 0,\n        removed = 0;\n\n    // account for removed characters\n    for (var i = 0; i < this._textLines.length; i++) {\n      tmp += this._textLines[i].length;\n\n      if (tmp + removed >= index) {\n        break;\n      }\n\n      if (this.text[tmp + removed] === '\\n' || this.text[tmp + removed] === ' ') {\n        removed++;\n      }\n    }\n\n    return index - i + removed;\n  };\n})();\n\n\n(function() {\n\n  if (typeof document !== 'undefined' && typeof window !== 'undefined') {\n    return;\n  }\n\n  var DOMParser = require('xmldom').DOMParser,\n      URL = require('url'),\n      HTTP = require('http'),\n      HTTPS = require('https'),\n\n      Canvas = require('canvas'),\n      Image = require('canvas').Image;\n\n  /** @private */\n  function request(url, encoding, callback) {\n    var oURL = URL.parse(url);\n\n    // detect if http or https is used\n    if ( !oURL.port ) {\n      oURL.port = ( oURL.protocol.indexOf('https:') === 0 ) ? 443 : 80;\n    }\n\n    // assign request handler based on protocol\n    var reqHandler = (oURL.protocol.indexOf('https:') === 0 ) ? HTTPS : HTTP,\n        req = reqHandler.request({\n          hostname: oURL.hostname,\n          port: oURL.port,\n          path: oURL.path,\n          method: 'GET'\n        }, function(response) {\n          var body = '';\n          if (encoding) {\n            response.setEncoding(encoding);\n          }\n          response.on('end', function () {\n            callback(body);\n          });\n          response.on('data', function (chunk) {\n            if (response.statusCode === 200) {\n              body += chunk;\n            }\n          });\n        });\n\n    req.on('error', function(err) {\n      if (err.errno === process.ECONNREFUSED) {\n        fabric.log('ECONNREFUSED: connection refused to ' + oURL.hostname + ':' + oURL.port);\n      }\n      else {\n        fabric.log(err.message);\n      }\n      callback(null);\n    });\n\n    req.end();\n  }\n\n  /** @private */\n  function requestFs(path, callback) {\n    var fs = require('fs');\n    fs.readFile(path, function (err, data) {\n      if (err) {\n        fabric.log(err);\n        throw err;\n      }\n      else {\n        callback(data);\n      }\n    });\n  }\n\n  fabric.util.loadImage = function(url, callback, context) {\n    function createImageAndCallBack(data) {\n      if (data) {\n        img.src = new Buffer(data, 'binary');\n        // preserving original url, which seems to be lost in node-canvas\n        img._src = url;\n        callback && callback.call(context, img);\n      }\n      else {\n        img = null;\n        callback && callback.call(context, null, true);\n      }\n    }\n    var img = new Image();\n    if (url && (url instanceof Buffer || url.indexOf('data') === 0)) {\n      img.src = img._src = url;\n      callback && callback.call(context, img);\n    }\n    else if (url && url.indexOf('http') !== 0) {\n      requestFs(url, createImageAndCallBack);\n    }\n    else if (url) {\n      request(url, 'binary', createImageAndCallBack);\n    }\n    else {\n      callback && callback.call(context, url);\n    }\n  };\n\n  fabric.loadSVGFromURL = function(url, callback, reviver) {\n    url = url.replace(/^\\n\\s*/, '').replace(/\\?.*$/, '').trim();\n    if (url.indexOf('http') !== 0) {\n      requestFs(url, function(body) {\n        fabric.loadSVGFromString(body.toString(), callback, reviver);\n      });\n    }\n    else {\n      request(url, '', function(body) {\n        fabric.loadSVGFromString(body, callback, reviver);\n      });\n    }\n  };\n\n  fabric.loadSVGFromString = function(string, callback, reviver) {\n    var doc = new DOMParser().parseFromString(string);\n    fabric.parseSVGDocument(doc.documentElement, function(results, options) {\n      callback && callback(results, options);\n    }, reviver);\n  };\n\n  fabric.util.getScript = function(url, callback) {\n    request(url, '', function(body) {\n      // eslint-disable-next-line no-eval\n      eval(body);\n      callback && callback();\n    });\n  };\n\n  // fabric.util.createCanvasElement = function(_, width, height) {\n  //   return new Canvas(width, height);\n  // }\n\n  /**\n   * Only available when running fabric on node.js\n   * @param {Number} width Canvas width\n   * @param {Number} height Canvas height\n   * @param {Object} [options] Options to pass to FabricCanvas.\n   * @param {Object} [nodeCanvasOptions] Options to pass to NodeCanvas.\n   * @return {Object} wrapped canvas instance\n   */\n  fabric.createCanvasForNode = function(width, height, options, nodeCanvasOptions) {\n    nodeCanvasOptions = nodeCanvasOptions || options;\n\n    var canvasEl = fabric.document.createElement('canvas'),\n        nodeCanvas = new Canvas(width || 600, height || 600, nodeCanvasOptions),\n        nodeCacheCanvas = new Canvas(width || 600, height || 600, nodeCanvasOptions);\n\n    // jsdom doesn't create style on canvas element, so here be temp. workaround\n    canvasEl.style = { };\n\n    canvasEl.width = nodeCanvas.width;\n    canvasEl.height = nodeCanvas.height;\n    options = options || { };\n    options.nodeCanvas = nodeCanvas;\n    options.nodeCacheCanvas = nodeCacheCanvas;\n    var FabricCanvas = fabric.Canvas || fabric.StaticCanvas,\n        fabricCanvas = new FabricCanvas(canvasEl, options);\n    fabricCanvas.nodeCanvas = nodeCanvas;\n    fabricCanvas.nodeCacheCanvas = nodeCacheCanvas;\n    fabricCanvas.contextContainer = nodeCanvas.getContext('2d');\n    fabricCanvas.contextCache = nodeCacheCanvas.getContext('2d');\n    fabricCanvas.Font = Canvas.Font;\n    return fabricCanvas;\n  };\n\n  var originaInitStatic = fabric.StaticCanvas.prototype._initStatic;\n  fabric.StaticCanvas.prototype._initStatic = function(el, options) {\n    el = el || fabric.document.createElement('canvas');\n    this.nodeCanvas = new Canvas(el.width, el.height);\n    this.nodeCacheCanvas = new Canvas(el.width, el.height);\n    originaInitStatic.call(this, el, options);\n    this.contextContainer = this.nodeCanvas.getContext('2d');\n    this.contextCache = this.nodeCacheCanvas.getContext('2d');\n    this.Font = Canvas.Font;\n  };\n\n  /** @ignore */\n  fabric.StaticCanvas.prototype.createPNGStream = function() {\n    return this.nodeCanvas.createPNGStream();\n  };\n\n  fabric.StaticCanvas.prototype.createJPEGStream = function(opts) {\n    return this.nodeCanvas.createJPEGStream(opts);\n  };\n\n  fabric.StaticCanvas.prototype._initRetinaScaling = function() {\n    if (!this._isRetinaScaling()) {\n      return;\n    }\n\n    this.lowerCanvasEl.setAttribute('width', this.width * fabric.devicePixelRatio);\n    this.lowerCanvasEl.setAttribute('height', this.height * fabric.devicePixelRatio);\n    this.nodeCanvas.width = this.width * fabric.devicePixelRatio;\n    this.nodeCanvas.height = this.height * fabric.devicePixelRatio;\n    this.contextContainer.scale(fabric.devicePixelRatio, fabric.devicePixelRatio);\n    return this;\n  };\n  if (fabric.Canvas) {\n    fabric.Canvas.prototype._initRetinaScaling = fabric.StaticCanvas.prototype._initRetinaScaling;\n  }\n\n  var origSetBackstoreDimension = fabric.StaticCanvas.prototype._setBackstoreDimension;\n  fabric.StaticCanvas.prototype._setBackstoreDimension = function(prop, value) {\n    origSetBackstoreDimension.call(this, prop, value);\n    this.nodeCanvas[prop] = value;\n    return this;\n  };\n  if (fabric.Canvas) {\n    fabric.Canvas.prototype._setBackstoreDimension = fabric.StaticCanvas.prototype._setBackstoreDimension;\n  }\n\n})();\n\n"]}