@ngdoc function
@name angular.bootstrap
@module ng
@description
Use this function to manually start up angular application.

See: {@link guide/bootstrap Bootstrap}

Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
They must use {@link ng.directive:ngApp ngApp}.

Angular 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 Angular try to work on the DOM.

```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 angular 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 run 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.

@returns {auto.$injector} Returns the newly created injector for this app.
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] === document) ? 'document' : startingTag(element);
      throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
    }

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

  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;

  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);
    });
    doBootstrap();
  };
}