text: /*
   * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
   * http://paperjs.org/
   *
   * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
   * http://scratchdisk.com/ & http://jonathanpuckey.com/
   *
   * Distributed under the MIT license. See LICENSE file for details.
   *
   * All rights reserved.
   */
  
  /**
   * @name PaperScript
   * @namespace
   */
  Base.exports.PaperScript = function() {
      // Locally turn of exports and define for inlined acorn.
      // Just declaring the local vars is enough, as they will be undefined.
      var exports, define,
          // The scope into which the library is loaded.
          scope = this;
  /*#*/ include('../../node_modules/acorn/acorn.min.js', { exports: false });
  
      // Operators to overload
  
      var binaryOperators = {
          // The hidden math methods are to be injected specifically, see below.
          '+': '__add',
          '-': '__subtract',
          '*': '__multiply',
          '/': '__divide',
          '%': '__modulo',
          '==': '__equals',
          '!=': '__equals'
      };
  
      var unaryOperators = {
          '-': '__negate',
          '+': null
      };
  
      // Inject underscored math methods as aliases to Point, Size and Color.
      var fields = Base.each(
          ['add', 'subtract', 'multiply', 'divide', 'modulo', 'equals', 'negate'],
          function(name) {
              // Create an alias for each math method to be injected into the
              // classes using Straps.js' #inject()
              this['__' + name] = '#' + name;
          },
          {}
      );
      Point.inject(fields);
      Size.inject(fields);
      Color.inject(fields);
  
      // Use very short name for the binary operator (__$__) as well as the
      // unary operator ($__), as operations will be replaced with then.
      // The underscores stands for the values, and the $ for the operators.
  
      // Binary Operator Handler
      function __$__(left, operator, right) {
          var handler = binaryOperators[operator];
          if (left && left[handler]) {
              var res = left[handler](right);
              return operator === '!=' ? !res : res;
          }
          switch (operator) {
          case '+': return left + right;
          case '-': return left - right;
          case '*': return left * right;
          case '/': return left / right;
          case '%': return left % right;
          case '==': return left == right;
          case '!=': return left != right;
          }
      }
  
      // Unary Operator Handler
      function $__(operator, value) {
          var handler = unaryOperators[operator];
          if (handler && value && value[handler])
              return value[handler]();
          switch (operator) {
          case '+': return +value;
          case '-': return -value;
          }
      }
  
      // AST Helpers
  
      function parse(code, options) {
          return scope.acorn.parse(code, options);
      }
  
      /**
       * Compiles PaperScript code into JavaScript code.
       *
       * @name PaperScript.compile
       * @function
       *
       * @option options.url {String} the url of the source, for source-map
       *     generation
       * @option options.source {String} the source to be used for the source-
       *     mapping, in case the code that's passed in has already been mingled.
       *
       * @param {String} code the PaperScript code
       * @param {Object} [option] the compilation options
       * @return {Object} an object holding the compiled PaperScript translated
       *     into JavaScript code along with source-maps and other information.
       */
      function compile(code, options) {
          if (!code)
              return '';
          options = options || {};
          // Use Acorn or Esprima to translate the code into an AST structure
          // which is then walked and parsed for operators to overload. Instead of
          // modifying the AST and translating it back to code, we directly change
          // the source code based on the parser's range information, to preserve
          // line-numbers in syntax errors and remove the need for Escodegen.
  
          // Track code insertions so their differences can be added to the
          // original offsets.
          var insertions = [];
  
          // Converts an original offset to the one in the current state of the
          // modified code.
          function getOffset(offset) {
              // Add all insertions before this location together to calculate
              // the current offset
              for (var i = 0, l = insertions.length; i < l; i++) {
                  var insertion = insertions[i];
                  if (insertion[0] >= offset)
                      break;
                  offset += insertion[1];
              }
              return offset;
          }
  
          // Returns the node's code as a string, taking insertions into account.
          function getCode(node) {
              return code.substring(getOffset(node.range[0]),
                      getOffset(node.range[1]));
          }
  
          // Returns the code between two nodes, e.g. an operator and white-space.
          function getBetween(left, right) {
              return code.substring(getOffset(left.range[1]),
                      getOffset(right.range[0]));
          }
  
          // Replaces the node's code with a new version and keeps insertions
          // information up-to-date.
          function replaceCode(node, str) {
              var start = getOffset(node.range[0]),
                  end = getOffset(node.range[1]),
                  insert = 0;
              // Sort insertions by their offset, so getOffest() can do its thing
              for (var i = insertions.length - 1; i >= 0; i--) {
                  if (start > insertions[i][0]) {
                      insert = i + 1;
                      break;
                  }
              }
              insertions.splice(insert, 0, [start, str.length - end + start]);
              code = code.substring(0, start) + str + code.substring(end);
          }
  
          // Recursively walks the AST and replaces the code of certain nodes
          function walkAST(node, parent) {
              if (!node)
                  return;
              // The easiest way to walk through the whole AST is to simply loop
              // over each property of the node and filter out fields we don't
              // need to consider...
              for (var key in node) {
                  if (key === 'range' || key === 'loc')
                      continue;
                  var value = node[key];
                  if (Array.isArray(value)) {
                      for (var i = 0, l = value.length; i < l; i++)
                          walkAST(value[i], node);
                  } else if (value && typeof value === 'object') {
                      // We cannot use Base.isPlainObject() for these since
                      // Acorn.js uses its own internal prototypes now.
                      walkAST(value, node);
                  }
              }
              switch (node.type) {
              case 'UnaryExpression': // -a
                  if (node.operator in unaryOperators
                          && node.argument.type !== 'Literal') {
                      var arg = getCode(node.argument);
                      replaceCode(node, '$__("' + node.operator + '", '
                              + arg + ')');
                  }
                  break;
              case 'BinaryExpression': // a + b, a - b, a / b, a * b, a == b, ...
                  if (node.operator in binaryOperators
                          && node.left.type !== 'Literal') {
                      var left = getCode(node.left),
                          right = getCode(node.right),
                          between = getBetween(node.left, node.right),
                          operator = node.operator;
                      replaceCode(node, '__$__(' + left + ','
                              // To preserve line-breaks, get the code in between
                              // left & right, and replace the occurrence of the
                              // operator with its string counterpart:
                              + between.replace(new RegExp('\\' + operator),
                                  '"' + operator + '"')
                              + ', ' + right + ')');
                  }
                  break;
              case 'UpdateExpression': // a++, a--, ++a, --a
              case 'AssignmentExpression': /// a += b, a -= b
                  var parentType = parent && parent.type;
                  if (!(
                          // Filter out for statements to allow loop increments
                          // to perform well
                          parentType === 'ForStatement'
                          // We need to filter out parents that are comparison
                          // operators, e.g. for situations like `if (++i < 1)`,
                          // as we can't replace that with
                          // `if (__$__(i, "+", 1) < 1)`
                          // Match any operator beginning with =, !, < and >.
                          || parentType === 'BinaryExpression'
                              && /^[=!<>]/.test(parent.operator)
                          // array[i++] is a MemberExpression with computed = true
                          // We can't replace that with array[__$__(i, "+", 1)].
                          || parentType === 'MemberExpression' && parent.computed
                  )) {
                      if (node.type === 'UpdateExpression') {
                          var arg = getCode(node.argument),
                              exp = '__$__(' + arg + ', "' + node.operator[0]
                                      + '", 1)',
                              str = arg + ' = ' + exp;
                          // If this is not a prefixed update expression
                          // (++a, --a), assign the old value before updating it.
                          if (!node.prefix
                                  && (parentType === 'AssignmentExpression'
                                      || parentType === 'VariableDeclarator')) {
                              // Handle special issue #691 where the old value is
                              // assigned to itself, and the expression is just
                              // executed after, e.g.: `var x = ***; x = x++;`
                              if (getCode(parent.left || parent.id) === arg)
                                  str = exp;
                              str = arg + '; ' + str;
                          }
                          replaceCode(node, str);
                      } else { // AssignmentExpression
                          if (/^.=$/.test(node.operator)
                                  && node.left.type !== 'Literal') {
                              var left = getCode(node.left),
                                  right = getCode(node.right),
                                  exp = left + ' = __$__(' + left + ', "'
                                      + node.operator[0] + '", ' + right + ')';
                              // If the original expression is wrapped in
                              // parenthesis, do the same with the replacement:
                              replaceCode(node, /^\(.*\)$/.test(getCode(node))
                                      ? '(' + exp + ')' : exp);
                          }
                      }
                  }
                  break;
              }
          }
  
          // Source-map support:
          // Encodes a Variable Length Quantity as a Base64 string.
          // See: http://www.html5rocks.com/en/tutorials/developertools/sourcemaps
          function encodeVLQ(value) {
              var res = '',
                  base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
              value = (Math.abs(value) << 1) + (value < 0 ? 1 : 0);
              while (value || !res) {
                  var next = value & (32 - 1);
                  value >>= 5;
                  if (value)
                      next |= 32;
                  res += base64[next];
              }
              return res;
          }
  
          var url = options.url || '',
              agent = paper.agent,
              version = agent.versionNumber,
              offsetCode = false,
              sourceMaps = options.sourceMaps,
              // Include the original code in the sourceMap if there is no linked
              // source file so the debugger can still display it correctly.
              source = options.source || code,
              lineBreaks = /\r\n|\n|\r/mg,
              offset = options.offset || 0,
              map;
          // TODO: Verify these browser versions for source map support, and check
          // other browsers.
          if (sourceMaps && (agent.chrome && version >= 30
                  || agent.webkit && version >= 537.76 // >= Safari 7.0.4
                  || agent.firefox && version >= 23
                  || agent.node)) {
              if (agent.node) {
                  // -2 required to remove function header:
                  // https://code.google.com/p/chromium/issues/detail?id=331655
                  offset -= 2;
              } else if (window && url && !window.location.href.indexOf(url)) {
                  // If the code stems from the actual html page, determine the
                  // offset of inlined code.
                  var html = document.getElementsByTagName('html')[0].innerHTML;
                  // Count the amount of line breaks in the html before this code
                  // to determine the offset.
                  offset = html.substr(0, html.indexOf(code) + 1).match(
                          lineBreaks).length + 1;
              }
              // A hack required by older versions of browsers to align inlined
              // code: Instead of starting the mappings at the given offset, we
              // have to shift the actual code down to the place in the original
              // file, as source-map support seems incomplete in these browsers.
              offsetCode = offset > 0 && !(
                      agent.chrome && version >= 36 ||
                      agent.safari && version >= 600 ||
                      agent.firefox && version >= 40 ||
                      agent.node);
              var mappings = ['AA' + encodeVLQ(offsetCode ? 0 : offset) + 'A'];
              // Create empty entries by the amount of lines + 1, so join can be
              // used below to produce the actual instructions that many times.
              mappings.length = (code.match(lineBreaks) || []).length + 1
                      + (offsetCode ? offset : 0);
              map = {
                  version: 3,
                  file: url,
                  names:[],
                  // Since PaperScript doesn't actually change the offsets between
                  // the lines of the original code, all that is required is a
                  // mappings string that increments by one between each line.
                  // AACA is the instruction to increment the line by one.
                  // TODO: Add support for column offsets!
                  mappings: mappings.join(';AACA'),
                  sourceRoot: '',
                  sources: [url],
                  sourcesContent: [source]
              };
          }
          // Now do the parsing magic
          walkAST(parse(code, { ranges: true }));
          if (map) {
              if (offsetCode) {
                  // Adjust the line offset of the resulting code if required.
                  // This is part of a browser hack, see above.
                  code = new Array(offset + 1).join('\n') + code;
              }
              if (/^(inline|both)$/.test(sourceMaps)) {
                  code += "\n//# sourceMappingURL=data:application/json;base64,"
                          + self.btoa(unescape(encodeURIComponent(
                              JSON.stringify(map))));
              }
              code += "\n//# sourceURL=" + (url || 'paperscript');
          }
          return {
              url: url,
              source: source,
              code: code,
              map: map
          };
      }
  
      /**
       * Compiles the PaperScript code into a compiled function and executes it.
       * The compiled function receives all properties of the passed {@link
       * PaperScope} as arguments, to emulate a global scope with unaffected
       * performance. It also installs global view and tool handlers automatically
       * on the respective objects.
       *
       * @name PaperScript.execute
       * @function
       *
       * @option options.url {String} the url of the source, for source-map
       *     generation
       * @option options.source {String} the source to be used for the source-
       *     mapping, in case the code that's passed in has already been mingled.
       *
       * @param {String} code the PaperScript code
       * @param {PaperScope} scope the scope for which the code is executed
       * @param {Object} [option] the compilation options
       * @return {Object} an object holding the compiled PaperScript translated
       *     into JavaScript code along with source-maps and other information.
       */
      function execute(code, scope, options) {
          // Set currently active scope.
          paper = scope;
          var view = scope.getView(),
              // Only create a tool if the tool object is accessed or something
              // resembling a global tool handler is contained in the code, but
              // no tool objects are actually created.
              tool = /\btool\.\w+|\s+on(?:Key|Mouse)(?:Up|Down|Move|Drag)\b/
                      .test(code) && !/\bnew\s+Tool\b/.test(code)
                          ? new Tool() : null,
              toolHandlers = tool ? tool._events : [],
              // Compile a list of all handlers that can be defined globally
              // inside the PaperScript. These are passed on to the function as
              // undefined arguments, so that their name exists, rather than
              // injecting a code line that defines them as variables. They are
              // exported again at the end of the function.
              handlers = ['onFrame', 'onResize'].concat(toolHandlers),
              // compile a list of parameter names for all variables that need to
              // appear as globals inside the script. At the same time, also
              // collect their values, so we can pass them on as arguments in the
              // function call.
              params = [],
              args = [],
              func,
              compiled = typeof code === 'object' ? code : compile(code, options);
          code = compiled.code;
          function expose(scope, hidden) {
              // Look through all enumerable properties on the scope and expose
              // these too as pseudo-globals, but only if they seem to be in use.
              for (var key in scope) {
                  // Next to \b well also need to match \s and \W in the beginning
                  // of $__, since $ is not part of \w. And that causes \b to not
                  // match ^ longer, so include that specifically too.
                  if ((hidden || !/^_/.test(key)) && new RegExp('([\\b\\s\\W]|^)'
                          + key.replace(/\$/g, '\\$') + '\\b').test(code)) {
                      params.push(key);
                      args.push(scope[key]);
                  }
              }
          }
          expose({ __$__: __$__, $__: $__, paper: scope, view: view, tool: tool },
                  true);
          expose(scope);
          // Finally define the handler variable names as parameters and compose
          // the string describing the properties for the returned object at the
          // end of the code execution, so we can retrieve their values from the
          // function call.
          handlers = Base.each(handlers, function(key) {
              // Check for each handler explicitly and only return them if they
              // seem to exist.
              if (new RegExp('\\s+' + key + '\\b').test(code)) {
                  params.push(key);
                  this.push(key + ': ' + key);
              }
          }, []).join(', ');
          // We need an additional line that returns the handlers in one object.
          if (handlers)
              code += '\nreturn { ' + handlers + ' };';
          var agent = paper.agent;
          if (document && (agent.chrome
                  || agent.firefox && agent.versionNumber < 40)) {
              // On older Firefox, all error numbers inside dynamically compiled
              // code are relative to the line where the eval / compilation
              // happened. To fix this issue, we're temporarily inserting a new
              // script tag.
              // We also use this on Chrome to fix issues with compiled functions:
              // https://code.google.com/p/chromium/issues/detail?id=331655
              var script = document.createElement('script'),
                  head = document.head || document.getElementsByTagName('head')[0];
              // Add a new-line before the code on Firefox since the error
              // messages appear to be aligned to line number 0...
              if (agent.firefox)
                  code = '\n' + code;
              script.appendChild(document.createTextNode(
                  'paper._execute = function(' + params + ') {' + code + '\n}'
              ));
              head.appendChild(script);
              func = paper._execute;
              delete paper._execute;
              head.removeChild(script);
          } else {
              func = Function(params, code);
          }
          var res = func.apply(scope, args) || {};
          // Now install the 'global' tool and view handlers, and we're done!
          Base.each(toolHandlers, function(key) {
              var value = res[key];
              if (value)
                  tool[key] = value;
          });
          if (view) {
              if (res.onResize)
                  view.setOnResize(res.onResize);
              // Emit resize event directly, so any user
              // defined resize handlers are called.
              view.emit('resize', {
                  size: view.size,
                  delta: new Point()
              });
              if (res.onFrame)
                  view.setOnFrame(res.onFrame);
              // Automatically request an update at the end. This is only needed
              // if the script does not actually produce anything yet, and the
              // used canvas contains previous content.
              view.requestUpdate();
          }
          return compiled;
      }
  
      function loadScript(script) {
          // Only load this script if it not loaded already.
          // Support both text/paperscript and text/x-paperscript:
          if (/^text\/(?:x-|)paperscript$/.test(script.type)
                  && PaperScope.getAttribute(script, 'ignore') !== 'true') {
              // Produce a new PaperScope for this script now. Scopes are cheap so
              // let's not worry about the initial one that was already created.
              // Define an id for each PaperScript, so its scope can be retrieved
              // through PaperScope.get().
              // If a canvas id is provided, pass it on to the PaperScope so a
              // project is created for it now.
              var canvasId = PaperScope.getAttribute(script, 'canvas'),
                  canvas = document.getElementById(canvasId),
                  // To avoid possible duplicate browser requests for PaperScript
                  // files, support the data-src attribute as well as src:
                  // TODO: Consider switching from data-paper- to data- prefix
                  // in PaperScope.getAttribute() and use it here too:
                  src = script.src || script.getAttribute('data-src'),
                  async = PaperScope.hasAttribute(script, 'async'),
                  scopeAttribute = 'data-paper-scope';
              if (!canvas)
                  throw new Error('Unable to find canvas with id "'
                          + canvasId + '"');
              // See if there already is a scope for this canvas and reuse it, to
              // support multiple scripts per canvas. Otherwise create a new one.
              var scope = PaperScope.get(canvas.getAttribute(scopeAttribute))
                          || new PaperScope().setup(canvas);
              // Link the element to this scope, so we can reuse the scope when
              // compiling multiple scripts for the same element.
              canvas.setAttribute(scopeAttribute, scope._id);
              if (src) {
                  // If we're loading from a source, request the source
                  // synchronously to guarantee code is executed in the
                  // same order the script tags appear.
                  // If the async attribute is specified on the script element,
                  // request the source asynchronously and execute as soon as
                  // it is retrieved.
                  Http.request({
                      url: src,
                      async: async,
                      mimeType: 'text/plain',
                      onLoad: function(code) {
                          execute(code, scope, src);
                      }
                  });
              } else {
                  // We can simply get the code form the script tag.
                  execute(script.innerHTML, scope, script.baseURI);
              }
              // Mark script as loaded now.
              script.setAttribute('data-paper-ignore', 'true');
              return scope;
          }
      }
  
      function loadAll() {
          Base.each(document && document.getElementsByTagName('script'),
                  loadScript);
      }
  
     /**
       * Loads, compiles and executes PaperScript code in the HTML document. Note
       * that this method is executed automatically for all scripts in the
       * document through a window load event. You can optionally call it earlier
       * (e.g. from a DOM ready event), or you can mark scripts to be ignored by
       * setting the attribute `ignore="true"` or `data-paper-ignore="true"`, and
       * call the `PaperScript.load(script)` method for each script separately
       * when needed.
       *
       * @name PaperScript.load
       * @function
       * @param {HTMLScriptElement} [script=null] the script to load. If none is
       *     provided, all scripts of the HTML document are iterated over and
       *     loaded
       * @return {PaperScope} the scope produced for the passed `script`, or
       *     `undefined` of multiple scripts area loaded
       */
      function load(script) {
          return script ? loadScript(script) : loadAll();
      }
  
      if (window) {
          // Catch cases where paper.js is loaded after the browser event has
          // already occurred.
          if (document.readyState === 'complete') {
              // Handle it asynchronously
              setTimeout(loadAll);
          } else {
              DomEvent.add(window, { load: loadAll });
          }
      }
  
      return {
          compile: compile,
          execute: execute,
          load: load,
          parse: parse
      };
  // Pass on `this` as the binding object, so we can reference Acorn both in
  // development and in the built library.
  }.call(this);
  