if (window[{{jsonpFunction}}]) {
  throw new Error('Duplicate bootstrap defined');
}

// install a JSONP callback for chunk loading
{{!
  Derived from:
  https://github.com/webpack/webpack/blob/master/lib/JsonpMainTemplatePlugin.js

  MIT License http://www.opensource.org/licenses/mit-license.php
  Author Tobias Koppers @sokra
}}
function __webpack_components__(componentName, chunkIds, chunkDeps, moreModules) {
  // Ensure that the entry chunk is loaded before we do anything
  loadComponent(componentName, function(component) {
    component.ec/*ensureComponent*/(chunkDeps, function() {
      var moduleId, chunkId, i = 0, callbacks = [];

      // add "moreModules" to the modules object,
      // then flag all "chunkIds" as loaded and fire callback
      for (; i < chunkIds.length; i++) {
        chunkId = chunkIds[i];

        // Queue any pending callbacks and then mark as loaded
        callbacks.push.apply(callbacks, component.ic/*installedChunks*/[chunkId] || []);
        component.ic/*installedChunks*/[chunkId] = 0;
      }
      for (moduleId in moreModules) {
        component.m[moduleId] = moreModules[moduleId];
      }

      // If we have the component entry module, then run it
      if (moreModules[0]) {
        component(0);
      }

      while (callbacks.length) {
        callbacks.shift().call(null, component);
      }
    });
  }, !chunkIds[0]);
};
window[{{jsonpFunction}}] = __webpack_components__;

// Expose for test init
__webpack_components__.n = componentNames;

var installedComponents = __webpack_components__.c = {},
    cssSheets = {},

    jsPaths = {{jsChunkNames}};

// Exposing for testing/debugging purposes.
__webpack_components__.ex = moduleExports;

var isArray = Array.isArray || function(arg) {
  return Object.prototype.toString.call(arg) === '[object Array]';
};

function resolveUrl(url) {
  // Relative URLs should honor the path prefix
  if (!/(^\/)|\/\//.test(url)) {
    url = (__webpack_components__.p || '') + url;
  }
  return url;
}

