{"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","areHostMethods","methodNames","test","getElement","setElement","uid","getUniqueId","element","__uniqueID","createWrappedHandler","e","event","addListener","removeListener","shouldUseAddListenerRemoveListener","documentElement","shouldUseAttachEventDetachEvent","listeners","handlers","addEventListener","removeEventListener","listener","wrappedHandler","createListener","attachEvent","detachEvent","existingHandler","handlersForEvent","createDispatcher","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","onComplete","xhr","parameters","param","addParamToUrl","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","normalizeAttr","normalizeValue","parentAttributes","parsed","isArray","transformMatrix","parseTransformAttribute","visible","isNaN","_getMultipleNodes","nodeNames","nodeName","nodeList","nodeArray","elementMatchesRule","selectors","firstMatching","parentMatching","selectorMatches","selector","doesSomeParentMatch","matcher","classNames","getAttribute","RegExp","elementById","node","nodelist","cssRules","gradientDefs","skewMatrix","matrix","commaWsp","reTransformList","reTransform","attributeValue","matrices","m","operation","translateMatrix","rotateMatrix","multiplierX","multiplierY","combinedMatrix","reViewBoxAttrValue","applyViewboxTransform","viewBoxWidth","viewBoxHeight","viewBoxAttr","widthAttr","heightAttr","preserveAspectRatio","missingViewBox","missingDimAttr","toBeParsed","parsedDim","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","elList","idsToXlinkMap","parseAttributes","ownAttributes","rule","getGlobalStylesForElement","parseStyleAttribute","normalizedAttr","normalizedValue","normalizedStyle","font","mergedAttrs","setAlpha","getAlpha","toRgba","_setStrokeFillOpacity","ElementsParser","parse","chunk","pair","parseStyleString","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","getLinearCoords","getRadialCoords","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","xi","iLine","xcount","lineKey","getBoundingRectWidth","getBoundingRectHeight","scaleToWidth","boundingRectFactor","scaleToHeight","_calculateCurrentDimensions","currentWidth","currentHeight","_angle","_hypotenuse","mtr","skipAbsolute","_setCornerCoords","_calcRotateMatrix","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","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","distanceBtwLastCharAndCursor","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"]}