function bootstrap(element, modules, config) {
  if (!isObject(config)) config = {};
  var defaultConfig = {
    strictDi: false
  };
  config = extend(defaultConfig, config);
  var doBootstrap = function() {
    element = jqLite(element);

    if (element.injector()) {
      var tag = (element[0] === window.document) ? 'document' : startingTag(element);
      // Encode angle brackets to prevent input from being sanitized to empty string #8683.
      throw ngMinErr(
          'btstrpd',
          'App already bootstrapped with this element \'{0}\'',
          tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
    }

    modules = modules || [];
    modules.unshift(['$provide', function($provide) {
      $provide.value('$rootElement', element);
    }]);

    if (config.debugInfoEnabled) {
      // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
      modules.push(['$compileProvider', function($compileProvider) {
        $compileProvider.debugInfoEnabled(true);
      }]);
    }

    modules.unshift('ng');
    var injector = createInjector(modules, config.strictDi);
    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
       function bootstrapApply(scope, element, compile, injector) {
        scope.$apply(function() {
          element.data('$injector', injector);
          compile(element)(scope);
        });
      }]
    );
    return injector;
  };

  var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;

  if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
    config.debugInfoEnabled = true;
    window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
  }

  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
    return doBootstrap();
  }

  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
  angular.resumeBootstrap = function(extraModules) {
    forEach(extraModules, function(module) {
      modules.push(module);
    });
    return doBootstrap();
  };

  if (isFunction(angular.resumeDeferredBootstrap)) {
    angular.resumeDeferredBootstrap();
  }
}
@ngdoc function
@name angular.bootstrap
@module ng
@description
Use this function to manually start up AngularJS application.

For more information, see the {@link guide/bootstrap Bootstrap guide}.

AngularJS will detect if it has been loaded into the browser more than once and only allow the
first loaded script to be bootstrapped and will report a warning to the browser console for
each of the subsequent scripts. This prevents strange results in applications, where otherwise
multiple instances of AngularJS try to work on the DOM.

<div class="alert alert-warning">
**Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
They must use {@link ng.directive:ngApp ngApp}.
</div>

<div class="alert alert-warning">
**Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
causing animations to stop working and making the injector inaccessible from outside the app.
</div>

```html
<!doctype html>
<html>
<body>
<div ng-controller="WelcomeController">
  {{greeting}}
</div>

<script src="angular.js"></script>
<script>
  var app = angular.module('demo', [])
  .controller('WelcomeController', function($scope) {
      $scope.greeting = 'Welcome!';
  });
  angular.bootstrap(document, ['demo']);
</script>
</body>
</html>
```

@param {DOMElement} element DOM element which is the root of AngularJS application.
@param {Array<String|Function|Array>=} modules an array of modules to load into the application.
    Each item in the array should be the name of a predefined module or a (DI annotated)
    function that will be invoked by the injector as a `config` block.
    See: {@link angular.module modules}
@param {Object=} config an object for defining configuration options for the application. The
    following keys are supported:

* `strictDi` - disable automatic function annotation for the application. This is meant to
  assist in finding bugs which break minified code. Defaults to `false`.

@returns {auto.$injector} Returns the newly created injector for this app.