text: /**
   * Copyright 2013-2015, Facebook, Inc.
   * All rights reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree. An additional grant
   * of patent rights can be found in the PATENTS file in the same directory.
   */
  /* jslint evil: true */
  /*eslint-disable no-eval */
  /*eslint-disable block-scoped-var */
  
  'use strict';
  
  var jstransform = require('jstransform/simple');
  
  var headEl;
  var dummyAnchor;
  var inlineScriptCount = 0;
  
  // The source-map library relies on Object.defineProperty, but IE8 doesn't
  // support it fully even with es5-sham. Indeed, es5-sham's defineProperty
  // throws when Object.prototype.__defineGetter__ is missing, so we skip building
  // the source map in that case.
  var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
  
  /**
   * Run provided code through jstransform.
   *
   * @param {string} source Original source code
   * @param {object?} options Options to pass to jstransform
   * @return {object} object as returned from jstransform
   */
  function transformReact(source, options) {
    options = options || {};
  
    // Always enable the React transforms.
    options.react = true;
  
    // Force the sourcemaps option manually. We don't want to use it if it will
    // break (see above note about supportsAccessors). We'll only override the
    // value here if sourceMap was specified and is truthy. This guarantees that
    // we won't override any user intent (since this method is exposed publicly).
    if (options.sourceMap) {
      options.sourceMap = supportsAccessors;
    }
  
    // Otherwise just pass all options straight through to react-tools.
    return jstransform.transform(source, options);
  }
  
  /**
   * Eval provided source after transforming it.
   *
   * @param {string} source Original source code
   * @param {object?} options Options to pass to jstransform
   */
  function exec(source, options) {
    return eval(transformReact(source, options).code);
  }
  
  /**
   * This method returns a nicely formated line of code pointing to the exact
   * location of the error `e`. The line is limited in size so big lines of code
   * are also shown in a readable way.
   *
   * Example:
   * ... x', overflow:'scroll'}} id={} onScroll={this.scroll} class=" ...
   * ^
   *
   * @param {string} code The full string of code
   * @param {Error} e The error being thrown
   * @return {string} formatted message
   * @internal
   */
  function createSourceCodeErrorMessage(code, e) {
    var sourceLines = code.split('\n');
    // e.lineNumber is non-standard so we can't depend on its availability. If
    // we're in a browser where it isn't supported, don't even bother trying to
    // format anything. We may also hit a case where the line number is reported
    // incorrectly and is outside the bounds of the actual code. Handle that too.
    if (!e.lineNumber || e.lineNumber > sourceLines.length) {
      return '';
    }
    var erroneousLine = sourceLines[e.lineNumber - 1];
  
    // Removes any leading indenting spaces and gets the number of
    // chars indenting the `erroneousLine`
    var indentation = 0;
    erroneousLine = erroneousLine.replace(/^\s+/, function(leadingSpaces) {
      indentation = leadingSpaces.length;
      return '';
    });
  
    // Defines the number of characters that are going to show
    // before and after the erroneous code
    var LIMIT = 30;
    var errorColumn = e.column - indentation;
  
    if (errorColumn > LIMIT) {
      erroneousLine = '... ' + erroneousLine.slice(errorColumn - LIMIT);
      errorColumn = 4 + LIMIT;
    }
    if (erroneousLine.length - errorColumn > LIMIT) {
      erroneousLine = erroneousLine.slice(0, errorColumn + LIMIT) + ' ...';
    }
    var message = '\n\n' + erroneousLine + '\n';
    message += new Array(errorColumn - 1).join(' ') + '^';
    return message;
  }
  
  /**
   * Actually transform the code.
   *
   * @param {string} code
   * @param {string?} url
   * @param {object?} options
   * @return {string} The transformed code.
   * @internal
   */
  function transformCode(code, url, options) {
    try {
      return transformReact(code, options).code;
    } catch(e) {
      e.message += '\n    at ';
      if (url) {
        if ('fileName' in e) {
          // We set `fileName` if it's supported by this error object and
          // a `url` was provided.
          // The error will correctly point to `url` in Firefox.
          e.fileName = url;
        }
        e.message += url + ':' + e.lineNumber + ':' + e.columnNumber;
      } else {
        e.message += location.href;
      }
      e.message += createSourceCodeErrorMessage(code, e);
      throw e;
    }
  }
  
  
  /**
   * Appends a script element at the end of the <head> with the content of code,
   * after transforming it.
   *
   * @param {string} code The original source code
   * @param {string?} url Where the code came from. null if inline
   * @param {object?} options Options to pass to jstransform
   * @internal
   */
  function run(code, url, options) {
    var scriptEl = document.createElement('script');
    scriptEl.text = transformCode(code, url, options);
    headEl.appendChild(scriptEl);
  }
  
  /**
   * Load script from the provided url and pass the content to the callback.
   *
   * @param {string} url The location of the script src
   * @param {function} successCallback Function to call with the content of url
   * @param {function} errorCallback Function to call if error
   * @internal
   */
  function load(url, successCallback, errorCallback) {
    var xhr;
    xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP')
                               : new XMLHttpRequest();
  
    // async, however scripts will be executed in the order they are in the
    // DOM to mirror normal script loading.
    xhr.open('GET', url, true);
    if ('overrideMimeType' in xhr) {
      xhr.overrideMimeType('text/plain');
    }
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        if (xhr.status === 0 || xhr.status === 200) {
          successCallback(xhr.responseText);
        } else {
          errorCallback();
          throw new Error('Could not load ' + url);
        }
      }
    };
    return xhr.send(null);
  }
  
  /**
   * Loop over provided script tags and get the content, via innerHTML if an
   * inline script, or by using XHR. Transforms are applied if needed. The scripts
   * are executed in the order they are found on the page.
   *
   * @param {array} scripts The <script> elements to load and run.
   * @internal
   */
  function loadScripts(scripts) {
    var result = [];
    var count = scripts.length;
  
    function check() {
      var script, i;
  
      for (i = 0; i < count; i++) {
        script = result[i];
  
        if (script.loaded && !script.executed) {
          script.executed = true;
          run(script.content, script.url, script.options);
        } else if (!script.loaded && !script.error && !script.async) {
          break;
        }
      }
    }
  
    scripts.forEach(function(script, i) {
      // Determine the filename to use for the sourcemap.
      var sourceFilename;
      if (script.src == null) {
        sourceFilename = 'Inline JSX script';
        inlineScriptCount++;
        if (inlineScriptCount > 1) {
          sourceFilename += ' (' + inlineScriptCount + ')';
        }
      } else if (dummyAnchor) {
        // Firefox has problems when the sourcemap sourceFilename is a proper URL
        // with a protocol and hostname, so use the pathname. We could use just
        // the filename, but hopefully using the full path will prevent potential
        // issues where the same filename exists in multiple directories.
        dummyAnchor.href = script.src;
        sourceFilename = dummyAnchor.pathname.substr(1);
      }
  
      var options = {
        sourceMapInline: true,
        sourceFilename: sourceFilename,
      };
      if (/;harmony=true(;|$)/.test(script.type)) {
        options.harmony = true;
      }
      if (/;stripTypes=true(;|$)/.test(script.type)) {
        options.stripTypes = true;
      }
  
      // script.async is always true for non-javascript script tags
      var async = script.hasAttribute('async');
  
      if (script.src) {
        result[i] = {
          async: async,
          error: false,
          executed: false,
          content: null,
          loaded: false,
          url: script.src,
          options: options,
        };
  
        load(script.src, function(content) {
          result[i].loaded = true;
          result[i].content = content;
          check();
        }, function() {
          result[i].error = true;
          check();
        });
      } else {
        result[i] = {
          async: async,
          error: false,
          executed: false,
          content: script.innerHTML,
          loaded: true,
          url: null,
          options: options,
        };
      }
    });
  
    check();
  }
  
  /**
   * Find and run all script tags with type="text/jsx".
   *
   * @internal
   */
  function runScripts() {
    var scripts = document.getElementsByTagName('script');
  
    // Array.prototype.slice cannot be used on NodeList on IE8
    var jsxScripts = [];
    for (var i = 0; i < scripts.length; i++) {
      if (/^text\/jsx(;|$)/.test(scripts.item(i).type)) {
        jsxScripts.push(scripts.item(i));
      }
    }
  
    if (jsxScripts.length < 1) {
      return;
    }
  
    console.warn(
      'You are using the in-browser JSX transformer. Be sure to precompile ' +
      'your JSX for production - ' +
      'http://facebook.github.io/react/docs/tooling-integration.html#jsx'
    );
  
    loadScripts(jsxScripts);
  }
  
  // Listen for load event if we're in a browser and then kick off finding and
  // running of scripts.
  if (typeof window !== 'undefined' && window !== null) {
    headEl = document.getElementsByTagName('head')[0];
    dummyAnchor = document.createElement('a');
  
    if (window.addEventListener) {
      window.addEventListener('DOMContentLoaded', runScripts, false);
    } else {
      window.attachEvent('onload', runScripts);
    }
  }
  
  module.exports = {
    transform: transformReact,
    exec: exec,
  };
  