text: (function(global) {
  
    'use strict';
  
    var fabric = global.fabric || (global.fabric = { }),
        pi = Math.PI,
        extend = fabric.util.object.extend;
  
    if (fabric.Circle) {
      fabric.warn('fabric.Circle is already defined.');
      return;
    }
  
    /**
     * Circle class
     * @class fabric.Circle
     * @extends fabric.Object
     * @see {@link fabric.Circle#initialize} for constructor definition
     */
    fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ {
  
      /**
       * Type of an object
       * @type String
       * @default
       */
      type: 'circle',
  
      /**
       * Radius of this circle
       * @type Number
       * @default
       */
      radius: 0,
  
      /**
       * Start angle of the circle, moving clockwise
       * @type Number
       * @default 0
       */
      startAngle: 0,
  
      /**
       * End angle of the circle
       * @type Number
       * @default 2Pi
       */
      endAngle: pi * 2,
  
      /**
       * Constructor
       * @param {Object} [options] Options object
       * @return {fabric.Circle} thisArg
       */
      initialize: function(options) {
        options = options || { };
  
        this.callSuper('initialize', options);
        this.set('radius', options.radius || 0);
  
        this.startAngle = options.startAngle || this.startAngle;
        this.endAngle = options.endAngle || this.endAngle;
      },
  
      /**
       * @private
       * @param {String} key
       * @param {Any} value
       * @return {fabric.Circle} thisArg
       */
      _set: function(key, value) {
        this.callSuper('_set', key, value);
  
        if (key === 'radius') {
          this.setRadius(value);
        }
  
        return this;
      },
  
      /**
       * Returns object representation of an instance
       * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
       * @return {Object} object representation of an instance
       */
      toObject: function(propertiesToInclude) {
        return extend(this.callSuper('toObject', propertiesToInclude), {
          radius: this.get('radius'),
          startAngle: this.startAngle,
          endAngle: this.endAngle
        });
      },
  
      /* _TO_SVG_START_ */
      /**
       * Returns svg representation of an instance
       * @param {Function} [reviver] Method for further parsing of svg representation.
       * @return {String} svg representation of an instance
       */
      toSVG: function(reviver) {
        var markup = this._createBaseSVGMarkup(), x = 0, y = 0,
        angle = (this.endAngle - this.startAngle) % ( 2 * pi);
  
        if (angle === 0) {
          if (this.group && this.group.type === 'path-group') {
            x = this.left + this.radius;
            y = this.top + this.radius;
          }
          markup.push(
            '<circle ', this.getSvgId(),
              'cx="' + x + '" cy="' + y + '" ',
              'r="', this.radius,
              '" style="', this.getSvgStyles(),
              '" transform="', this.getSvgTransform(),
              ' ', this.getSvgTransformMatrix(),
            '"/>\n'
          );
        }
        else {
          var startX = Math.cos(this.startAngle) * this.radius,
              startY = Math.sin(this.startAngle) * this.radius,
              endX = Math.cos(this.endAngle) * this.radius,
              endY = Math.sin(this.endAngle) * this.radius,
              largeFlag = angle > pi ? '1' : '0';
  
          markup.push(
            '<path d="M ' + startX + ' ' + startY,
            ' A ' + this.radius + ' ' + this.radius,
            ' 0 ', + largeFlag + ' 1', ' ' + endX + ' ' + endY,
            '" style="', this.getSvgStyles(),
            '" transform="', this.getSvgTransform(),
            ' ', this.getSvgTransformMatrix(),
            '"/>\n'
          );
        }
  
        return reviver ? reviver(markup.join('')) : markup.join('');
      },
      /* _TO_SVG_END_ */
  
      /**
       * @private
       * @param {CanvasRenderingContext2D} ctx context to render on
       * @param {Boolean} [noTransform] When true, context is not transformed
       */
      _render: function(ctx, noTransform) {
        ctx.beginPath();
        ctx.arc(noTransform ? this.left + this.radius : 0,
                noTransform ? this.top + this.radius : 0,
                this.radius,
                this.startAngle,
                this.endAngle, false);
        this._renderFill(ctx);
        this._renderStroke(ctx);
      },
  
      /**
       * Returns horizontal radius of an object (according to how an object is scaled)
       * @return {Number}
       */
      getRadiusX: function() {
        return this.get('radius') * this.get('scaleX');
      },
  
      /**
       * Returns vertical radius of an object (according to how an object is scaled)
       * @return {Number}
       */
      getRadiusY: function() {
        return this.get('radius') * this.get('scaleY');
      },
  
      /**
       * Sets radius of an object (and updates width accordingly)
       * @return {fabric.Circle} thisArg
       */
      setRadius: function(value) {
        this.radius = value;
        return this.set('width', value * 2).set('height', value * 2);
      },
  
      /**
       * Returns complexity of an instance
       * @return {Number} complexity of this instance
       */
      complexity: function() {
        return 1;
      }
    });
  
    /* _FROM_SVG_START_ */
    /**
     * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement})
     * @static
     * @memberOf fabric.Circle
     * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement
     */
    fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy r'.split(' '));
  
    /**
     * Returns {@link fabric.Circle} instance from an SVG element
     * @static
     * @memberOf fabric.Circle
     * @param {SVGElement} element Element to parse
     * @param {Object} [options] Options object
     * @throws {Error} If value of `r` attribute is missing or invalid
     * @return {fabric.Circle} Instance of fabric.Circle
     */
    fabric.Circle.fromElement = function(element, options) {
      options || (options = { });
  
      var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);
  
      if (!isValidRadius(parsedAttributes)) {
        throw new Error('value of `r` attribute is required and can not be negative');
      }
  
      parsedAttributes.left = parsedAttributes.left || 0;
      parsedAttributes.top = parsedAttributes.top || 0;
  
      var obj = new fabric.Circle(extend(parsedAttributes, options));
  
      obj.left -= obj.radius;
      obj.top -= obj.radius;
      return obj;
    };
  
    /**
     * @private
     */
    function isValidRadius(attributes) {
      return (('radius' in attributes) && (attributes.radius >= 0));
    }
    /* _FROM_SVG_END_ */
  
    /**
     * Returns {@link fabric.Circle} instance from an object representation
     * @static
     * @memberOf fabric.Circle
     * @param {Object} object Object to create an instance from
     * @return {Object} Instance of fabric.Circle
     */
    fabric.Circle.fromObject = function(object) {
      return new fabric.Circle(object);
    };
  
  })(typeof exports !== 'undefined' ? exports : this);
  