text: function readMemberExpression(p, value) {
    var pParts = p.split('.');
    while (pParts.length)
      value = value[pParts.shift()];
    return value;
  }
  
  function getMapMatch(map, name) {
    var bestMatch, bestMatchLength = 0;
  
    for (var p in map) {
      if (name.substr(0, p.length) == p && (name.length == p.length || name[p.length] == '/')) {
        var curMatchLength = p.split('/').length;
        if (curMatchLength <= bestMatchLength)
          continue;
        bestMatch = p;
        bestMatchLength = curMatchLength;
      }
    }
  
    return bestMatch;
  }
  
  function prepareBaseURL(loader) {
    // ensure baseURl is fully normalized
    if (this._loader.baseURL !== this.baseURL) {
      if (this.baseURL[this.baseURL.length - 1] != '/')
        this.baseURL += '/';
  
      this._loader.baseURL = this.baseURL = new URL(this.baseURL, baseURIObj).href;
    }
  }
  
  var envModule;
  function setProduction(isProduction, isBuilder) {
    this.set('@system-env', envModule = this.newModule({
      browser: isBrowser,
      node: !!this._nodeRequire,
      production: !isBuilder && isProduction,
      dev: isBuilder || !isProduction,
      build: isBuilder,
      'default': true
    }));
  }
  
  hookConstructor(function(constructor) {
    return function() {
      constructor.call(this);
  
      // support baseURL
      this.baseURL = baseURI;
  
      // support map and paths
      this.map = {};
  
      // make the location of the system.js script accessible
      if (typeof $__curScript != 'undefined')
        this.scriptSrc = $__curScript.src;
  
      // global behaviour flags
      this.warnings = false;
      this.defaultJSExtensions = false;
      this.pluginFirst = false;
      this.loaderErrorStack = false;
  
      // by default load ".json" files as json
      // leading * meta doesn't need normalization
      // NB add this in next breaking release
      // this.meta['*.json'] = { format: 'json' };
  
      // support the empty module, as a concept
      this.set('@empty', this.newModule({}));
  
      setProduction.call(this, false, false);
    };
  });
  
  // include the node require since we're overriding it
  if (typeof require != 'undefined' && typeof process != 'undefined' && !process.browser)
    SystemJSLoader.prototype._nodeRequire = require;
  
  /*
    Core SystemJS Normalization
  
    If a name is relative, we apply URL normalization to the page
    If a name is an absolute URL, we leave it as-is
  
    Plain names (neither of the above) run through the map and paths
    normalization phases.
  
    The paths normalization phase applies last (paths extension), which
    defines the `decanonicalize` function and normalizes everything into
    a URL.
   */
  
  var parentModuleContext;
  function getNodeModule(name, baseURL) {
    if (!isPlain(name))
      throw new Error('Node module ' + name + ' can\'t be loaded as it is not a package require.');
  
    if (!parentModuleContext) {
      var Module = this._nodeRequire('module');
      var base = decodeURI(baseURL.substr(isWindows ? 8 : 7));
      parentModuleContext = new Module(base);
      parentModuleContext.paths = Module._nodeModulePaths(base);
    }
    return parentModuleContext.require(name);
  }
  
  function coreResolve(name, parentName) {
    // standard URL resolution
    if (isRel(name))
      return urlResolve(name, parentName);
    else if (isAbsolute(name))
      return name;
  
    // plain names not starting with './', '://' and '/' go through custom resolution
    var mapMatch = getMapMatch(this.map, name);
  
    if (mapMatch) {
      name = this.map[mapMatch] + name.substr(mapMatch.length);
  
      if (isRel(name))
        return urlResolve(name);
      else if (isAbsolute(name))
        return name;
    }
  
    if (this.has(name))
      return name;
  
    // dynamically load node-core modules when requiring `@node/fs` for example
    if (name.substr(0, 6) == '@node/') {
      if (!this._nodeRequire)
        throw new TypeError('Error loading ' + name + '. Can only load node core modules in Node.');
      if (this.builder)
        this.set(name, this.newModule({}));
      else
        this.set(name, this.newModule(getESModule(getNodeModule.call(this, name.substr(6), this.baseURL))));
      return name;
    }
  
    // prepare the baseURL to ensure it is normalized
    prepareBaseURL.call(this);
  
    return applyPaths(this, name) || this.baseURL + name;
  }
  
  hook('normalize', function(normalize) {
    return function(name, parentName, skipExt) {
      var resolved = coreResolve.call(this, name, parentName);
      if (this.defaultJSExtensions && !skipExt && resolved.substr(resolved.length - 3, 3) != '.js' && !isPlain(resolved))
        resolved += '.js';
      return resolved;
    };
  });
  
  // percent encode just '#' in urls if using HTTP requests
  var httpRequest = typeof XMLHttpRequest != 'undefined';
  hook('locate', function(locate) {
    return function(load) {
      return Promise.resolve(locate.call(this, load))
      .then(function(address) {
        if (httpRequest)
          return address.replace(/#/g, '%23');
        return address;
      });
    };
  });
  
  /*
   * Fetch with authorization
   */
  hook('fetch', function() {
    return function(load) {
      return new Promise(function(resolve, reject) {
        fetchTextFromURL(load.address, load.metadata.authorization, resolve, reject);
      });
    };
  });
  
  /*
    __useDefault
  
    When a module object looks like:
    newModule(
      __useDefault: true,
      default: 'some-module'
    })
  
    Then importing that module provides the 'some-module'
    result directly instead of the full module.
  
    Useful for eg module.exports = function() {}
  */
  hook('import', function(systemImport) {
    return function(name, parentName, parentAddress) {
      if (parentName && parentName.name)
        warn.call(this, 'SystemJS.import(name, { name: parentName }) is deprecated for SystemJS.import(name, parentName), while importing ' + name + ' from ' + parentName.name);
      return systemImport.call(this, name, parentName, parentAddress).then(function(module) {
        return module.__useDefault ? module['default'] : module;
      });
    };
  });
  
  /*
   * Allow format: 'detect' meta to enable format detection
   */
  hook('translate', function(systemTranslate) {
    return function(load) {
      if (load.metadata.format == 'detect')
        load.metadata.format = undefined;
      return systemTranslate.apply(this, arguments);
    };
  });
  
  
  /*
   * JSON format support
   *
   * Supports loading JSON files as a module format itself
   *
   * Usage:
   *
   * SystemJS.config({
   *   meta: {
   *     '*.json': { format: 'json' }
   *   }
   * });
   *
   * Module is returned as if written:
   *
   * export default {JSON}
   *
   * No named exports are provided
   *
   * Files ending in ".json" are treated as json automatically by SystemJS
   */
  hook('instantiate', function(instantiate) {
    return function(load) {
      if (load.metadata.format == 'json' && !this.builder) {
        var entry = load.metadata.entry = createEntry();
        entry.deps = [];
        entry.execute = function() {
          try {
            return JSON.parse(load.source);
          }
          catch(e) {
            throw new Error("Invalid JSON file " + load.name);
          }
        };
      }
    };
  })
  
  /*
   Extend config merging one deep only
  
    loader.config({
      some: 'random',
      config: 'here',
      deep: {
        config: { too: 'too' }
      }
    });
  
    <=>
  
    loader.some = 'random';
    loader.config = 'here'
    loader.deep = loader.deep || {};
    loader.deep.config = { too: 'too' };
  
  
    Normalizes meta and package configs allowing for:
  
    SystemJS.config({
      meta: {
        './index.js': {}
      }
    });
  
    To become
  
    SystemJS.meta['https://thissite.com/index.js'] = {};
  
    For easy normalization canonicalization with latest URL support.
  
  */
  function envSet(loader, cfg, envCallback) {
    if (envModule.browser && cfg.browserConfig)
      envCallback(cfg.browserConfig);
    if (envModule.node && cfg.nodeConfig)
      envCallback(cfg.nodeConfig);
    if (envModule.dev && cfg.devConfig)
      envCallback(cfg.devConfig);
    if (envModule.build && cfg.buildConfig)
      envCallback(cfg.buildConfig);
    if (envModule.production && cfg.productionConfig)
      envCallback(cfg.productionConfig);
  }
  
  SystemJSLoader.prototype.getConfig = function(name) {
    var cfg = {};
    var loader = this;
    for (var p in loader) {
      if (loader.hasOwnProperty && !loader.hasOwnProperty(p) || p in SystemJSLoader.prototype && p != 'transpiler')
        continue;
      if (indexOf.call(['_loader', 'amdDefine', 'amdRequire', 'defined', 'failed', 'version', 'loads'], p) == -1)
        cfg[p] = loader[p];
    }
    cfg.production = envModule.production;
    return cfg;
  };
  
  var curCurScript;
  SystemJSLoader.prototype.config = function(cfg, isEnvConfig) {
    var loader = this;
  
    if ('loaderErrorStack' in cfg) {
      curCurScript = $__curScript;
      if (cfg.loaderErrorStack)
        $__curScript = undefined;
      else
        $__curScript = curCurScript;
    }
  
    if ('warnings' in cfg)
      loader.warnings = cfg.warnings;
  
    // transpiler deprecation path
    if (cfg.transpilerRuntime === false)
      loader._loader.loadedTranspilerRuntime = true;
  
    if ('production' in cfg || 'build' in cfg)
      setProduction.call(loader, !!cfg.production, !!(cfg.build || envModule && envModule.build));
  
    if (!isEnvConfig) {
      // if using nodeConfig / browserConfig / productionConfig, take baseURL from there
      // these exceptions will be unnecessary when we can properly implement config queuings
      var baseURL;
      envSet(loader, cfg, function(cfg) {
        baseURL = baseURL || cfg.baseURL;
      });
      baseURL = baseURL || cfg.baseURL;
  
      // always configure baseURL first
      if (baseURL) {
        var hasConfig = false;
        function checkHasConfig(obj) {
          for (var p in obj)
            if (obj.hasOwnProperty(p))
              return true;
        }
        if (checkHasConfig(loader.packages) || checkHasConfig(loader.meta) || checkHasConfig(loader.depCache) || checkHasConfig(loader.bundles) || checkHasConfig(loader.packageConfigPaths))
          throw new TypeError('Incorrect configuration order. The baseURL must be configured with the first SystemJS.config call.');
  
        this.baseURL = baseURL;
        prepareBaseURL.call(this);
      }
  
      if (cfg.paths)
        extend(loader.paths, cfg.paths);
  
      envSet(loader, cfg, function(cfg) {
        if (cfg.paths)
          extend(loader.paths, cfg.paths);
      });
  
      // warn on wildcard path deprecations
      if (this.warnings) {
        for (var p in loader.paths)
          if (p.indexOf('*') != -1)
            warn.call(loader, 'Paths configuration "' + p + '" -> "' + loader.paths[p] + '" uses wildcards which are being deprecated for just leaving a trailing "/" to indicate folder paths.');
      }
    }
  
    if (cfg.defaultJSExtensions) {
      loader.defaultJSExtensions = cfg.defaultJSExtensions;
      warn.call(loader, 'The defaultJSExtensions configuration option is deprecated, use packages configuration instead.');
    }
  
    if (cfg.pluginFirst)
      loader.pluginFirst = cfg.pluginFirst;
  
    if (cfg.map) {
      for (var p in cfg.map) {
        var v = cfg.map[p];
  
        // object map backwards-compat into packages configuration
        if (typeof v !== 'string') {
          var defaultJSExtension = loader.defaultJSExtensions && p.substr(p.length - 3, 3) != '.js';
          var prop = loader.decanonicalize(p);
          if (defaultJSExtension && prop.substr(prop.length - 3, 3) == '.js')
            prop = prop.substr(0, prop.length - 3);
  
          // if a package main, revert it
          var pkgMatch = '';
          for (var pkg in loader.packages) {
            if (prop.substr(0, pkg.length) == pkg
                && (!prop[pkg.length] || prop[pkg.length] == '/')
                && pkgMatch.split('/').length < pkg.split('/').length)
              pkgMatch = pkg;
          }
          if (pkgMatch && loader.packages[pkgMatch].main)
            prop = prop.substr(0, prop.length - loader.packages[pkgMatch].main.length - 1);
  
          var pkg = loader.packages[prop] = loader.packages[prop] || {};
          pkg.map = v;
        }
        else {
          loader.map[p] = v;
        }
      }
    }
  
    if (cfg.packageConfigPaths) {
      var packageConfigPaths = [];
      for (var i = 0; i < cfg.packageConfigPaths.length; i++) {
        var path = cfg.packageConfigPaths[i];
        var packageLength = Math.max(path.lastIndexOf('*') + 1, path.lastIndexOf('/'));
        var normalized = coreResolve.call(loader, path.substr(0, packageLength));
        packageConfigPaths[i] = normalized + path.substr(packageLength);
      }
      loader.packageConfigPaths = packageConfigPaths;
    }
  
    if (cfg.bundles) {
      for (var p in cfg.bundles) {
        var bundle = [];
        for (var i = 0; i < cfg.bundles[p].length; i++) {
          var defaultJSExtension = loader.defaultJSExtensions && cfg.bundles[p][i].substr(cfg.bundles[p][i].length - 3, 3) != '.js';
          var normalizedBundleDep = loader.decanonicalize(cfg.bundles[p][i]);
          if (defaultJSExtension && normalizedBundleDep.substr(normalizedBundleDep.length - 3, 3) == '.js')
            normalizedBundleDep = normalizedBundleDep.substr(0, normalizedBundleDep.length - 3);
          bundle.push(normalizedBundleDep);
        }
        loader.bundles[p] = bundle;
      }
    }
  
    if (cfg.packages) {
      for (var p in cfg.packages) {
        if (p.match(/^([^\/]+:)?\/\/$/))
          throw new TypeError('"' + p + '" is not a valid package name.');
  
        var prop = coreResolve.call(loader, p);
  
        // allow trailing slash in packages
        if (prop[prop.length - 1] == '/')
          prop = prop.substr(0, prop.length - 1);
  
        setPkgConfig(loader, prop, cfg.packages[p], false);
      }
    }
  
    for (var c in cfg) {
      var v = cfg[c];
  
      if (indexOf.call(['baseURL', 'map', 'packages', 'bundles', 'paths', 'warnings', 'packageConfigPaths',
            'loaderErrorStack', 'browserConfig', 'nodeConfig', 'devConfig', 'buildConfig', 'productionConfig'], c) != -1)
        continue;
  
      if (typeof v != 'object' || v instanceof Array) {
        loader[c] = v;
      }
      else {
        loader[c] = loader[c] || {};
  
        for (var p in v) {
          // base-level wildcard meta does not normalize to retain catch-all quality
          if (c == 'meta' && p[0] == '*') {
            extend(loader[c][p] = loader[c][p] || {}, v[p]);
          }
          else if (c == 'meta') {
            // meta can go through global map, with defaultJSExtensions adding
            var resolved = coreResolve.call(loader, p);
            if (loader.defaultJSExtensions && resolved.substr(resolved.length - 3, 3) != '.js' && !isPlain(resolved))
              resolved += '.js';
            extend(loader[c][resolved] = loader[c][resolved] || {}, v[p]);
          }
          else if (c == 'depCache') {
            var defaultJSExtension = loader.defaultJSExtensions && p.substr(p.length - 3, 3) != '.js';
            var prop = loader.decanonicalize(p);
            if (defaultJSExtension && prop.substr(prop.length - 3, 3) == '.js')
              prop = prop.substr(0, prop.length - 3);
            loader[c][prop] = [].concat(v[p]);
          }
          else {
            loader[c][p] = v[p];
          }
        }
      }
    }
  
    envSet(loader, cfg, function(cfg) {
      loader.config(cfg, true);
    });
  };
  