// loadScript
function loadScript(src, fileId, componentName, reload) {
  fileId = componentName + '_' + fileId;
  {{#if fruitLoops}}
    FruitLoops.loadInContext(src);
    $('body').append('<script type="text/javascript" type="utf-8" src="' + resolveUrl(src) + '"'
          + ' data-circus-jsid="' + fileId + '">');
  {{else}}
    var script = document.querySelector('[data-circus-jsid="' + fileId + '"]');
    if (script) {
      if (reload) {
        script.parentNode.removeChild(script);
      } else {
        return;
      }
    }

    // Load the actual script
    var head = document.getElementsByTagName('head')[0];
    script = document.createElement('script');
    script.type = 'text/javascript';
    script.charset = 'utf-8';
    script.src = resolveUrl(src);
    script.setAttribute('data-circus-jsid', fileId);
    head.appendChild(script);
  {{/if}}
}


function lookupChunkId(componentName, chunkId, moduleId) {
  var exports = moduleExports[componentName],
      chunks = moduleChunks[componentName];

  if (chunks === true) {
    return 0;
  } else if (exports[chunkId] != null) {
    moduleId = exports[chunkId];
  }
  if (chunks[moduleId] != null) {
    chunkId = chunks[moduleId];
  }
  return chunkId;
}

// Retrieves a currently loaded external module.
function linkComponent(componentName, module) {
  var component = installedComponents[componentName];

  if (!component || !component.call) {
    throw new Error('Component "' + componentName + '" required but not loaded');
  }

  return component(module);
}

// ensureComponent
function ensureComponent(componentName, id, callback) {
  // Allow array inputs.
  if (id.length === 0) {
    setTimeout(callback, 0);
    return;
  } else if (isArray(id)) {
    var run = 0;
    for (var i = 0, len = id.length; i < len; i++) {
      ensureComponent(componentName, id[i], function() {
        if (++run === len) {
          callback();
        }
      });
    }
    return;
  }

  var module = linkedModules[componentName][id],
      componentId = module[0]/*component*/,
      componentName = componentNames[componentId];

  loadComponent(componentName, function(component) {
    // Once the component is loaded, then ensure that the necessary chunks are
    // loaded as well.
    if (component && component.e) {
      component.e/*nsure*/(lookupChunkId(componentName, undefined, module[1]/*id*/), callback);
    } else {
      // Or we have a component that consists of only one chunk
      callback();
    }
  });
}

function ensureChunk(requireFn, componentName, chunkId, callback) {
  chunkId = lookupChunkId(componentName, chunkId);

  var installed = requireFn.ic/*installedChunks*/;
  if (installed[chunkId] === 0) {
    return callback.call(null, requireFn);
  }

  var scriptName = jsPaths[componentName][chunkId];

  // an array means "currently loading".
  if(installed[chunkId] !== undefined) {
    installed[chunkId].push(callback);
  } else {
    // Script is either inlined in the bootstrop or will be loaded in the next step
    installed[chunkId] = [callback];

    if (scriptName) {
      // start chunk loading
      loadScript(scriptName, chunkId, componentName);
    }
  }
}

function require(requireFn, componentName, moduleId) {
  var exports = moduleExports[componentName];
  if (exports[moduleId] != null) {
    moduleId = exports[moduleId];
  }
  var installedModules = requireFn.im/*installedModules*/;

  // Check if module is in cache
  if (installedModules[moduleId]) {
    return installedModules[moduleId].exports;
  }

  // Create a new module (and put it into the cache)
  var module = installedModules[moduleId] = {
    {{moduleObject}}
    exports: {},
    id: moduleId,
    loaded: false
  };

  // Execute the module function
  requireFn.m[moduleId].call(module.exports, module, module.exports, {{moduleRequire}});

  // Flag the module as loaded
  module.loaded = true;

  // Return the exports of the module
  return module.exports;
}


// Component loading: Loads the entry point for a particular component, which can
// then load any necessary chunks and other required components.
function loadComponent(componentName, callback, entryLoading) {
  var component = installedComponents[componentName];
  if (component) {
    return callback(component);
  }

  function requireFn(moduleId) {
    return require(requireFn, componentName, moduleId);
  }
  requireFn.name = componentName;
  requireFn.p/*ath*/ = __webpack_components__.p;
  requireFn.m/*odules*/ = [];
  requireFn.ic/*installedChunks*/ = {};
  requireFn.im/*installedModules*/ = {};

  requireFn.ru/*resolveUrl*/ = resolveUrl;

  // Extend the require function with our implementation details
  {{#if includeCssLoader}}
    // Expose the css loader
    requireFn.cs = function(chunkId) {
      cssLoader(componentName, chunkId);
    };
  {{/if}}

  requireFn.e/*nsure*/ = function(chunkId, callback) {
    ensureChunk(requireFn, componentName, chunkId, callback);
  };

  if (componentNames.length > 1) {
    // Retrieves a currently loaded external module.
    requireFn.l/*ink*/ = function(id) {
      var module = linkedModules[componentName][id];
      return linkComponent(componentNames[module[0]/*component*/], module[1]/*id*/);
    };

    // Loads the external component hosting a given module.
    requireFn.ec/*ensureComponent*/ = function(id, callback) {
      ensureComponent(componentName, id, callback);
    };
  } else {
    requireFn.ec/*ensureComponent*/ = function(id, callback) {
      // Stub to simplify upstream handling.
      callback();
    };
  }

  {{requireExtensions}}

  // We create this immediately. All callers should utilize the component.e method to
  // make sure that they wait until the component is functionally loaded.
  installedComponents[componentName] = requireFn;

  if (entryLoading) {
    callback(requireFn);
  } else {
    requireFn.e(0, function() {
      callback(requireFn);
    });
  }
}
__webpack_components__.lc = loadComponent;

{{#if includeCssLoader}}
var cssPaths = {{cssChunkNames}};

function cssLoader(componentName, chunkId) {
  var fileId = componentName + '_' + chunkId,
      path = cssPaths[componentName][chunkId];

  if (cssSheets[fileId] || !path) {
    return cssSheets[fileId];
  }

  {{#if fruitLoops}}
    cssSheets[fileId] = $('head').append('<link rel="stylesheet" href="' + resolveUrl(path) + '" data-circus-cssid="' + fileId + '">');
  {{else}}
    cssSheets[fileId] = document.querySelector('[data-circus-cssid="' + fileId + '"]');

    if (!cssSheets[fileId]) {
      var styleElement = cssSheets[fileId] = document.createElement('link');
      styleElement.rel = 'stylesheet';
      styleElement.type = 'text/css';
      styleElement.href = resolveUrl(path);
      styleElement.setAttribute('data-circus-cssid', fileId);

      var head = document.getElementsByTagName('head')[0];
      head.appendChild(styleElement);
    }

    return cssSheets[fileId];
  {{/if}}
}
{{/if}}


// Via http://dustindiaz.com/smallest-domready-ever
function ready(callback) {
  var readyState = document.readyState;
  if (readyState === 'uninitialized' || readyState === 'loading') {
    setTimeout(function() { ready(callback); }, 9);
  } else {
    callback();
  }
}
