MOON
Server: Apache
System: Linux res.emeff.ca 3.10.0-962.3.2.lve1.5.24.10.el7.x86_64 #1 SMP Wed Mar 20 07:36:02 EDT 2019 x86_64
User: accemeff (1004)
PHP: 7.0.33
Disabled: NONE
Upload Files
File: /home/accemeff/vendor/craftcms/cms/lib/fabric/fabric.js.map
{"version":3,"sources":["fabric.js"],"names":["fabric","version","exports","document","window","require","jsdom","decodeURIComponent","createWindow","parentWindow","isTouchSupported","isLikelyNode","Buffer","SHARED_ATTRIBUTES","DPI","reNum","fontPaths","iMatrix","canvasModule","perfLimitSizeTotal","maxCacheSideLimit","minCacheSideLimit","charWidthsCache","devicePixelRatio","webkitDevicePixelRatio","mozDevicePixelRatio","_removeEventListener","eventName","handler","this","__eventListeners","eventListener","indexOf","util","array","fill","observe","arguments","length","prop","on","push","stopObserving","call","fire","options","listenersForEvent","i","len","filter","value","Observable","off","trigger","Collection","_objects","add","apply","_onObjectAdded","renderOnAddRemove","renderAll","insertAt","object","index","nonSplicing","objects","getObjects","splice","remove","somethingRemoved","_onObjectRemoved","forEachObject","callback","context","type","o","item","isEmpty","size","contains","complexity","reduce","memo","current","CommonMethods","_setOptions","set","_initGradient","filler","property","colorStops","Gradient","_initPattern","source","Pattern","_initClipping","clipTo","functionBody","getFunctionBody","Function","_setObject","obj","_set","key","get","toggle","global","sqrt","Math","atan2","pow","abs","PiBy180","PI","removeFromArray","idx","getRandomInt","min","max","floor","random","degreesToRadians","degrees","radiansToDegrees","radians","rotatePoint","point","origin","subtractEquals","v","rotateVector","Point","x","y","addEquals","vector","sin","cos","transformPoint","p","t","ignoreOffset","makeBoundingBoxFromPoints","points","xPoints","minX","maxX","width","yPoints","minY","maxY","left","top","height","invertTransform","a","r","toFixed","number","fractionDigits","parseFloat","Number","parseUnit","fontSize","unit","exec","Text","DEFAULT_SVG_FONT_SIZE","falseFunction","getKlass","namespace","string","camelize","charAt","toUpperCase","slice","resolveNamespace","parts","split","loadImage","url","crossOrigin","img","createImage","onload","onerror","log","src","enlivenObjects","reviver","onLoaded","numLoadedObjects","numTotalObjects","enlivenedObjects","forEach","fromObject","error","enlivenPatterns","patterns","numLoadedPatterns","numPatterns","enlivenedPatterns","pattern","groupSVGElements","elements","path","PathGroup","sourcePath","populateWithProperties","destination","properties","Object","prototype","toString","drawDashedLine","ctx","x2","y2","da","dx","dy","rot","dc","di","draw","save","translate","moveTo","rotate","restore","createCanvasElement","canvasEl","createElement","getContext","G_vmlCanvasManager","initElement","createAccessors","klass","propName","capitalizedPropName","setterName","getterName","proto","stateProperties","clipContext","receiver","beginPath","clip","multiplyTransformMatrices","b","is2x2","qrDecompose","angle","denom","scaleX","scaleY","skewX","skewY","translateX","translateY","customTransformMatrix","skewMatrixX","tan","scaleMatrix","resetObjectTransform","target","flipX","flipY","setAngle","fn","String","match","isTransparent","tolerance","_isTransparent","imageData","getImageData","l","data","parsePreserveAspectRatioAttribute","attribute","align","meetOrSlice","aspectRatioAttrs","pop","alignX","alignY","clearFabricFontCache","fontFamily","limitDimsByArea","ar","maximumArea","roughWidth","perfLimitSizeY","capValue","arcToSegmentsCache","segmentToBezierCache","boundsOfCurveCache","_join","Array","join","arcToSegments","toX","toY","rx","ry","large","sweep","rotateX","argsString","th","sinTh","cosTh","fromX","fromY","px","py","rx2","ry2","py2","px2","pl","root","s","cx","cy","cx1","cy1","mTheta","calcVectorAngle","dtheta","segments","ceil","result","mDelta","mT","th3","segmentToBezier","th2","argsString2","costh2","sinth2","costh3","sinth3","cp1X","cp1Y","cp2X","cp2Y","ux","uy","vx","vy","ta","tb","getBoundsOfCurve","x0","y0","x1","y1","x3","y3","c","t1","t2","b2ac","sqrtb2ac","tvalues","bounds","mt","j","jlen","drawArc","fx","fy","coords","segs","segsNorm","bezierCurveTo","getBoundsOfArc","tx","ty","bound","find","byProperty","condition","searchElement","TypeError","n","POSITIVE_INFINITY","NEGATIVE_INFINITY","k","map","every","some","val","rv","invoke","method","args","value1","value2","extend","deep","Element","hasOwnProperty","clone","trim","replace","character","capitalize","firstLetterOnly","toLowerCase","escapeXml","Dummy","bind","thisArg","_this","concat","emptyFunction","IS_DONTENUM_BUGGY","addMethods","parent","superclass","constructor","returnValue","valueOf","Subclass","callSuper","methodName","parentMethod","superClassMethod","console","createClass","initialize","shift","subclasses","unknown","areHostMethods","methodNames","test","getElement","setElement","uid","getUniqueId","element","__uniqueID","createListener","wrappedHandler","e","event","addListener","removeListener","shouldUseAddListenerRemoveListener","documentElement","shouldUseAttachEventDetachEvent","listeners","handlers","addEventListener","removeEventListener","listener","attachEvent","detachEvent","existingHandler","handlersForEvent","pointerX","clientX","pointerY","clientY","_getPointer","pageProp","clientProp","touchProp","getPointer","srcElement","scroll","getScrollLeftTop","parseEl","supportsOpacity","style","opacity","supportsFilters","reOpacity","setOpacity","es","currentStyle","hasLayout","zoom","setStyle","styles","elementStyle","cssText","styleFloat","_slice","sliceCanConvertNodelists","getElementStyle","selectProp","toArray","arrayLike","childNodes","err","makeElement","tagName","attributes","el","className","htmlFor","setAttribute","docElement","body","scrollLeft","scrollTop","parentNode","host","nodeType","arr","defaultView","getComputedStyle","attr","undefined","makeElementUnselectable","onselectstart","unselectable","makeElementSelectable","getScript","headEl","getElementsByTagName","scriptEl","loading","onreadystatechange","readyState","appendChild","getById","id","getElementById","addClass","wrapElement","wrapper","replaceChild","getElementOffset","docElem","scrollLeftTop","doc","ownerDocument","box","offset","offsetAttributes","borderLeftWidth","borderTopWidth","paddingLeft","paddingTop","parseInt","getBoundingClientRect","clientLeft","clientTop","makeXHR","factories","ActiveXObject","XMLHttpRequest","emptyFn","request","param","onComplete","xhr","parameters","open","setRequestHeader","send","warn","noop","_requestAnimFrame","requestAnimationFrame","webkitRequestAnimationFrame","mozRequestAnimationFrame","oRequestAnimationFrame","msRequestAnimationFrame","setTimeout","requestAnimFrame","animate","timestamp","time","start","Date","duration","finish","onChange","abort","easing","d","startValue","endValue","byValue","onStart","tick","ticktime","currentTime","timePerc","valuePerc","animateColor","fromColor","toColor","startColor","Color","getSource","endColor","begin","end","pos","color","posValue","colorEasing","normalize","asin","elastic","opts","easeInBounce","easeOutBounce","ease","easeInQuad","easeOutQuad","easeInOutQuad","easeInCubic","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","easeInSine","easeOutSine","easeInOutSine","easeInExpo","easeOutExpo","easeInOutExpo","easeInCirc","easeOutCirc","easeInOutCirc","easeInElastic","easeOutElastic","easeInOutElastic","easeInBack","easeOutBack","easeInOutBack","easeInOutBounce","reAllowedSVGTagNames","reViewBoxTagNames","reNotAllowedAncestors","reAllowedParents","attributesMap","display","visibility","transform","fill-opacity","fill-rule","font-family","font-size","font-style","font-weight","stroke-dasharray","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-decoration","text-anchor","colorAttributes","stroke","_getMultipleNodes","nodeNames","nodeName","nodeList","nodeArray","elementMatchesRule","selectors","firstMatching","parentMatching","selectorMatches","selector","doesSomeParentMatch","matcher","classNames","getAttribute","RegExp","elementById","node","nodelist","cssRules","gradientDefs","parseTransformAttribute","skewMatrix","matrix","commaWsp","reTransformList","reTransform","attributeValue","matrices","multiplierX","multiplierY","m","operation","combinedMatrix","reViewBoxAttrValue","applyViewboxTransform","viewBoxWidth","viewBoxHeight","viewBoxAttr","widthAttr","heightAttr","preserveAspectRatio","missingViewBox","missingDimAttr","toBeParsed","parsedDim","translateMatrix","firstChild","parseSVGDocument","parsingOptions","attrs","xlink","substr","el2","cloneNode","currentTrans","oldLength","el3","nodeValue","removeAttribute","parseUseDirectives","svgUid","__uid","descendants","selectNodes","hasAncestorWithNodeName","getGradientDefs","getCSSRules","parseElements","instances","reFontDeclaration","parseFontDeclaration","oStyle","fontStyle","fontWeight","lineHeight","isNaN","elList","idsToXlinkMap","parseAttributes","parentAttributes","ownAttributes","rule","getGlobalStylesForElement","parseStyleAttribute","normalizedAttr","normalizedValue","parsed","isArray","normalizedStyle","transformMatrix","visible","font","mergedAttrs","setAlpha","getAlpha","toRgba","_setStrokeFillOpacity","ElementsParser","parse","chunk","pair","parseStyleObject","parsePointsAttribute","parsedPoints","allRules","styleContents","textContent","text","ruleObj","propertyValuePairs","_rule","loadSVGFromURL","xml","responseXML","responseText","async","loadXML","results","_options","loadSVGFromString","DOMParser","parser","parseFromString","numElements","createObjects","_obj","createObject","fromElement","_createObject","checkIfDone","createCallback","resolveGradient","instanceFillValue","gradientId","that","scalarAdd","scalar","scalarAddEquals","subtract","scalarSubtract","scalarSubtractEquals","multiply","multiplyEquals","divide","divideEquals","eq","lt","lte","gt","gte","lerp","distanceFrom","midPointFrom","setXY","setX","setY","setFromPoint","swap","Intersection","status","appendPoint","appendPoints","intersectLineLine","a1","a2","b1","b2","uaT","ubT","uB","ua","ub","intersectLinePolygon","inter","intersectPolygonPolygon","points1","points2","intersectPolygonRectangle","r1","r2","topRight","bottomLeft","inter1","inter2","inter3","inter4","_tryParsingColor","setSource","hue2rgb","q","colorNameMap","sourceFromHex","sourceFromRgb","sourceFromHsl","_rgbToHsl","g","h","round","_source","toRgb","toHsl","hsl","toHsla","toHex","toHexa","alpha","toGrayscale","average","currentAlpha","toBlackWhite","threshold","overlayWith","otherColor","otherSource","reRGBa","reHSLa","reHex","aqua","black","blue","fuchsia","gray","grey","green","lime","maroon","navy","olive","orange","purple","red","silver","teal","white","yellow","fromRgb","fromSource","fromRgba","fromHsl","fromHsla","fromHex","isShortNotation","isRGBa","substring","oColor","getColorStop","colorAlpha","keyValuePairs","_convertPercentUnitsToValues","gradientUnits","propValue","addFactor","multFactor","ellipseMatrix","scaleFactor","offsetX","offsetY","gradientTransform","addColorStop","position","toObject","propertiesToInclude","toSVG","markup","commonAttributes","needsSwap","sort","group","reverse","minRadius","percentageShift","colorStop","toLive","gradient","createLinearGradient","createRadialGradient","instance","colorStopEls","forObject","repeat","setOptions","NUM_FRACTION_DIGITS","toDataURL","patternSource","patternWidth","patternHeight","patternOffsetX","patternOffsetY","patternImgSrc","complete","naturalWidth","naturalHeight","createPattern","Shadow","blur","affectStroke","includeDefaultValues","_parseShadow","shadow","shadowStr","offsetsAndBlur","reOffsetsAndBlur","fBoxX","fBoxY","StaticCanvas","CANVAS_INIT_ERROR","Error","_initStatic","backgroundColor","backgroundImage","overlayColor","overlayImage","stateful","controlsAboveOverlay","allowTouchScrolling","imageSmoothingEnabled","viewportTransform","backgroundVpt","overlayVpt","onBeforeScaleRotate","enableRetinaScaling","vptCoords","skipOffscreen","cb","_createLowerCanvas","_initOptions","_setImageSmoothing","interactive","_initRetinaScaling","setOverlayImage","setBackgroundImage","setBackgroundColor","setOverlayColor","calcOffset","_isRetinaScaling","getRetinaScaling","lowerCanvasEl","contextContainer","scale","_offset","image","__setBgOverlayImage","__setBgOverlayColor","webkitImageSmoothingEnabled","mozImageSmoothingEnabled","msImageSmoothingEnabled","oImageSmoothingEnabled","Image","_createCanvasElement","_applyCanvasStyle","getWidth","getHeight","setWidth","setDimensions","setHeight","dimensions","cssValue","cssOnly","_setBackstoreDimension","backstoreOnly","_setCssDimension","upperCanvasEl","cacheCanvasEl","wrapperEl","getZoom","setViewportTransform","vpt","activeGroup","_activeGroup","setCoords","calcViewportBoundaries","zoomToPoint","before","after","setZoom","absolutePan","relativePan","setupState","canvas","clearContext","clearRect","clear","_hasITextHandlers","_mouseUpITextHandler","_iTextInstances","canvasToDrawOn","renderCanvas","iVpt","tl","br","tr","bl","_renderBackground","_renderObjects","drawControls","_renderOverlay","render","_renderBackgroundOrOverlay","fillStyle","fillRect","getCenter","centerObjectH","_centerObject","getCenterPoint","centerObjectV","centerObject","center","viewportCenterObject","vpCenter","getVpCenter","viewportCenterObjectH","viewportCenterObjectV","setPositionByOrigin","toDatalessJSON","toDatalessObject","_toObjectMethod","_toObjects","__serializeBgOverlay","excludeFromExport","_toObject","originalValue","bgImage","overlay","background","svgViewportTransformation","_setSVGPreamble","_setSVGHeader","_setSVGBgOverlayColor","_setSVGBgOverlayImage","_setSVGObjects","suppressPreamble","encoding","viewBox","createSVGFontFacesMarkup","createSVGRefElementsMarkup","row","rowIndex","charIndex","fontList","_setSVGObject","sendToBack","objs","unshift","bringToFront","sendBackwards","intersecting","newIdx","objsMoved","_findNewLowerIndex","intersectsWithObject","isContainedWithinObject","bringForward","_findNewUpperIndex","dispose","DataURLExporter","EMPTY_JSON","supports","setLineDash","toJSON","BaseBrush","strokeLineCap","strokeLineJoin","strokeDashArray","setShadow","_setBrushStyles","contextTop","strokeStyle","lineWidth","lineCap","lineJoin","_setShadow","shadowColor","shadowBlur","shadowOffsetX","shadowOffsetY","_resetShadow","PencilBrush","_points","onMouseDown","pointer","_prepareForDrawing","_captureDrawingPath","_render","onMouseMove","onMouseUp","_finalizeAndAddPath","_reset","_addPoint","pointerPoint","p1","p2","midPoint","quadraticCurveTo","lineTo","convertPointsToSVGPath","multSignX","multSignY","manyPoints","createPath","pathData","Path","strokeWidth","originX","originY","translateToGivenOrigin","closePath","CircleBrush","drawDot","addPoint","arc","radius","originalRenderOnAddRemove","circles","circle","Circle","Group","circleRadius","circleColor","SprayBrush","density","dotWidth","dotWidthVariance","randomOpacity","optimizeOverlapping","sprayChunks","addSprayChunk","rects","ilen","sprayChunk","rect","Rect","_getOptimizedRects","uniqueRects","uniqueRectsArray","sprayChunkPoints","globalAlpha","PatternBrush","getPatternSrc","patternCanvas","patternCtx","getPatternSrcFunction","getPattern","topLeft","_getLeftTopCoords","supportLineDash","Canvas","_initInteractive","_createCacheCanvas","uniScaleTransform","uniScaleKey","centeredScaling","centeredRotation","centeredKey","altActionKey","selection","selectionKey","altSelectionKey","selectionColor","selectionDashArray","selectionBorderColor","selectionLineWidth","hoverCursor","moveCursor","defaultCursor","freeDrawingCursor","rotationCursor","containerClass","perPixelTargetFind","targetFindTolerance","skipTargetFind","isDrawingMode","preserveObjectStacking","snapAngle","snapThreshold","stopContextMenu","fireRightClick","fireMiddleClick","_currentTransform","_groupSelector","_initWrapperElement","_createUpperCanvas","_initEventListeners","freeDrawingBrush","_chooseObjectsToRender","getActiveGroup","activeObject","getActiveObject","objsToRender","activeGroupObjects","contextTopDirty","renderTop","_drawSelection","_resetCurrentTransform","original","_shouldCenterTransform","action","_setOriginToCenter","mouseXSign","mouseYSign","containsPoint","xy","_normalizePointer","_findTargetCorner","calcTransformMatrix","invertedM","vptPointer","restorePointerVpt","isTargetTransparent","hasBorders","transparentCorners","contextCache","originalColor","selectionBackgroundColor","active","_renderControls","_shouldClearSelection","evented","selectable","centerTransform","altKey","_getOriginFromCorner","corner","_getActionFromCorner","_setupCurrentTransform","ex","ey","lastX","lastY","theta","shiftKey","_translateObject","newLeft","newTop","moveX","moveY","_changeSkewTransformOrigin","mouseMove","by","origins","0","skew","originA","originB","flipSign","skewSign","_skewObject","skewed","lockSkewingX","lockSkewingY","actualMouseByOrigin","constraintPosition","actualMouseByCenter","toLocalPoint","lastMouseByCenter","dim","_getTransformedDimensions","translateToOriginPoint","_setObjectSkew","localMouse","_dim","newValue","newDim","dimNoSkew","otherBy","_otherBy","_by","newDimMouse","atan","_scaleObject","lockScalingX","lockScalingY","lockScalingFlip","scaled","_setLocalMouse","_setObjectScale","changeX","changeY","forbidScalingX","forbidScalingY","_scaleObjectEqually","newScaleX","newScaleY","_flipObject","dist","lastDist","signX","signY","padding","_rotateObject","lastAngle","curAngle","hasRoated","rightAngleLocked","leftAngleLocked","setCursor","cursor","_resetObjectTransform","groupSelector","aleft","atop","_setLineDash","strokeRect","findTarget","skipGroup","activeTarget","activeTargetSubs","targets","_searchPossibleTargets","_fireOverOutEvents","overOpt","outOpt","hoveredTarget","_hoveredTarget","previousTarget","nextTarget","_checkTarget","isEditing","normalizedPointer","subTarget","subTargetCheck","ignoreZoom","cssScale","boundsWidth","boundsHeight","bottom","right","lowerCanvasClass","_copyCanvasStyle","class","touch-action","fromEl","toEl","getSelectionContext","getSelectionElement","_setActiveObject","_activeObject","onDeselect","setActiveObject","currentActiveObject","_discardActiveObject","discardActiveObject","_setActiveGroup","setActiveGroup","_discardActiveGroup","destroy","discardActiveGroup","deactivateAll","allObjects","deactivateAllWithDispatch","removeListeners","removeChild","_drawObjectsControls","originalProperties","_realizeGroupTransformOnObject","_unwindGroupTransformOnObject","originalValues","realizeTransform","_setCursorFromEvent","cursorOffset","mr","mb","ml","checkClick","which","button","cursorMap","_bindEvents","_onResize","_onMouseDown","_onMouseMove","_onMouseOut","_onMouseEnter","_onMouseWheel","_onContextMenu","passive","eventjs","_onGesture","_onDrag","_onOrientationChange","_onShake","_onLongPress","eventsBinded","_onMouseUp","self","__onTransformGesture","__onDrag","__onMouseWheel","hiddenTextarea","focus","__onOrientationChange","__onShake","__onLongPress","stopPropagation","preventDefault","__onMouseDown","__onMouseUp","__onMouseMove","_shouldRender","isMoving","_previousPointer","_handleEvent","_isCurrentlyDrawing","_onMouseUpInDrawingMode","searchTarget","isClick","_finalizeCurrentTransform","actionPerformed","shouldRender","_maybeGroupObjects","__corner","eventType","targetObj","subTargets","_scaling","_restoreOriginXY","hasStateChanged","_previousOriginX","_previousOriginY","originPoint","_onMouseDownInDrawingMode","_onMouseMoveInDrawingMode","shouldGroup","_shouldGroup","_handleGrouping","_beforeTransform","saveState","_setCenterToOrigin","touches","_transformObject","reset","_beforeScaleTransform","_performTransformAction","_fire","_onScale","currentAction","_setCornerCursor","_getRotatedCornerCursor","hasRotatingPoint","getAngle","_updateActiveGroup","_createActiveGroup","saveCoords","removeWithUpdate","addWithUpdate","_createGroup","groupObjects","exitEditing","_groupSelectedObjects","_collectObjects","currentObject","selectionX1Y1","selectionX2Y2","intersectsWithRect","isContainedWithinRect","setObjectsCoords","supportQuality","format","quality","multiplier","cropping","__toDataURLWithMultiplier","origWidth","origHeight","scaledWidth","scaledHeight","newZoom","vp","newVp","originalInteractive","__toDataURL","toDataURLWithMultiplier","loadFromDatalessJSON","json","loadFromJSON","serialized","JSON","_enlivenObjects","_setBgOverlay","loaded","cbIfLoaded","__setBgOverlay","enlivedObject","_toDataURL","_toDataURLWithMultiplier","stringify","cloneWithoutData","backgroundImageOpacity","backgroundImageStretch","supportsLineDash","objectCaching","cornerSize","borderColor","borderDashArray","cornerColor","cornerStrokeColor","cornerStyle","cornerDashArray","fillRule","globalCompositeOperation","strokeMiterLimit","borderOpacityWhenMoving","borderScaleFactor","minScaleLimit","hasControls","rotatingPointOffset","lockMovementX","lockMovementY","lockRotation","lockUniScaling","statefullCache","noScaleCache","dirty","cacheProperties","_cacheProperties","_cacheCanvas","_cacheContext","_updateCacheCanvas","_limitCacheSize","dims","limitedDims","zoomX","capped","zoomY","_getCacheCanvasDimensions","objectScale","getObjectScaling","retina","_getNonTransformedDimensions","drawingWidth","drawingHeight","minCacheSize","dimensionsChanged","cacheWidth","cacheHeight","zoomChanged","shouldRedraw","additionalWidth","additionalHeight","shouldResizeCanvas","canvasWidth","canvasHeight","sizeGrowing","setTransform","cacheTranslationX","cacheTranslationY","fromLeft","_transformDone","_removeDefaultValues","scaling","shouldConstrainValue","isChanged","_constrainScale","setOnGroup","setSourcePath","getViewportTransform","isNotVisible","noTransform","isOnScreen","_setupCompositeOperation","drawSelectionBackground","_setOpacity","shouldCache","isCacheDirty","propertySet","drawObject","drawCacheOnCanvas","_removeCacheCanvas","needsItsOwnCache","isCaching","willDrawShadow","_setStrokeStyles","_setFillStyles","drawImage","skipCanvas","_removeShadow","miterLimit","dashArray","alternative","drawBordersInGroup","drawBorders","multX","multY","_applyPatternGradientTransform","patternTransform","_renderFill","_renderStroke","_renderDashedStroke","cloneAsImage","dataUrl","boundingRect","getBoundingRect","origParams","getLeft","getTop","originalCanvas","isType","setGradient","setPatternFill","setColor","shouldCenterOrigin","_resetOrigin","centerH","viewportCenterH","centerV","viewportCenterV","viewportCenter","getLocalPointer","pClicked","objectLeftTop","_fromObject","forceAsync","extraParam","originXOffset","originYOffset","fromOriginX","fromOriginY","toOriginX","toOriginY","translateToCenterPoint","leftTop","getPointByOrigin","adjustPosition","to","offsetFrom","offsetTo","hypotFull","xFull","yFull","_originalOriginX","_originalOriginY","multiplyMatrices","oCoords","aCoords","getCoords","absolute","calculate","calcCoords","pointTL","pointBR","other","lines","_getImageLines","_findCrossPoints","centerPoint","topline","rightline","bottomline","leftline","iLine","xcount","lineKey","getBoundingRectWidth","getBoundingRectHeight","scaleToWidth","boundingRectFactor","scaleToHeight","_calculateCurrentDimensions","currentWidth","currentHeight","_angle","_hypotenuse","mtr","skipAbsolute","_setCornerCoords","_calcRotateMatrix","rotateMatrix","dimensionMatrix","_calcDimensionsTransformMatrix","flipping","bbox","dimX","dimY","getSvgColorString","str","getSvgStyles","skipShadow","getSvgFilter","getSvgId","getSvgTransform","getSkewX","getSkewY","translatePart","anglePart","scalePart","skewXPart","skewYPart","addTranslateX","flipXPart","addTranslateY","getSvgTransformMatrix","_createBaseSVGMarkup","originalSet","saveProps","props","tmpObj","dashedPropertySet","keys","_isEqual","origValue","currentValue","firstPass","_controlsVisibility","isControlVisible","newTheta","cornerHypotenuse","cosHalfOffset","sinHalfOffset","wh","rotateHeight","scaleOffset","_drawControl","control","controlName","_getControlsVisibility","setControlVisible","setControlsVisibility","FX_DURATION","fxCenterObjectH","callbacks","empty","fxCenterObjectV","fxRemove","skipCallbacks","propsToAnimate","_animate","propPair","from","valueProgress","timeProgress","coordProps","makeEdgeToOriginGetter","propertyNames","originValues","axis1","axis2","dimension","nearest","farthest","Line","_setWidthHeight","_getLeftToOriginX","_getTopToOriginY","cp","calcLinePoints","origStrokeStyle","xMult","yMult","ATTRIBUTE_NAMES","parsedAttributes","line","pi","startAngle","endAngle","setRadius","startX","startY","endX","endY","largeFlag","getRadiusX","getRadiusY","Triangle","widthBy2","heightBy2","piBy2","Ellipse","getRx","getRy","ellipse","_initRxRy","w","isRounded","Polyline","_calcDimensions","pathOffset","diffX","diffY","commonRender","Polygon","_toString","commandLengths","repeatedCommands","M","fromArray","_parsePath","_setPositionDimensions","calcDim","_parseDimensions","_renderPathCommands","tempX","tempY","previous","subpathStartX","subpathStartY","controlX","controlY","chunks","addTransform","currentPath","coordsStr","coordsParsed","re","command","commandLength","repeatedCommand","klen","aX","aY","pathUrl","paths","parseDimensionsFromPaths","xC","yC","parentCache","caching","isSameColor","pathsToObject","originalDefaults","firstPathFill","pathFill","total","originalPaths","pathGroup","_lockProperties","isAlreadyGrouped","_updateObjectsCoords","_updateObjectsACoords","_calcBounds","skipCoordsChange","_updateObjectCoords","__origHasControls","objectLeft","objectTop","_restoreObjectsState","_setObjectActive","delegatedProperties","textDecoration","textAlign","objsToObject","_renderObject","originalHasRotatingPoint","_restoreObjectState","_originalLeft","_originalTop","hasMoved","onlyWidthHeight","iLen","jLen","_getBounds","minXY","maxXY","_lastScaleX","_lastScaleY","minimumScaleTrigger","filters","resizeFilters","_initElement","_element","_callback","_originalElement","_initConfig","applyFilters","_filteredEl","setCrossOrigin","getOriginalSize","_stroke","filterObj","getSrc","getSvgSrc","origFill","filtered","_src","setSrc","imgElement","forResizing","replacement","retinaScaling","minimumScale","applyTo","toBuffer","pngCompression","elementToDraw","imageMargins","_findMargins","_needsResize","marginX","marginY","scales","_resetWidthHeight","CSS_CANVAS","_initFilters","fromURL","imgOptions","preserveAR","_getAngleValueForStraighten","straighten","fxStraighten","straightenObject","fxStraightenObject","BaseFilter","Brightness","brightness","putImageData","Convolute","opaque","dstOff","scx","scy","srcOff","wt","weights","pixels","side","halfSide","sw","sh","output","createImageData","dst","alphaFac","GradientTransparency","Grayscale","Invert","Mask","mask","channel","maskEl","maskCanvasEl","maskData","Noise","noise","rand","Pixelate","blocksize","_i","_ilen","_j","_jlen","RemoveWhite","distance","limit","Sepia","avg","Sepia2","Tint","tintR","tintG","tintB","alpha1","Multiply","Blend","mode","tg","_r","_g","_b","isImage","_el","tmpCanvas","Resize","resizeType","lanczosLobes","rcpScaleX","rcpScaleY","oW","oH","dW","dH","sliceByTwo","hermiteFastResize","bilinearFiltering","lanczosResize","multW","multH","signW","signH","doneW","doneH","stepW","stepH","tmpCtx","lobes","srcImg","destImg","srcData","destData","lanczos","xx","ratioX","ratioY","rcpRatioX","rcpRatioY","range2X","range2Y","cacheLanc","icenter","process","u","weight","fX","fY","xDiff","yDiff","chnl","origPix","w4","destImage","destPixels","ratioW","ratioH","ratioWHalf","ratioHHalf","img2","data2","weightsAlpha","gxR","gxG","gxB","gxA","centerY","yy","centerX","w0","ColorMatrix","Contrast","contrast","contrastF","Saturate","saturate","adjust","_dimensionAffectingProps","_reNewline","_reSpacesAndTabs","textBackgroundColor","_fontSizeFraction","_fontSizeMult","charSpacing","__skipDimension","_initDimensions","_setTextStyles","_textLines","_splitTextIntoLines","_clearCache","_getTextWidth","cursorWidth","_getTextHeight","_renderTextLinesBackground","_renderText","_renderTextDecoration","_renderTextFill","_renderTextStroke","textBaseline","_getFontDeclaration","_getHeightOfSingleLine","_getHeightOfLine","maxWidth","_getLineWidth","currentLineWidth","_renderChars","chars","_char","shortM","additionalSpace","_getWidthOfCharSpacing","measureText","_renderTextLine","lineIndex","word","words","charOffset","wordsWidth","_getWidthOfWords","widthDiff","numSpaces","spaceWidth","leftOffset","_getLeftOffset","_getTopOffset","isEmptyStyles","_renderTextCommon","lineHeights","heightOfLine","maxHeight","_getLineLeftOffset","lineLeftOffset","lineTopOffset","originalFill","__lineWidths","__lineHeights","_shouldClearDimensionCache","shouldClear","_forceClearCache","_measureLine","finalWidth","halfOfVerticalBox","offsets","oLen","renderLinesAtOffset","additionalProperties","_getSVGLeftTopOffsets","textAndBg","_getSVGTextAndBg","textTop","textLeft","_wrapSVGTextAndBg","lineTop","textBgRects","textSpans","textTopOffset","textLeftOffset","_setSVGBg","_setSVGTextLineBg","_setSVGTextLineText","yPos","_getFillAttributes","_setSVGTextLineJustifed","fillColor","textHeightScaleFactor","scaledDiff","textHeight","offX","IText","selectionStart","selectionEnd","editable","editingBorderColor","cursorColor","cursorDelay","cursorDuration","_reSpace","_currentCursorOpacity","_selectionDirection","_abortCursorAnimation","__widthOfSpace","initBehavior","p3","setSelectionStart","_updateAndFire","setSelectionEnd","_fireSelectionChanged","_updateTextarea","getSelectionStyles","startIndex","endIndex","loc","get2DCursorLocation","_getStyleDeclaration","setSelectionStyles","_extendStyles","_getLineStyle","_setLineStyle","_setStyleDeclaration","clearContextTop","cursorOffsetCache","renderCursorOrSelection","_clearTextArea","boundaries","_getCursorBoundaries","renderCursor","renderSelection","getCurrentCharStyle","getCurrentCharFontSize","getCurrentCharColor","typeOfBoundaries","_getCursorBoundariesOffsets","lineLeft","topOffset","_getWidthOfChar","cursorLocation","charHeight","__isMousedown","startLine","endLine","realLineHeight","lineOffset","boxWidth","j2","j2len","_renderCharsFast","prevStyle","thisStyle","charsToRender","_hasStyleChanged","_renderChar","skipFillStrokeCheck","charWidth","shouldFill","shouldStroke","_charWidth","decl","_getHeightOfChar","_applyCharStylesGetWidth","jChar","fillText","strokeText","_renderCharDecoration","decoration","decorationWeight","positions","underline","line-through","overline","decorations","leftCache","topCache","widthCache","heightCache","colorCache","_getWidthOfCharsAt","_getCacheProp","styleDeclaration","_getFontCache","cacheProp","charDecl","_applyFontStyles","returnCloneOrEmpty","_deleteStyleDeclaration","_deleteLineStyle","_isMeasuring","_getWidthOfSpace","currentCharHeight","initAddedHandler","initRemovedHandler","initCursorSelectionHandlers","initDoubleClickSimulation","mouseMoveHandler","selected","_initCanvasHandlers","_removeCanvasHandlers","_tick","_currentTickState","_animateCursor","targetOpacity","completeMethod","tickState","isAborted","_onTickComplete","_cursorTimeout1","clearTimeout","_currentTickCompleteState","initDelayedCursor","restart","delay","abortCursorAnimation","_cursorTimeout2","selectAll","getSelectedText","findWordBoundaryLeft","startFrom","findWordBoundaryRight","findLineBoundaryLeft","findLineBoundaryRight","getNumNewLinesInSelectedText","selectedText","numNewLines","searchWordBoundary","direction","reNonWord","selectWord","newSelectionStart","newSelectionEnd","selectLine","enterEditing","exitEditingOnOthers","initHiddenTextarea","_saveEditingProps","_setEditingProps","_textBeforeEdit","initMouseMoveHandler","getSelectionStartFromPointer","currentStart","currentEnd","__selectionStartOnMouseDown","restartCursorIfNeeded","inCompositionMode","_calcTextareaPosition","upperCanvas","_savedProps","_restoreEditingProps","overCursor","isTextChanged","_removeExtraneousStyles","_removeCharsFromTo","_removeSingleCharAndStyle","isBeginningOfLine","indexStyle","removeStyleObject","insertChars","_chars","useCopiedStyle","copiedTextStyle","insertChar","skipUpdate","styleObject","isEndOfLine","insertStyleObjects","insertNewlineStyleObject","shiftLineStyles","currentCharStyle","newLineStyles","somethingAdded","numIndex","insertCharStyleObject","currentLineStyles","currentLineStylesCloned","numericIndex","newStyle","clonedStyles","numericLine","_removeStyleObject","_getTextOnPreviousLine","lIndex","textOnPreviousLine","newCharIndexOnPrevLine","insertNewline","setSelectionStartEndWithShift","newSelection","setSelectionInBoundaries","__lastClickTime","__lastLastClickTime","__lastPointer","__newClickTime","newPointer","isTripleClick","_stopEvent","isDoubleClick","__lastIsEditing","__lastSelected","initMousedownHandler","initMouseupHandler","initClicks","__mousedownX","__mousedownY","setCursorByClick","_isObjectMoved","mouseOffset","prevWidth","widthOfLine","_getNewSelectionStartFromOffset","onKeyDown","onKeyUp","onInput","copy","cut","paste","onCompositionStart","onCompositionUpdate","onCompositionEnd","_clickHandlerInitialized","onClick","keysMap","8","9","27","13","33","34","35","36","37","38","39","40","46","ctrlKeysMapUp","67","88","ctrlKeysMapDown","65","keyCode","ctrlKey","metaKey","stopImmediatePropagation","_copyDone","diff","charsToInsert","offsetEnd","textLength","newTextLength","prevCompositionLength","compositionStart","forwardDelete","moveCursorRight","removeChars","clipboardData","_getClipboardData","setData","copiedText","getData","_getWidthBeforeCursor","textBeforeCursor","widthBeforeCursor","getDownCursorOffset","isRight","selectionProp","_getSelectionForOffset","indexOnOtherLine","_getIndexOnLine","getUpCursorOffset","foundMatch","textOnLine","widthOfCharsOnLine","indexOnLine","widthOfChar","leftEdge","rightEdge","offsetFromLeftEdge","moveCursorDown","_moveCursorUpOrDown","moveCursorUp","moveCursorWithShift","moveCursorWithoutShift","moveCursorLeft","_moveCursorLeftOrRight","_move","_moveLeft","_moveRight","moveCursorLeftWithoutShift","change","moveCursorLeftWithShift","actionName","moveCursorRightWithShift","moveCursorRightWithoutShift","changed","_removeCharsNearCursor","leftLineBoundary","leftWordBoundary","_setSVGTextLineChars","_getSVGLineTopOffset","styleDecl","_createTextCharSpan","_createTextCharBg","lastHeight","fillStyles","Textbox","minWidth","dynamicMinWidth","__cachedLines","getTextboxControlVisibility","_generateStyleMap","realLineCount","realLineCharCount","charCount","_styleMap","_wrapText","wrapped","_wrapLine","_measureText","wordWidth","infixWidth","largestWordWidth","lineJustStarted","originalAlign","__oldScaleX","numLines","removed","lineLen","lineChars","getMinWidth","setObjectScaleOverridden","_refreshControlsVisibility","override","tmp","URL","HTTP","HTTPS","createImageAndCallBack","requestFs","eval","createCanvasForNode","nodeCanvasOptions","nodeCanvas","nodeCacheCanvas","fabricCanvas","Font","originaInitStatic","createPNGStream","createJPEGStream","origSetBackstoreDimension","oURL","port","protocol","req","hostname","response","setEncoding","statusCode","errno","ECONNREFUSED","message","readFile"],"mappings":"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","file":"fabric.js","sourcesContent":["/* 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"]}