/* esm-bundle - @angular/upgrade@18.2.2 - es format - Use of this source code is governed by an MIT-style license that can be found in the LICENSE file at https://angular.io/license */
import * as i0 from '@angular/core';
import { Version, EventEmitter, Directive, NgZone, Injector, Compiler, NgModule, resolveForwardRef, Inject, ElementRef, Testability, ComponentFactoryResolver, ChangeDetectorRef, TestabilityRegistry, ApplicationRef, SimpleChange } from '@angular/core';
import { __decorate, __metadata } from 'tslib';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

/**
 * @license Angular v18.2.2
 * (c) 2010-2024 Google LLC. https://angular.io/
 * License: MIT
 */


/**
 * @module
 * @description
 * Entry point for all public APIs of the upgrade package.
 */
/**
 * @publicApi
 */
const VERSION = new Version('18.2.2');
function noNg() {
  throw new Error('AngularJS v1.x is not loaded!');
}
const noNgElement = () => noNg();
noNgElement.cleanData = noNg;
let angular = {
  bootstrap: noNg,
  module: noNg,
  element: noNgElement,
  injector: noNg,
  version: undefined,
  resumeBootstrap: noNg,
  getTestability: noNg
};
try {
  if (window.hasOwnProperty('angular')) {
    angular = window.angular;
  }
} catch {
  // ignore in CJS mode.
}
const bootstrap = (e, modules, config) => angular.bootstrap(e, modules, config);
// Do not declare as `module` to avoid webpack bug
// (see https://github.com/angular/angular/issues/30050).
const module_ = (prefix, dependencies) => angular.module(prefix, dependencies);
const element = e => angular.element(e);
element.cleanData = nodes => angular.element.cleanData(nodes);
const $COMPILE = '$compile';
const $CONTROLLER = '$controller';
const $HTTP_BACKEND = '$httpBackend';
const $INJECTOR = '$injector';
const $PARSE = '$parse';
const $ROOT_ELEMENT = '$rootElement';
const $ROOT_SCOPE = '$rootScope';
const $SCOPE = '$scope';
const $TEMPLATE_CACHE = '$templateCache';
const $$TESTABILITY = '$$testability';
const COMPILER_KEY = '$$angularCompiler';
const DOWNGRADED_MODULE_COUNT_KEY = '$$angularDowngradedModuleCount';
const INJECTOR_KEY = '$$angularInjector';
const LAZY_MODULE_REF = '$$angularLazyModuleRef';
const NG_ZONE_KEY = '$$angularNgZone';
const UPGRADE_APP_TYPE_KEY = '$$angularUpgradeAppType';
const REQUIRE_INJECTOR = '?^^' + INJECTOR_KEY;
const REQUIRE_NG_MODEL = '?ngModel';

/**
 * A `PropertyBinding` represents a mapping between a property name
 * and an attribute name. It is parsed from a string of the form
 * `"prop: attr"`; or simply `"propAndAttr" where the property
 * and attribute have the same identifier.
 */
class PropertyBinding {
  constructor(prop, attr) {
    this.prop = prop;
    this.attr = attr;
    this.bracketAttr = `[${this.attr}]`;
    this.parenAttr = `(${this.attr})`;
    this.bracketParenAttr = `[(${this.attr})]`;
    const capitalAttr = this.attr.charAt(0).toUpperCase() + this.attr.slice(1);
    this.onAttr = `on${capitalAttr}`;
    this.bindAttr = `bind${capitalAttr}`;
    this.bindonAttr = `bindon${capitalAttr}`;
  }
}
const DIRECTIVE_PREFIX_REGEXP = /^(?:x|data)[:\-_]/i;
const DIRECTIVE_SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
function onError(e) {
  // TODO: (misko): We seem to not have a stack trace here!
  console.error(e, e.stack);
  throw e;
}
/**
 * Clean the jqLite/jQuery data on the element and all its descendants.
 * Equivalent to how jqLite/jQuery invoke `cleanData()` on an Element when removed:
 *   https://github.com/angular/angular.js/blob/2e72ea13fa98bebf6ed4b5e3c45eaf5f990ed16f/src/jqLite.js#L349-L355
 *   https://github.com/jquery/jquery/blob/6984d1747623dbc5e87fd6c261a5b6b1628c107c/src/manipulation.js#L182
 *
 * NOTE:
 * `cleanData()` will also invoke the AngularJS `$destroy` DOM event on the element:
 *   https://github.com/angular/angular.js/blob/2e72ea13fa98bebf6ed4b5e3c45eaf5f990ed16f/src/Angular.js#L1932-L1945
 *
 * @param node The DOM node whose data needs to be cleaned.
 */
function cleanData(node) {
  element.cleanData([node]);
  if (isParentNode(node)) {
    element.cleanData(node.querySelectorAll('*'));
  }
}
function controllerKey(name) {
  return '$' + name + 'Controller';
}
/**
 * Destroy an AngularJS app given the app `$injector`.
 *
 * NOTE: Destroying an app is not officially supported by AngularJS, but try to do our best by
 *       destroying `$rootScope` and clean the jqLite/jQuery data on `$rootElement` and all
 *       descendants.
 *
 * @param $injector The `$injector` of the AngularJS app to destroy.
 */
function destroyApp($injector) {
  const $rootElement = $injector.get($ROOT_ELEMENT);
  const $rootScope = $injector.get($ROOT_SCOPE);
  $rootScope.$destroy();
  cleanData($rootElement[0]);
}
function directiveNormalize(name) {
  return name.replace(DIRECTIVE_PREFIX_REGEXP, '').replace(DIRECTIVE_SPECIAL_CHARS_REGEXP, (_, letter) => letter.toUpperCase());
}
function getTypeName(type) {
  // Return the name of the type or the first line of its stringified version.
  return type.overriddenName || type.name || type.toString().split('\n')[0];
}
function getDowngradedModuleCount($injector) {
  return $injector.has(DOWNGRADED_MODULE_COUNT_KEY) ? $injector.get(DOWNGRADED_MODULE_COUNT_KEY) : 0;
}
function getUpgradeAppType($injector) {
  return $injector.has(UPGRADE_APP_TYPE_KEY) ? $injector.get(UPGRADE_APP_TYPE_KEY) : 0 /* UpgradeAppType.None */;
}
function isFunction(value) {
  return typeof value === 'function';
}
function isParentNode(node) {
  return isFunction(node.querySelectorAll);
}
function validateInjectionKey($injector, downgradedModule, injectionKey, attemptedAction) {
  const upgradeAppType = getUpgradeAppType($injector);
  const downgradedModuleCount = getDowngradedModuleCount($injector);
  // Check for common errors.
  switch (upgradeAppType) {
    case 1 /* UpgradeAppType.Dynamic */:
    case 2 /* UpgradeAppType.Static */:
      if (downgradedModule) {
        throw new Error(`Error while ${attemptedAction}: 'downgradedModule' unexpectedly specified.\n` + "You should not specify a value for 'downgradedModule', unless you are downgrading " + "more than one Angular module (via 'downgradeModule()').");
      }
      break;
    case 3 /* UpgradeAppType.Lite */:
      if (!downgradedModule && downgradedModuleCount >= 2) {
        throw new Error(`Error while ${attemptedAction}: 'downgradedModule' not specified.\n` + 'This application contains more than one downgraded Angular module, thus you need to ' + "always specify 'downgradedModule' when downgrading components and injectables.");
      }
      if (!$injector.has(injectionKey)) {
        throw new Error(`Error while ${attemptedAction}: Unable to find the specified downgraded module.\n` + 'Did you forget to downgrade an Angular module or include it in the AngularJS ' + 'application?');
      }
      break;
    default:
      throw new Error(`Error while ${attemptedAction}: Not a valid '@angular/upgrade' application.\n` + 'Did you forget to downgrade an Angular module or include it in the AngularJS ' + 'application?');
  }
}
class Deferred {
  constructor() {
    this.promise = new Promise((res, rej) => {
      this.resolve = res;
      this.reject = rej;
    });
  }
}
/**
 * @return Whether the passed-in component implements the subset of the
 *     `ControlValueAccessor` interface needed for AngularJS `ng-model`
 *     compatibility.
 */
function supportsNgModel(component) {
  return typeof component.writeValue === 'function' && typeof component.registerOnChange === 'function';
}
/**
 * Glue the AngularJS `NgModelController` (if it exists) to the component
 * (if it implements the needed subset of the `ControlValueAccessor` interface).
 */
function hookupNgModel(ngModel, component) {
  if (ngModel && supportsNgModel(component)) {
    ngModel.$render = () => {
      component.writeValue(ngModel.$viewValue);
    };
    component.registerOnChange(ngModel.$setViewValue.bind(ngModel));
    if (typeof component.registerOnTouched === 'function') {
      component.registerOnTouched(ngModel.$setTouched.bind(ngModel));
    }
  }
}
/**
 * Test two values for strict equality, accounting for the fact that `NaN !== NaN`.
 */
function strictEquals(val1, val2) {
  return val1 === val2 || val1 !== val1 && val2 !== val2;
}
const INITIAL_VALUE$1 = {
  __UNINITIALIZED__: true
};
class DowngradeComponentAdapter {
  constructor(element, attrs, scope, ngModel, parentInjector, $compile, $parse, componentFactory, wrapCallback) {
    this.element = element;
    this.attrs = attrs;
    this.scope = scope;
    this.ngModel = ngModel;
    this.parentInjector = parentInjector;
    this.$compile = $compile;
    this.$parse = $parse;
    this.componentFactory = componentFactory;
    this.wrapCallback = wrapCallback;
    this.implementsOnChanges = false;
    this.inputChangeCount = 0;
    this.inputChanges = {};
    this.componentScope = scope.$new();
  }
  compileContents() {
    const compiledProjectableNodes = [];
    const projectableNodes = this.groupProjectableNodes();
    const linkFns = projectableNodes.map(nodes => this.$compile(nodes));
    this.element.empty();
    linkFns.forEach(linkFn => {
      linkFn(this.scope, clone => {
        compiledProjectableNodes.push(clone);
        this.element.append(clone);
      });
    });
    return compiledProjectableNodes;
  }
  createComponentAndSetup(projectableNodes, manuallyAttachView = false, propagateDigest = true) {
    const component = this.createComponent(projectableNodes);
    this.setupInputs(manuallyAttachView, propagateDigest, component);
    this.setupOutputs(component.componentRef);
    this.registerCleanup(component.componentRef);
    return component.componentRef;
  }
  createComponent(projectableNodes) {
    const providers = [{
      provide: $SCOPE,
      useValue: this.componentScope
    }];
    const childInjector = Injector.create({
      providers: providers,
      parent: this.parentInjector,
      name: 'DowngradeComponentAdapter'
    });
    const componentRef = this.componentFactory.create(childInjector, projectableNodes, this.element[0]);
    const viewChangeDetector = componentRef.injector.get(ChangeDetectorRef);
    const changeDetector = componentRef.changeDetectorRef;
    // testability hook is commonly added during component bootstrap in
    // packages/core/src/application_ref.bootstrap()
    // in downgraded application, component creation will take place here as well as adding the
    // testability hook.
    const testability = componentRef.injector.get(Testability, null);
    if (testability) {
      componentRef.injector.get(TestabilityRegistry).registerApplication(componentRef.location.nativeElement, testability);
    }
    hookupNgModel(this.ngModel, componentRef.instance);
    return {
      viewChangeDetector,
      componentRef,
      changeDetector
    };
  }
  setupInputs(manuallyAttachView, propagateDigest = true, {
    componentRef,
    changeDetector,
    viewChangeDetector
  }) {
    const attrs = this.attrs;
    const inputs = this.componentFactory.inputs || [];
    for (const input of inputs) {
      const inputBinding = new PropertyBinding(input.propName, input.templateName);
      let expr = null;
      if (attrs.hasOwnProperty(inputBinding.attr)) {
        const observeFn = (prop => {
          let prevValue = INITIAL_VALUE$1;
          return currValue => {
            // Initially, both `$observe()` and `$watch()` will call this function.
            if (!strictEquals(prevValue, currValue)) {
              if (prevValue === INITIAL_VALUE$1) {
                prevValue = currValue;
              }
              this.updateInput(componentRef, prop, prevValue, currValue);
              prevValue = currValue;
            }
          };
        })(inputBinding.prop);
        attrs.$observe(inputBinding.attr, observeFn);
        // Use `$watch()` (in addition to `$observe()`) in order to initialize the input in time
        // for `ngOnChanges()`. This is necessary if we are already in a `$digest`, which means that
        // `ngOnChanges()` (which is called by a watcher) will run before the `$observe()` callback.
        let unwatch = this.componentScope.$watch(() => {
          unwatch();
          unwatch = null;
          observeFn(attrs[inputBinding.attr]);
        });
      } else if (attrs.hasOwnProperty(inputBinding.bindAttr)) {
        expr = attrs[inputBinding.bindAttr];
      } else if (attrs.hasOwnProperty(inputBinding.bracketAttr)) {
        expr = attrs[inputBinding.bracketAttr];
      } else if (attrs.hasOwnProperty(inputBinding.bindonAttr)) {
        expr = attrs[inputBinding.bindonAttr];
      } else if (attrs.hasOwnProperty(inputBinding.bracketParenAttr)) {
        expr = attrs[inputBinding.bracketParenAttr];
      }
      if (expr != null) {
        const watchFn = (prop => (currValue, prevValue) => this.updateInput(componentRef, prop, prevValue, currValue))(inputBinding.prop);
        this.componentScope.$watch(expr, watchFn);
      }
    }
    // Invoke `ngOnChanges()` and Change Detection (when necessary)
    const detectChanges = () => changeDetector.detectChanges();
    const prototype = this.componentFactory.componentType.prototype;
    this.implementsOnChanges = !!(prototype && prototype.ngOnChanges);
    this.componentScope.$watch(() => this.inputChangeCount, this.wrapCallback(() => {
      // Invoke `ngOnChanges()`
      if (this.implementsOnChanges) {
        const inputChanges = this.inputChanges;
        this.inputChanges = {};
        componentRef.instance.ngOnChanges(inputChanges);
      }
      viewChangeDetector.markForCheck();
      // If opted out of propagating digests, invoke change detection when inputs change.
      if (!propagateDigest) {
        detectChanges();
      }
    }));
    // If not opted out of propagating digests, invoke change detection on every digest
    if (propagateDigest) {
      this.componentScope.$watch(this.wrapCallback(detectChanges));
    }
    // If necessary, attach the view so that it will be dirty-checked.
    // (Allow time for the initial input values to be set and `ngOnChanges()` to be called.)
    if (manuallyAttachView || !propagateDigest) {
      let unwatch = this.componentScope.$watch(() => {
        unwatch();
        unwatch = null;
        const appRef = this.parentInjector.get(ApplicationRef);
        appRef.attachView(componentRef.hostView);
      });
    }
  }
  setupOutputs(componentRef) {
    const attrs = this.attrs;
    const outputs = this.componentFactory.outputs || [];
    for (const output of outputs) {
      const outputBindings = new PropertyBinding(output.propName, output.templateName);
      const bindonAttr = outputBindings.bindonAttr.substring(0, outputBindings.bindonAttr.length - 6);
      const bracketParenAttr = `[(${outputBindings.bracketParenAttr.substring(2, outputBindings.bracketParenAttr.length - 8)})]`;
      // order below is important - first update bindings then evaluate expressions
      if (attrs.hasOwnProperty(bindonAttr)) {
        this.subscribeToOutput(componentRef, outputBindings, attrs[bindonAttr], true);
      }
      if (attrs.hasOwnProperty(bracketParenAttr)) {
        this.subscribeToOutput(componentRef, outputBindings, attrs[bracketParenAttr], true);
      }
      if (attrs.hasOwnProperty(outputBindings.onAttr)) {
        this.subscribeToOutput(componentRef, outputBindings, attrs[outputBindings.onAttr]);
      }
      if (attrs.hasOwnProperty(outputBindings.parenAttr)) {
        this.subscribeToOutput(componentRef, outputBindings, attrs[outputBindings.parenAttr]);
      }
    }
  }
  subscribeToOutput(componentRef, output, expr, isAssignment = false) {
    const getter = this.$parse(expr);
    const setter = getter.assign;
    if (isAssignment && !setter) {
      throw new Error(`Expression '${expr}' is not assignable!`);
    }
    const emitter = componentRef.instance[output.prop];
    if (emitter) {
      const subscription = emitter.subscribe({
        next: isAssignment ? v => setter(this.scope, v) : v => getter(this.scope, {
          '$event': v
        })
      });
      componentRef.onDestroy(() => subscription.unsubscribe());
    } else {
      throw new Error(`Missing emitter '${output.prop}' on component '${getTypeName(this.componentFactory.componentType)}'!`);
    }
  }
  registerCleanup(componentRef) {
    const testabilityRegistry = componentRef.injector.get(TestabilityRegistry);
    const destroyComponentRef = this.wrapCallback(() => componentRef.destroy());
    let destroyed = false;
    this.element.on('$destroy', () => {
      // The `$destroy` event may have been triggered by the `cleanData()` call in the
      // `componentScope` `$destroy` handler below. In that case, we don't want to call
      // `componentScope.$destroy()` again.
      if (!destroyed) this.componentScope.$destroy();
    });
    this.componentScope.$on('$destroy', () => {
      if (!destroyed) {
        destroyed = true;
        testabilityRegistry.unregisterApplication(componentRef.location.nativeElement);
        // The `componentScope` might be getting destroyed, because an ancestor element is being
        // removed/destroyed. If that is the case, jqLite/jQuery would normally invoke `cleanData()`
        // on the removed element and all descendants.
        //   https://github.com/angular/angular.js/blob/2e72ea13fa98bebf6ed4b5e3c45eaf5f990ed16f/src/jqLite.js#L349-L355
        //   https://github.com/jquery/jquery/blob/6984d1747623dbc5e87fd6c261a5b6b1628c107c/src/manipulation.js#L182
        //
        // Here, however, `destroyComponentRef()` may under some circumstances remove the element
        // from the DOM and therefore it will no longer be a descendant of the removed element when
        // `cleanData()` is called. This would result in a memory leak, because the element's data
        // and event handlers (and all objects directly or indirectly referenced by them) would be
        // retained.
        //
        // To ensure the element is always properly cleaned up, we manually call `cleanData()` on
        // this element and its descendants before destroying the `ComponentRef`.
        cleanData(this.element[0]);
        destroyComponentRef();
      }
    });
  }
  updateInput(componentRef, prop, prevValue, currValue) {
    if (this.implementsOnChanges) {
      this.inputChanges[prop] = new SimpleChange(prevValue, currValue, prevValue === currValue);
    }
    this.inputChangeCount++;
    componentRef.instance[prop] = currValue;
  }
  groupProjectableNodes() {
    let ngContentSelectors = this.componentFactory.ngContentSelectors;
    return groupNodesBySelector(ngContentSelectors, this.element.contents());
  }
}
/**
 * Group a set of DOM nodes into `ngContent` groups, based on the given content selectors.
 */
function groupNodesBySelector(ngContentSelectors, nodes) {
  const projectableNodes = [];
  for (let i = 0, ii = ngContentSelectors.length; i < ii; ++i) {
    projectableNodes[i] = [];
  }
  for (let j = 0, jj = nodes.length; j < jj; ++j) {
    const node = nodes[j];
    const ngContentIndex = findMatchingNgContentIndex(node, ngContentSelectors);
    if (ngContentIndex != null) {
      projectableNodes[ngContentIndex].push(node);
    }
  }
  return projectableNodes;
}
function findMatchingNgContentIndex(element, ngContentSelectors) {
  const ngContentIndices = [];
  let wildcardNgContentIndex = -1;
  for (let i = 0; i < ngContentSelectors.length; i++) {
    const selector = ngContentSelectors[i];
    if (selector === '*') {
      wildcardNgContentIndex = i;
    } else {
      if (matchesSelector(element, selector)) {
        ngContentIndices.push(i);
      }
    }
  }
  ngContentIndices.sort();
  if (wildcardNgContentIndex !== -1) {
    ngContentIndices.push(wildcardNgContentIndex);
  }
  return ngContentIndices.length ? ngContentIndices[0] : null;
}
function matchesSelector(el, selector) {
  const elProto = Element.prototype;
  return el.nodeType === Node.ELEMENT_NODE ?
  // matches is supported by all browsers from 2014 onwards except non-chromium edge
  (elProto.matches ?? elProto.msMatchesSelector).call(el, selector) : false;
}
function isThenable(obj) {
  return !!obj && isFunction(obj.then);
}
/**
 * Synchronous, promise-like object.
 */
class SyncPromise {
  constructor() {
    this.resolved = false;
    this.callbacks = [];
  }
  static all(valuesOrPromises) {
    const aggrPromise = new SyncPromise();
    let resolvedCount = 0;
    const results = [];
    const resolve = (idx, value) => {
      results[idx] = value;
      if (++resolvedCount === valuesOrPromises.length) aggrPromise.resolve(results);
    };
    valuesOrPromises.forEach((p, idx) => {
      if (isThenable(p)) {
        p.then(v => resolve(idx, v));
      } else {
        resolve(idx, p);
      }
    });
    return aggrPromise;
  }
  resolve(value) {
    // Do nothing, if already resolved.
    if (this.resolved) return;
    this.value = value;
    this.resolved = true;
    // Run the queued callbacks.
    this.callbacks.forEach(callback => callback(value));
    this.callbacks.length = 0;
  }
  then(callback) {
    if (this.resolved) {
      callback(this.value);
    } else {
      this.callbacks.push(callback);
    }
  }
}

/**
 * @description
 *
 * A helper function that allows an Angular component to be used from AngularJS.
 *
 * *Part of the [upgrade/static](api?query=upgrade%2Fstatic)
 * library for hybrid upgrade apps that support AOT compilation*
 *
 * This helper function returns a factory function to be used for registering
 * an AngularJS wrapper directive for "downgrading" an Angular component.
 *
 * @usageNotes
 * ### Examples
 *
 * Let's assume that you have an Angular component called `ng2Heroes` that needs
 * to be made available in AngularJS templates.
 *
 * {@example upgrade/static/ts/full/module.ts region="ng2-heroes"}
 *
 * We must create an AngularJS [directive](https://docs.angularjs.org/guide/directive)
 * that will make this Angular component available inside AngularJS templates.
 * The `downgradeComponent()` function returns a factory function that we
 * can use to define the AngularJS directive that wraps the "downgraded" component.
 *
 * {@example upgrade/static/ts/full/module.ts region="ng2-heroes-wrapper"}
 *
 * For more details and examples on downgrading Angular components to AngularJS components please
 * visit the [Upgrade guide](https://angular.io/guide/upgrade#using-angular-components-from-angularjs-code).
 *
 * @param info contains information about the Component that is being downgraded:
 *
 * - `component: Type<any>`: The type of the Component that will be downgraded
 * - `downgradedModule?: string`: The name of the downgraded module (if any) that the component
 *   "belongs to", as returned by a call to `downgradeModule()`. It is the module, whose
 *   corresponding Angular module will be bootstrapped, when the component needs to be instantiated.
 *   <br />
 *   (This option is only necessary when using `downgradeModule()` to downgrade more than one
 *   Angular module.)
 * - `propagateDigest?: boolean`: Whether to perform {@link ChangeDetectorRef#detectChanges} on the
 * component on every
 *   [$digest](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest). If set to `false`,
 *   change detection will still be performed when any of the component's inputs changes.
 *   (Default: true)
 *
 * @returns a factory function that can be used to register the component in an
 * AngularJS module.
 *
 * @publicApi
 */
function downgradeComponent(info) {
  const directiveFactory = function ($compile, $injector, $parse) {
    // When using `downgradeModule()`, we need to handle certain things specially. For example:
    // - We always need to attach the component view to the `ApplicationRef` for it to be
    //   dirty-checked.
    // - We need to ensure callbacks to Angular APIs (e.g. change detection) are run inside the
    //   Angular zone.
    //   NOTE: This is not needed, when using `UpgradeModule`, because `$digest()` will be run
    //         inside the Angular zone (except if explicitly escaped, in which case we shouldn't
    //         force it back in).
    const isNgUpgradeLite = getUpgradeAppType($injector) === 3 /* UpgradeAppType.Lite */;
    const wrapCallback = !isNgUpgradeLite ? cb => cb : cb => () => NgZone.isInAngularZone() ? cb() : ngZone.run(cb);
    let ngZone;
    // When downgrading multiple modules, special handling is needed wrt injectors.
    const hasMultipleDowngradedModules = isNgUpgradeLite && getDowngradedModuleCount($injector) > 1;
    return {
      restrict: 'E',
      terminal: true,
      require: [REQUIRE_INJECTOR, REQUIRE_NG_MODEL],
      // Controller needs to be set so that `angular-component-router.js` (from beta Angular 2)
      // configuration properties can be made available. See:
      // See G3: javascript/angular2/angular1_router_lib.js
      // https://github.com/angular/angular.js/blob/47bf11ee94664367a26ed8c91b9b586d3dd420f5/src/ng/compile.js#L1670-L1691.
      controller: function () {},
      link: (scope, element, attrs, required) => {
        // We might have to compile the contents asynchronously, because this might have been
        // triggered by `UpgradeNg1ComponentAdapterBuilder`, before the Angular templates have
        // been compiled.
        const ngModel = required[1];
        const parentInjector = required[0];
        let moduleInjector = undefined;
        let ranAsync = false;
        if (!parentInjector || hasMultipleDowngradedModules) {
          const downgradedModule = info.downgradedModule || '';
          const lazyModuleRefKey = `${LAZY_MODULE_REF}${downgradedModule}`;
          const attemptedAction = `instantiating component '${getTypeName(info.component)}'`;
          validateInjectionKey($injector, downgradedModule, lazyModuleRefKey, attemptedAction);
          const lazyModuleRef = $injector.get(lazyModuleRefKey);
          moduleInjector = lazyModuleRef.injector ?? lazyModuleRef.promise;
        }
        // Notes:
        //
        // There are two injectors: `finalModuleInjector` and `finalParentInjector` (they might be
        // the same instance, but that is irrelevant):
        // - `finalModuleInjector` is used to retrieve `ComponentFactoryResolver`, thus it must be
        //   on the same tree as the `NgModule` that declares this downgraded component.
        // - `finalParentInjector` is used for all other injection purposes.
        //   (Note that Angular knows to only traverse the component-tree part of that injector,
        //   when looking for an injectable and then switch to the module injector.)
        //
        // There are basically three cases:
        // - If there is no parent component (thus no `parentInjector`), we bootstrap the downgraded
        //   `NgModule` and use its injector as both `finalModuleInjector` and
        //   `finalParentInjector`.
        // - If there is a parent component (and thus a `parentInjector`) and we are sure that it
        //   belongs to the same `NgModule` as this downgraded component (e.g. because there is only
        //   one downgraded module, we use that `parentInjector` as both `finalModuleInjector` and
        //   `finalParentInjector`.
        // - If there is a parent component, but it may belong to a different `NgModule`, then we
        //   use the `parentInjector` as `finalParentInjector` and this downgraded component's
        //   declaring `NgModule`'s injector as `finalModuleInjector`.
        //   Note 1: If the `NgModule` is already bootstrapped, we just get its injector (we don't
        //           bootstrap again).
        //   Note 2: It is possible that (while there are multiple downgraded modules) this
        //           downgraded component and its parent component both belong to the same NgModule.
        //           In that case, we could have used the `parentInjector` as both
        //           `finalModuleInjector` and `finalParentInjector`, but (for simplicity) we are
        //           treating this case as if they belong to different `NgModule`s. That doesn't
        //           really affect anything, since `parentInjector` has `moduleInjector` as ancestor
        //           and trying to resolve `ComponentFactoryResolver` from either one will return
        //           the same instance.
        // If there is a parent component, use its injector as parent injector.
        // If this is a "top-level" Angular component, use the module injector.
        const finalParentInjector = parentInjector || moduleInjector;
        // If this is a "top-level" Angular component or the parent component may belong to a
        // different `NgModule`, use the module injector for module-specific dependencies.
        // If there is a parent component that belongs to the same `NgModule`, use its injector.
        const finalModuleInjector = moduleInjector || parentInjector;
        const doDowngrade = (injector, moduleInjector) => {
          // Retrieve `ComponentFactoryResolver` from the injector tied to the `NgModule` this
          // component belongs to.
          const componentFactoryResolver = moduleInjector.get(ComponentFactoryResolver);
          const componentFactory = componentFactoryResolver.resolveComponentFactory(info.component);
          if (!componentFactory) {
            throw new Error(`Expecting ComponentFactory for: ${getTypeName(info.component)}`);
          }
          const injectorPromise = new ParentInjectorPromise(element);
          const facade = new DowngradeComponentAdapter(element, attrs, scope, ngModel, injector, $compile, $parse, componentFactory, wrapCallback);
          const projectableNodes = facade.compileContents();
          const componentRef = facade.createComponentAndSetup(projectableNodes, isNgUpgradeLite, info.propagateDigest);
          injectorPromise.resolve(componentRef.injector);
          if (ranAsync) {
            // If this is run async, it is possible that it is not run inside a
            // digest and initial input values will not be detected.
            scope.$evalAsync(() => {});
          }
        };
        const downgradeFn = !isNgUpgradeLite ? doDowngrade : (pInjector, mInjector) => {
          if (!ngZone) {
            ngZone = pInjector.get(NgZone);
          }
          wrapCallback(() => doDowngrade(pInjector, mInjector))();
        };
        // NOTE:
        // Not using `ParentInjectorPromise.all()` (which is inherited from `SyncPromise`), because
        // Closure Compiler (or some related tool) complains:
        // `TypeError: ...$src$downgrade_component_ParentInjectorPromise.all is not a function`
        SyncPromise.all([finalParentInjector, finalModuleInjector]).then(([pInjector, mInjector]) => downgradeFn(pInjector, mInjector));
        ranAsync = true;
      }
    };
  };
  // bracket-notation because of closure - see #14441
  directiveFactory['$inject'] = [$COMPILE, $INJECTOR, $PARSE];
  return directiveFactory;
}
/**
 * Synchronous promise-like object to wrap parent injectors,
 * to preserve the synchronous nature of AngularJS's `$compile`.
 */
class ParentInjectorPromise extends SyncPromise {
  constructor(element) {
    super();
    this.element = element;
    this.injectorKey = controllerKey(INJECTOR_KEY);
    // Store the promise on the element.
    element.data(this.injectorKey, this);
  }
  resolve(injector) {
    // Store the real injector on the element.
    this.element.data(this.injectorKey, injector);
    // Release the element to prevent memory leaks.
    this.element = null;
    // Resolve the promise.
    super.resolve(injector);
  }
}

/**
 * @description
 *
 * A helper function to allow an Angular service to be accessible from AngularJS.
 *
 * *Part of the [upgrade/static](api?query=upgrade%2Fstatic)
 * library for hybrid upgrade apps that support AOT compilation*
 *
 * This helper function returns a factory function that provides access to the Angular
 * service identified by the `token` parameter.
 *
 * @usageNotes
 * ### Examples
 *
 * First ensure that the service to be downgraded is provided in an `NgModule`
 * that will be part of the upgrade application. For example, let's assume we have
 * defined `HeroesService`
 *
 * {@example upgrade/static/ts/full/module.ts region="ng2-heroes-service"}
 *
 * and that we have included this in our upgrade app `NgModule`
 *
 * {@example upgrade/static/ts/full/module.ts region="ng2-module"}
 *
 * Now we can register the `downgradeInjectable` factory function for the service
 * on an AngularJS module.
 *
 * {@example upgrade/static/ts/full/module.ts region="downgrade-ng2-heroes-service"}
 *
 * Inside an AngularJS component's controller we can get hold of the
 * downgraded service via the name we gave when downgrading.
 *
 * {@example upgrade/static/ts/full/module.ts region="example-app"}
 *
 * <div class="alert is-important">
 *
 *   When using `downgradeModule()`, downgraded injectables will not be available until the Angular
 *   module that provides them is instantiated. In order to be safe, you need to ensure that the
 *   downgraded injectables are not used anywhere _outside_ the part of the app where it is
 *   guaranteed that their module has been instantiated.
 *
 *   For example, it is _OK_ to use a downgraded service in an upgraded component that is only used
 *   from a downgraded Angular component provided by the same Angular module as the injectable, but
 *   it is _not OK_ to use it in an AngularJS component that may be used independently of Angular or
 *   use it in a downgraded Angular component from a different module.
 *
 * </div>
 *
 * @param token an `InjectionToken` that identifies a service provided from Angular.
 * @param downgradedModule the name of the downgraded module (if any) that the injectable
 * "belongs to", as returned by a call to `downgradeModule()`. It is the module, whose injector will
 * be used for instantiating the injectable.<br />
 * (This option is only necessary when using `downgradeModule()` to downgrade more than one Angular
 * module.)
 *
 * @returns a [factory function](https://docs.angularjs.org/guide/di) that can be
 * used to register the service on an AngularJS module.
 *
 * @publicApi
 */
function downgradeInjectable(token, downgradedModule = '') {
  const factory = function ($injector) {
    const injectorKey = `${INJECTOR_KEY}${downgradedModule}`;
    const injectableName = isFunction(token) ? getTypeName(token) : String(token);
    const attemptedAction = `instantiating injectable '${injectableName}'`;
    validateInjectionKey($injector, downgradedModule, injectorKey, attemptedAction);
    try {
      const injector = $injector.get(injectorKey);
      return injector.get(token);
    } catch (err) {
      throw new Error(`Error while ${attemptedAction}: ${err.message || err}`);
    }
  };
  factory['$inject'] = [$INJECTOR];
  return factory;
}

/**
 * The Trusted Types policy, or null if Trusted Types are not
 * enabled/supported, or undefined if the policy has not been created yet.
 */
let policy;
/**
 * Returns the Trusted Types policy, or null if Trusted Types are not
 * enabled/supported. The first call to this function will create the policy.
 */
function getPolicy() {
  if (policy === undefined) {
    policy = null;
    const windowWithTrustedTypes = window;
    if (windowWithTrustedTypes.trustedTypes) {
      try {
        policy = windowWithTrustedTypes.trustedTypes.createPolicy('angular#unsafe-upgrade', {
          createHTML: s => s
        });
      } catch {
        // trustedTypes.createPolicy throws if called with a name that is
        // already registered, even in report-only mode. Until the API changes,
        // catch the error not to break the applications functionally. In such
        // cases, the code will fall back to using strings.
      }
    }
  }
  return policy;
}
/**
 * Unsafely promote a legacy AngularJS template to a TrustedHTML, falling back
 * to strings when Trusted Types are not available.
 * @security This is a security-sensitive function; any use of this function
 * must go through security review. In particular, the template string should
 * always be under full control of the application author, as untrusted input
 * can cause an XSS vulnerability.
 */
function trustedHTMLFromLegacyTemplate(html) {
  return getPolicy()?.createHTML(html) || html;
}

// Constants
const REQUIRE_PREFIX_RE = /^(\^\^?)?(\?)?(\^\^?)?/;
// Classes
class UpgradeHelper {
  constructor(injector, name, elementRef, directive) {
    this.name = name;
    this.$injector = injector.get($INJECTOR);
    this.$compile = this.$injector.get($COMPILE);
    this.$controller = this.$injector.get($CONTROLLER);
    this.element = elementRef.nativeElement;
    this.$element = element(this.element);
    this.directive = directive ?? UpgradeHelper.getDirective(this.$injector, name);
  }
  static getDirective($injector, name) {
    const directives = $injector.get(name + 'Directive');
    if (directives.length > 1) {
      throw new Error(`Only support single directive definition for: ${name}`);
    }
    const directive = directives[0];
    // AngularJS will transform `link: xyz` to `compile: () => xyz`. So we can only tell there was a
    // user-defined `compile` if there is no `link`. In other cases, we will just ignore `compile`.
    if (directive.compile && !directive.link) notSupported(name, 'compile');
    if (directive.replace) notSupported(name, 'replace');
    if (directive.terminal) notSupported(name, 'terminal');
    return directive;
  }
  static getTemplate($injector, directive, fetchRemoteTemplate = false, $element) {
    if (directive.template !== undefined) {
      return trustedHTMLFromLegacyTemplate(getOrCall(directive.template, $element));
    } else if (directive.templateUrl) {
      const $templateCache = $injector.get($TEMPLATE_CACHE);
      const url = getOrCall(directive.templateUrl, $element);
      const template = $templateCache.get(url);
      if (template !== undefined) {
        return trustedHTMLFromLegacyTemplate(template);
      } else if (!fetchRemoteTemplate) {
        throw new Error('loading directive templates asynchronously is not supported');
      }
      return new Promise((resolve, reject) => {
        const $httpBackend = $injector.get($HTTP_BACKEND);
        $httpBackend('GET', url, null, (status, response) => {
          if (status === 200) {
            resolve(trustedHTMLFromLegacyTemplate($templateCache.put(url, response)));
          } else {
            reject(`GET component template from '${url}' returned '${status}: ${response}'`);
          }
        });
      });
    } else {
      throw new Error(`Directive '${directive.name}' is not a component, it is missing template.`);
    }
  }
  buildController(controllerType, $scope) {
    // TODO: Document that we do not pre-assign bindings on the controller instance.
    // Quoted properties below so that this code can be optimized with Closure Compiler.
    const locals = {
      '$scope': $scope,
      '$element': this.$element
    };
    const controller = this.$controller(controllerType, locals, null, this.directive.controllerAs);
    this.$element.data?.(controllerKey(this.directive.name), controller);
    return controller;
  }
  compileTemplate(template) {
    if (template === undefined) {
      template = UpgradeHelper.getTemplate(this.$injector, this.directive, false, this.$element);
    }
    return this.compileHtml(template);
  }
  onDestroy($scope, controllerInstance) {
    if (controllerInstance && isFunction(controllerInstance.$onDestroy)) {
      controllerInstance.$onDestroy();
    }
    $scope.$destroy();
    cleanData(this.element);
  }
  prepareTransclusion() {
    const transclude = this.directive.transclude;
    const contentChildNodes = this.extractChildNodes();
    const attachChildrenFn = (scope, cloneAttachFn) => {
      // Since AngularJS v1.5.8, `cloneAttachFn` will try to destroy the transclusion scope if
      // `$template` is empty. Since the transcluded content comes from Angular, not AngularJS,
      // there will be no transclusion scope here.
      // Provide a dummy `scope.$destroy()` method to prevent `cloneAttachFn` from throwing.
      scope = scope || {
        $destroy: () => undefined
      };
      return cloneAttachFn($template, scope);
    };
    let $template = contentChildNodes;
    if (transclude) {
      const slots = Object.create(null);
      if (typeof transclude === 'object') {
        $template = [];
        const slotMap = Object.create(null);
        const filledSlots = Object.create(null);
        // Parse the element selectors.
        Object.keys(transclude).forEach(slotName => {
          let selector = transclude[slotName];
          const optional = selector.charAt(0) === '?';
          selector = optional ? selector.substring(1) : selector;
          slotMap[selector] = slotName;
          slots[slotName] = null; // `null`: Defined but not yet filled.
          filledSlots[slotName] = optional; // Consider optional slots as filled.
        });
        // Add the matching elements into their slot.
        contentChildNodes.forEach(node => {
          const slotName = slotMap[directiveNormalize(node.nodeName.toLowerCase())];
          if (slotName) {
            filledSlots[slotName] = true;
            slots[slotName] = slots[slotName] || [];
            slots[slotName].push(node);
          } else {
            $template.push(node);
          }
        });
        // Check for required slots that were not filled.
        Object.keys(filledSlots).forEach(slotName => {
          if (!filledSlots[slotName]) {
            throw new Error(`Required transclusion slot '${slotName}' on directive: ${this.name}`);
          }
        });
        Object.keys(slots).filter(slotName => slots[slotName]).forEach(slotName => {
          const nodes = slots[slotName];
          slots[slotName] = (scope, cloneAttach) => {
            return cloneAttach(nodes, scope);
          };
        });
      }
      // Attach `$$slots` to default slot transclude fn.
      attachChildrenFn.$$slots = slots;
      // AngularJS v1.6+ ignores empty or whitespace-only transcluded text nodes. But Angular
      // removes all text content after the first interpolation and updates it later, after
      // evaluating the expressions. This would result in AngularJS failing to recognize text
      // nodes that start with an interpolation as transcluded content and use the fallback
      // content instead.
      // To avoid this issue, we add a
      // [zero-width non-joiner character](https://en.wikipedia.org/wiki/Zero-width_non-joiner)
      // to empty text nodes (which can only be a result of Angular removing their initial content).
      // NOTE: Transcluded text content that starts with whitespace followed by an interpolation
      //       will still fail to be detected by AngularJS v1.6+
      $template.forEach(node => {
        if (node.nodeType === Node.TEXT_NODE && !node.nodeValue) {
          node.nodeValue = '\u200C';
        }
      });
    }
    return attachChildrenFn;
  }
  resolveAndBindRequiredControllers(controllerInstance) {
    const directiveRequire = this.getDirectiveRequire();
    const requiredControllers = this.resolveRequire(directiveRequire);
    if (controllerInstance && this.directive.bindToController && isMap(directiveRequire)) {
      const requiredControllersMap = requiredControllers;
      Object.keys(requiredControllersMap).forEach(key => {
        controllerInstance[key] = requiredControllersMap[key];
      });
    }
    return requiredControllers;
  }
  compileHtml(html) {
    this.element.innerHTML = html;
    return this.$compile(this.element.childNodes);
  }
  extractChildNodes() {
    const childNodes = [];
    let childNode;
    while (childNode = this.element.firstChild) {
      childNode.remove();
      childNodes.push(childNode);
    }
    return childNodes;
  }
  getDirectiveRequire() {
    const require = this.directive.require || this.directive.controller && this.directive.name;
    if (isMap(require)) {
      Object.entries(require).forEach(([key, value]) => {
        const match = value.match(REQUIRE_PREFIX_RE);
        const name = value.substring(match[0].length);
        if (!name) {
          require[key] = match[0] + key;
        }
      });
    }
    return require;
  }
  resolveRequire(require) {
    if (!require) {
      return null;
    } else if (Array.isArray(require)) {
      return require.map(req => this.resolveRequire(req));
    } else if (typeof require === 'object') {
      const value = {};
      Object.keys(require).forEach(key => value[key] = this.resolveRequire(require[key]));
      return value;
    } else if (typeof require === 'string') {
      const match = require.match(REQUIRE_PREFIX_RE);
      const inheritType = match[1] || match[3];
      const name = require.substring(match[0].length);
      const isOptional = !!match[2];
      const searchParents = !!inheritType;
      const startOnParent = inheritType === '^^';
      const ctrlKey = controllerKey(name);
      const elem = startOnParent ? this.$element.parent() : this.$element;
      const value = searchParents ? elem.inheritedData(ctrlKey) : elem.data(ctrlKey);
      if (!value && !isOptional) {
        throw new Error(`Unable to find required '${require}' in upgraded directive '${this.name}'.`);
      }
      return value;
    } else {
      throw new Error(`Unrecognized 'require' syntax on upgraded directive '${this.name}': ${require}`);
    }
  }
}
function getOrCall(property, ...args) {
  return isFunction(property) ? property(...args) : property;
}
// NOTE: Only works for `typeof T !== 'object'`.
function isMap(value) {
  return value && !Array.isArray(value) && typeof value === 'object';
}
function notSupported(name, feature) {
  throw new Error(`Upgraded directive '${name}' contains unsupported feature: '${feature}'.`);
}
const CAMEL_CASE = /([A-Z])/g;
const INITIAL_VALUE = {
  __UNINITIALIZED__: true
};
const NOT_SUPPORTED = 'NOT_SUPPORTED';
function getInputPropertyMapName(name) {
  return `input_${name}`;
}
function getOutputPropertyMapName(name) {
  return `output_${name}`;
}
class UpgradeNg1ComponentAdapterBuilder {
  constructor(name) {
    this.name = name;
    this.inputs = [];
    this.inputsRename = [];
    this.outputs = [];
    this.outputsRename = [];
    this.propertyOutputs = [];
    this.checkProperties = [];
    this.propertyMap = {};
    this.directive = null;
    const selector = name.replace(CAMEL_CASE, (all, next) => '-' + next.toLowerCase());
    const self = this;
    let MyClass = class MyClass extends UpgradeNg1ComponentAdapter {
      constructor(scope, injector, elementRef) {
        super(new UpgradeHelper(injector, name, elementRef, self.directive || undefined), scope, self.template, self.inputs, self.outputs, self.propertyOutputs, self.checkProperties, self.propertyMap);
      }
      static {
        this.ctorParameters = () => [{
          type: undefined,
          decorators: [{
            type: Inject,
            args: [$SCOPE]
          }]
        }, {
          type: Injector
        }, {
          type: ElementRef
        }];
      }
    };
    MyClass = __decorate([Directive({
      jit: true,
      selector: selector,
      inputs: this.inputsRename,
      outputs: this.outputsRename
    }), __metadata("design:paramtypes", [Object, Injector, ElementRef])], MyClass);
    this.type = MyClass;
  }
  extractBindings() {
    const btcIsObject = typeof this.directive.bindToController === 'object';
    if (btcIsObject && Object.keys(this.directive.scope).length) {
      throw new Error(`Binding definitions on scope and controller at the same time are not supported.`);
    }
    const context = btcIsObject ? this.directive.bindToController : this.directive.scope;
    if (typeof context == 'object') {
      Object.keys(context).forEach(propName => {
        const definition = context[propName];
        const bindingType = definition.charAt(0);
        const bindingOptions = definition.charAt(1);
        const attrName = definition.substring(bindingOptions === '?' ? 2 : 1) || propName;
        // QUESTION: What about `=*`? Ignore? Throw? Support?
        const inputName = getInputPropertyMapName(attrName);
        const inputNameRename = `${inputName}: ${attrName}`;
        const outputName = getOutputPropertyMapName(attrName);
        const outputNameRename = `${outputName}: ${attrName}`;
        const outputNameRenameChange = `${outputNameRename}Change`;
        switch (bindingType) {
          case '@':
          case '<':
            this.inputs.push(inputName);
            this.inputsRename.push(inputNameRename);
            this.propertyMap[inputName] = propName;
            break;
          case '=':
            this.inputs.push(inputName);
            this.inputsRename.push(inputNameRename);
            this.propertyMap[inputName] = propName;
            this.outputs.push(outputName);
            this.outputsRename.push(outputNameRenameChange);
            this.propertyMap[outputName] = propName;
            this.checkProperties.push(propName);
            this.propertyOutputs.push(outputName);
            break;
          case '&':
            this.outputs.push(outputName);
            this.outputsRename.push(outputNameRename);
            this.propertyMap[outputName] = propName;
            break;
          default:
            let json = JSON.stringify(context);
            throw new Error(`Unexpected mapping '${bindingType}' in '${json}' in '${this.name}' directive.`);
        }
      });
    }
  }
  /**
   * Upgrade ng1 components into Angular.
   */
  static resolve(exportedComponents, $injector) {
    const promises = Object.entries(exportedComponents).map(([name, exportedComponent]) => {
      exportedComponent.directive = UpgradeHelper.getDirective($injector, name);
      exportedComponent.extractBindings();
      return Promise.resolve(UpgradeHelper.getTemplate($injector, exportedComponent.directive, true)).then(template => exportedComponent.template = template);
    });
    return Promise.all(promises);
  }
}
class UpgradeNg1ComponentAdapter {
  constructor(helper, scope, template, inputs, outputs, propOuts, checkProperties, propertyMap) {
    this.helper = helper;
    this.template = template;
    this.inputs = inputs;
    this.outputs = outputs;
    this.propOuts = propOuts;
    this.checkProperties = checkProperties;
    this.propertyMap = propertyMap;
    this.controllerInstance = null;
    this.destinationObj = null;
    this.checkLastValues = [];
    this.$element = null;
    this.directive = helper.directive;
    this.element = helper.element;
    this.$element = helper.$element;
    this.componentScope = scope.$new(!!this.directive.scope);
    const controllerType = this.directive.controller;
    if (this.directive.bindToController && controllerType) {
      this.controllerInstance = this.helper.buildController(controllerType, this.componentScope);
      this.destinationObj = this.controllerInstance;
    } else {
      this.destinationObj = this.componentScope;
    }
    for (const input of this.inputs) {
      this[input] = null;
    }
    for (const output of this.outputs) {
      const emitter = this[output] = new EventEmitter();
      if (this.propOuts.indexOf(output) === -1) {
        this.setComponentProperty(output, (emitter => value => emitter.emit(value))(emitter));
      }
    }
    this.checkLastValues.push(...Array(propOuts.length).fill(INITIAL_VALUE));
  }
  ngOnInit() {
    // Collect contents, insert and compile template
    const attachChildNodes = this.helper.prepareTransclusion();
    const linkFn = this.helper.compileTemplate(trustedHTMLFromLegacyTemplate(this.template));
    // Instantiate controller (if not already done so)
    const controllerType = this.directive.controller;
    const bindToController = this.directive.bindToController;
    if (controllerType && !bindToController) {
      this.controllerInstance = this.helper.buildController(controllerType, this.componentScope);
    }
    // Require other controllers
    const requiredControllers = this.helper.resolveAndBindRequiredControllers(this.controllerInstance);
    // Hook: $onInit
    if (this.controllerInstance && isFunction(this.controllerInstance.$onInit)) {
      this.controllerInstance.$onInit();
    }
    // Linking
    const link = this.directive.link;
    const preLink = typeof link == 'object' && link.pre;
    const postLink = typeof link == 'object' ? link.post : link;
    const attrs = NOT_SUPPORTED;
    const transcludeFn = NOT_SUPPORTED;
    if (preLink) {
      preLink(this.componentScope, this.$element, attrs, requiredControllers, transcludeFn);
    }
    linkFn(this.componentScope, null, {
      parentBoundTranscludeFn: attachChildNodes
    });
    if (postLink) {
      postLink(this.componentScope, this.$element, attrs, requiredControllers, transcludeFn);
    }
    // Hook: $postLink
    if (this.controllerInstance && isFunction(this.controllerInstance.$postLink)) {
      this.controllerInstance.$postLink();
    }
  }
  ngOnChanges(changes) {
    const ng1Changes = {};
    Object.keys(changes).forEach(propertyMapName => {
      const change = changes[propertyMapName];
      this.setComponentProperty(propertyMapName, change.currentValue);
      ng1Changes[this.propertyMap[propertyMapName]] = change;
    });
    if (isFunction(this.destinationObj.$onChanges)) {
      this.destinationObj.$onChanges(ng1Changes);
    }
  }
  ngDoCheck() {
    const destinationObj = this.destinationObj;
    const lastValues = this.checkLastValues;
    const checkProperties = this.checkProperties;
    const propOuts = this.propOuts;
    checkProperties.forEach((propName, i) => {
      const value = destinationObj[propName];
      const last = lastValues[i];
      if (!strictEquals(last, value)) {
        const eventEmitter = this[propOuts[i]];
        eventEmitter.emit(lastValues[i] = value);
      }
    });
    if (this.controllerInstance && isFunction(this.controllerInstance.$doCheck)) {
      this.controllerInstance.$doCheck();
    }
  }
  ngOnDestroy() {
    this.helper.onDestroy(this.componentScope, this.controllerInstance);
  }
  setComponentProperty(name, value) {
    this.destinationObj[this.propertyMap[name]] = value;
  }
  static {
    this.ɵfac = function UpgradeNg1ComponentAdapter_Factory(__ngFactoryType__) {
      i0.ɵɵinvalidFactory();
    };
  }
  static {
    this.ɵdir = /* @__PURE__ */i0.ɵɵdefineDirective({
      type: UpgradeNg1ComponentAdapter,
      features: [i0.ɵɵNgOnChangesFeature]
    });
  }
}
(() => {
  (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UpgradeNg1ComponentAdapter, [{
    type: Directive
  }], () => [{
    type: UpgradeHelper
  }, {
    type: undefined
  }, {
    type: undefined
  }, {
    type: undefined
  }, {
    type: undefined
  }, {
    type: undefined
  }, {
    type: undefined
  }, {
    type: undefined
  }], null);
})();
let upgradeCount = 0;
/**
 * Use `UpgradeAdapter` to allow AngularJS and Angular to coexist in a single application.
 *
 * The `UpgradeAdapter` allows:
 * 1. creation of Angular component from AngularJS component directive
 *    (See {@link UpgradeAdapter#upgradeNg1Component})
 * 2. creation of AngularJS directive from Angular component.
 *    (See {@link UpgradeAdapter#downgradeNg2Component})
 * 3. Bootstrapping of a hybrid Angular application which contains both of the frameworks
 *    coexisting in a single application.
 *
 * @usageNotes
 * ### Mental Model
 *
 * When reasoning about how a hybrid application works it is useful to have a mental model which
 * describes what is happening and explains what is happening at the lowest level.
 *
 * 1. There are two independent frameworks running in a single application, each framework treats
 *    the other as a black box.
 * 2. Each DOM element on the page is owned exactly by one framework. Whichever framework
 *    instantiated the element is the owner. Each framework only updates/interacts with its own
 *    DOM elements and ignores others.
 * 3. AngularJS directives always execute inside AngularJS framework codebase regardless of
 *    where they are instantiated.
 * 4. Angular components always execute inside Angular framework codebase regardless of
 *    where they are instantiated.
 * 5. An AngularJS component can be upgraded to an Angular component. This creates an
 *    Angular directive, which bootstraps the AngularJS component directive in that location.
 * 6. An Angular component can be downgraded to an AngularJS component directive. This creates
 *    an AngularJS directive, which bootstraps the Angular component in that location.
 * 7. Whenever an adapter component is instantiated the host element is owned by the framework
 *    doing the instantiation. The other framework then instantiates and owns the view for that
 *    component. This implies that component bindings will always follow the semantics of the
 *    instantiation framework. The syntax is always that of Angular syntax.
 * 8. AngularJS is always bootstrapped first and owns the bottom most view.
 * 9. The new application is running in Angular zone, and therefore it no longer needs calls to
 *    `$apply()`.
 *
 * ### Example
 *
 * ```
 * const adapter = new UpgradeAdapter(forwardRef(() => MyNg2Module), myCompilerOptions);
 * const module = angular.module('myExample', []);
 * module.directive('ng2Comp', adapter.downgradeNg2Component(Ng2Component));
 *
 * module.directive('ng1Hello', function() {
 *   return {
 *      scope: { title: '=' },
 *      template: 'ng1[Hello {{title}}!](<span ng-transclude></span>)'
 *   };
 * });
 *
 *
 * @Component({
 *   selector: 'ng2-comp',
 *   inputs: ['name'],
 *   template: 'ng2[<ng1-hello [title]="name">transclude</ng1-hello>](<ng-content></ng-content>)',
 *   directives:
 * })
 * class Ng2Component {
 * }
 *
 * @NgModule({
 *   declarations: [Ng2Component, adapter.upgradeNg1Component('ng1Hello')],
 *   imports: [BrowserModule]
 * })
 * class MyNg2Module {}
 *
 *
 * document.body.innerHTML = '<ng2-comp name="World">project</ng2-comp>';
 *
 * adapter.bootstrap(document.body, ['myExample']).ready(function() {
 *   expect(document.body.textContent).toEqual(
 *       "ng2[ng1[Hello World!](transclude)](project)");
 * });
 *
 * ```
 *
 * @deprecated Deprecated since v5. Use `upgrade/static` instead, which also supports
 * [Ahead-of-Time compilation](tools/cli/aot-compiler).
 * @publicApi
 */
class UpgradeAdapter {
  constructor(ng2AppModule, compilerOptions) {
    this.ng2AppModule = ng2AppModule;
    this.compilerOptions = compilerOptions;
    this.idPrefix = `NG2_UPGRADE_${upgradeCount++}_`;
    this.downgradedComponents = [];
    /**
     * An internal map of ng1 components which need to up upgraded to ng2.
     *
     * We can't upgrade until injector is instantiated and we can retrieve the component metadata.
     * For this reason we keep a list of components to upgrade until ng1 injector is bootstrapped.
     *
     * @internal
     */
    this.ng1ComponentsToBeUpgraded = {};
    this.upgradedProviders = [];
    this.moduleRef = null;
    if (!ng2AppModule) {
      throw new Error('UpgradeAdapter cannot be instantiated without an NgModule of the Angular app.');
    }
  }
  /**
   * Allows Angular Component to be used from AngularJS.
   *
   * Use `downgradeNg2Component` to create an AngularJS Directive Definition Factory from
   * Angular Component. The adapter will bootstrap Angular component from within the
   * AngularJS template.
   *
   * @usageNotes
   * ### Mental Model
   *
   * 1. The component is instantiated by being listed in AngularJS template. This means that the
   *    host element is controlled by AngularJS, but the component's view will be controlled by
   *    Angular.
   * 2. Even thought the component is instantiated in AngularJS, it will be using Angular
   *    syntax. This has to be done, this way because we must follow Angular components do not
   *    declare how the attributes should be interpreted.
   * 3. `ng-model` is controlled by AngularJS and communicates with the downgraded Angular component
   *    by way of the `ControlValueAccessor` interface from @angular/forms. Only components that
   *    implement this interface are eligible.
   *
   * ### Supported Features
   *
   * - Bindings:
   *   - Attribute: `<comp name="World">`
   *   - Interpolation:  `<comp greeting="Hello {{name}}!">`
   *   - Expression:  `<comp [name]="username">`
   *   - Event:  `<comp (close)="doSomething()">`
   *   - ng-model: `<comp ng-model="name">`
   * - Content projection: yes
   *
   * ### Example
   *
   * ```
   * const adapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
   * const module = angular.module('myExample', []);
   * module.directive('greet', adapter.downgradeNg2Component(Greeter));
   *
   * @Component({
   *   selector: 'greet',
   *   template: '{{salutation}} {{name}}! - <ng-content></ng-content>'
   * })
   * class Greeter {
   *   @Input() salutation: string;
   *   @Input() name: string;
   * }
   *
   * @NgModule({
   *   declarations: [Greeter],
   *   imports: [BrowserModule]
   * })
   * class MyNg2Module {}
   *
   * document.body.innerHTML =
   *   'ng1 template: <greet salutation="Hello" [name]="world">text</greet>';
   *
   * adapter.bootstrap(document.body, ['myExample']).ready(function() {
   *   expect(document.body.textContent).toEqual("ng1 template: Hello world! - text");
   * });
   * ```
   */
  downgradeNg2Component(component) {
    this.downgradedComponents.push(component);
    return downgradeComponent({
      component
    });
  }
  /**
   * Allows AngularJS Component to be used from Angular.
   *
   * Use `upgradeNg1Component` to create an Angular component from AngularJS Component
   * directive. The adapter will bootstrap AngularJS component from within the Angular
   * template.
   *
   * @usageNotes
   * ### Mental Model
   *
   * 1. The component is instantiated by being listed in Angular template. This means that the
   *    host element is controlled by Angular, but the component's view will be controlled by
   *    AngularJS.
   *
   * ### Supported Features
   *
   * - Bindings:
   *   - Attribute: `<comp name="World">`
   *   - Interpolation:  `<comp greeting="Hello {{name}}!">`
   *   - Expression:  `<comp [name]="username">`
   *   - Event:  `<comp (close)="doSomething()">`
   * - Transclusion: yes
   * - Only some of the features of
   *   [Directive Definition Object](https://docs.angularjs.org/api/ng/service/$compile) are
   *   supported:
   *   - `compile`: not supported because the host element is owned by Angular, which does
   *     not allow modifying DOM structure during compilation.
   *   - `controller`: supported. (NOTE: injection of `$attrs` and `$transclude` is not supported.)
   *   - `controllerAs`: supported.
   *   - `bindToController`: supported.
   *   - `link`: supported. (NOTE: only pre-link function is supported.)
   *   - `name`: supported.
   *   - `priority`: ignored.
   *   - `replace`: not supported.
   *   - `require`: supported.
   *   - `restrict`: must be set to 'E'.
   *   - `scope`: supported.
   *   - `template`: supported.
   *   - `templateUrl`: supported.
   *   - `terminal`: ignored.
   *   - `transclude`: supported.
   *
   *
   * ### Example
   *
   * ```
   * const adapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
   * const module = angular.module('myExample', []);
   *
   * module.directive('greet', function() {
   *   return {
   *     scope: {salutation: '=', name: '=' },
   *     template: '{{salutation}} {{name}}! - <span ng-transclude></span>'
   *   };
   * });
   *
   * module.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
   *
   * @Component({
   *   selector: 'ng2',
   *   template: 'ng2 template: <greet salutation="Hello" [name]="world">text</greet>'
   * })
   * class Ng2Component {
   * }
   *
   * @NgModule({
   *   declarations: [Ng2Component, adapter.upgradeNg1Component('greet')],
   *   imports: [BrowserModule]
   * })
   * class MyNg2Module {}
   *
   * document.body.innerHTML = '<ng2></ng2>';
   *
   * adapter.bootstrap(document.body, ['myExample']).ready(function() {
   *   expect(document.body.textContent).toEqual("ng2 template: Hello world! - text");
   * });
   * ```
   */
  upgradeNg1Component(name) {
    if (this.ng1ComponentsToBeUpgraded.hasOwnProperty(name)) {
      return this.ng1ComponentsToBeUpgraded[name].type;
    } else {
      return (this.ng1ComponentsToBeUpgraded[name] = new UpgradeNg1ComponentAdapterBuilder(name)).type;
    }
  }
  /**
   * Registers the adapter's AngularJS upgrade module for unit testing in AngularJS.
   * Use this instead of `angular.mock.module()` to load the upgrade module into
   * the AngularJS testing injector.
   *
   * @usageNotes
   * ### Example
   *
   * ```
   * const upgradeAdapter = new UpgradeAdapter(MyNg2Module);
   *
   * // configure the adapter with upgrade/downgrade components and services
   * upgradeAdapter.downgradeNg2Component(MyComponent);
   *
   * let upgradeAdapterRef: UpgradeAdapterRef;
   * let $compile, $rootScope;
   *
   * // We must register the adapter before any calls to `inject()`
   * beforeEach(() => {
   *   upgradeAdapterRef = upgradeAdapter.registerForNg1Tests(['heroApp']);
   * });
   *
   * beforeEach(inject((_$compile_, _$rootScope_) => {
   *   $compile = _$compile_;
   *   $rootScope = _$rootScope_;
   * }));
   *
   * it("says hello", (done) => {
   *   upgradeAdapterRef.ready(() => {
   *     const element = $compile("<my-component></my-component>")($rootScope);
   *     $rootScope.$apply();
   *     expect(element.html()).toContain("Hello World");
   *     done();
   *   })
   * });
   *
   * ```
   *
   * @param modules any AngularJS modules that the upgrade module should depend upon
   * @returns an `UpgradeAdapterRef`, which lets you register a `ready()` callback to
   * run assertions once the Angular components are ready to test through AngularJS.
   */
  registerForNg1Tests(modules) {
    const windowNgMock = window['angular'].mock;
    if (!windowNgMock || !windowNgMock.module) {
      throw new Error("Failed to find 'angular.mock.module'.");
    }
    const {
      ng1Module,
      ng2BootstrapDeferred
    } = this.declareNg1Module(modules);
    windowNgMock.module(ng1Module.name);
    const upgrade = new UpgradeAdapterRef();
    ng2BootstrapDeferred.promise.then(ng1Injector => {
      // @ts-expect-error
      upgrade._bootstrapDone(this.moduleRef, ng1Injector);
    }, onError);
    return upgrade;
  }
  /**
   * Bootstrap a hybrid AngularJS / Angular application.
   *
   * This `bootstrap` method is a direct replacement (takes same arguments) for AngularJS
   * [`bootstrap`](https://docs.angularjs.org/api/ng/function/angular.bootstrap) method. Unlike
   * AngularJS, this bootstrap is asynchronous.
   *
   * @usageNotes
   * ### Example
   *
   * ```
   * const adapter = new UpgradeAdapter(MyNg2Module);
   * const module = angular.module('myExample', []);
   * module.directive('ng2', adapter.downgradeNg2Component(Ng2));
   *
   * module.directive('ng1', function() {
   *   return {
   *      scope: { title: '=' },
   *      template: 'ng1[Hello {{title}}!](<span ng-transclude></span>)'
   *   };
   * });
   *
   *
   * @Component({
   *   selector: 'ng2',
   *   inputs: ['name'],
   *   template: 'ng2[<ng1 [title]="name">transclude</ng1>](<ng-content></ng-content>)'
   * })
   * class Ng2 {
   * }
   *
   * @NgModule({
   *   declarations: [Ng2, adapter.upgradeNg1Component('ng1')],
   *   imports: [BrowserModule]
   * })
   * class MyNg2Module {}
   *
   * document.body.innerHTML = '<ng2 name="World">project</ng2>';
   *
   * adapter.bootstrap(document.body, ['myExample']).ready(function() {
   *   expect(document.body.textContent).toEqual(
   *       "ng2[ng1[Hello World!](transclude)](project)");
   * });
   * ```
   */
  bootstrap(element$1, modules, config) {
    const {
      ng1Module,
      ng2BootstrapDeferred,
      ngZone
    } = this.declareNg1Module(modules);
    const upgrade = new UpgradeAdapterRef();
    // Make sure resumeBootstrap() only exists if the current bootstrap is deferred
    const windowAngular = window['angular'];
    windowAngular.resumeBootstrap = undefined;
    ngZone.run(() => {
      bootstrap(element$1, [ng1Module.name], config);
    });
    const ng1BootstrapPromise = new Promise(resolve => {
      if (windowAngular.resumeBootstrap) {
        const originalResumeBootstrap = windowAngular.resumeBootstrap;
        windowAngular.resumeBootstrap = function () {
          windowAngular.resumeBootstrap = originalResumeBootstrap;
          const r = windowAngular.resumeBootstrap.apply(this, arguments);
          resolve();
          return r;
        };
      } else {
        resolve();
      }
    });
    Promise.all([ng2BootstrapDeferred.promise, ng1BootstrapPromise]).then(([ng1Injector]) => {
      element(element$1).data(controllerKey(INJECTOR_KEY), this.moduleRef.injector);
      this.moduleRef.injector.get(NgZone).run(() => {
        // @ts-expect-error
        upgrade._bootstrapDone(this.moduleRef, ng1Injector);
      });
    }, onError);
    return upgrade;
  }
  /**
   * Allows AngularJS service to be accessible from Angular.
   *
   * @usageNotes
   * ### Example
   *
   * ```
   * class Login { ... }
   * class Server { ... }
   *
   * @Injectable()
   * class Example {
   *   constructor(@Inject('server') server, login: Login) {
   *     ...
   *   }
   * }
   *
   * const module = angular.module('myExample', []);
   * module.service('server', Server);
   * module.service('login', Login);
   *
   * const adapter = new UpgradeAdapter(MyNg2Module);
   * adapter.upgradeNg1Provider('server');
   * adapter.upgradeNg1Provider('login', {asToken: Login});
   *
   * adapter.bootstrap(document.body, ['myExample']).ready((ref) => {
   *   const example: Example = ref.ng2Injector.get(Example);
   * });
   *
   * ```
   */
  upgradeNg1Provider(name, options) {
    const token = options && options.asToken || name;
    this.upgradedProviders.push({
      provide: token,
      useFactory: $injector => $injector.get(name),
      deps: [$INJECTOR]
    });
  }
  /**
   * Allows Angular service to be accessible from AngularJS.
   *
   * @usageNotes
   * ### Example
   *
   * ```
   * class Example {
   * }
   *
   * const adapter = new UpgradeAdapter(MyNg2Module);
   *
   * const module = angular.module('myExample', []);
   * module.factory('example', adapter.downgradeNg2Provider(Example));
   *
   * adapter.bootstrap(document.body, ['myExample']).ready((ref) => {
   *   const example: Example = ref.ng1Injector.get('example');
   * });
   *
   * ```
   */
  downgradeNg2Provider(token) {
    return downgradeInjectable(token);
  }
  /**
   * Declare the AngularJS upgrade module for this adapter without bootstrapping the whole
   * hybrid application.
   *
   * This method is automatically called by `bootstrap()` and `registerForNg1Tests()`.
   *
   * @param modules The AngularJS modules that this upgrade module should depend upon.
   * @returns The AngularJS upgrade module that is declared by this method
   *
   * @usageNotes
   * ### Example
   *
   * ```
   * const upgradeAdapter = new UpgradeAdapter(MyNg2Module);
   * upgradeAdapter.declareNg1Module(['heroApp']);
   * ```
   */
  declareNg1Module(modules = []) {
    const delayApplyExps = [];
    let original$applyFn;
    let rootScopePrototype;
    const upgradeAdapter = this;
    const ng1Module = module_(this.idPrefix, modules);
    const platformRef = platformBrowserDynamic();
    const ngZone = new NgZone({
      enableLongStackTrace: Zone.hasOwnProperty('longStackTraceZoneSpec')
    });
    const ng2BootstrapDeferred = new Deferred();
    ng1Module.constant(UPGRADE_APP_TYPE_KEY, 1 /* UpgradeAppType.Dynamic */).factory(INJECTOR_KEY, () => this.moduleRef.injector.get(Injector)).factory(LAZY_MODULE_REF, [INJECTOR_KEY, injector => ({
      injector
    })]).constant(NG_ZONE_KEY, ngZone).factory(COMPILER_KEY, () => this.moduleRef.injector.get(Compiler)).config(['$provide', '$injector', (provide, ng1Injector) => {
      provide.decorator($ROOT_SCOPE, ['$delegate', function (rootScopeDelegate) {
        // Capture the root apply so that we can delay first call to $apply until we
        // bootstrap Angular and then we replay and restore the $apply.
        rootScopePrototype = rootScopeDelegate.constructor.prototype;
        if (rootScopePrototype.hasOwnProperty('$apply')) {
          original$applyFn = rootScopePrototype.$apply;
          rootScopePrototype.$apply = exp => delayApplyExps.push(exp);
        } else {
          throw new Error("Failed to find '$apply' on '$rootScope'!");
        }
        return rootScopeDelegate;
      }]);
      if (ng1Injector.has($$TESTABILITY)) {
        provide.decorator($$TESTABILITY, ['$delegate', function (testabilityDelegate) {
          const originalWhenStable = testabilityDelegate.whenStable;
          // Cannot use arrow function below because we need the context
          const newWhenStable = function (callback) {
            originalWhenStable.call(this, function () {
              const ng2Testability = upgradeAdapter.moduleRef.injector.get(Testability);
              if (ng2Testability.isStable()) {
                callback.apply(this, arguments);
              } else {
                ng2Testability.whenStable(newWhenStable.bind(this, callback));
              }
            });
          };
          testabilityDelegate.whenStable = newWhenStable;
          return testabilityDelegate;
        }]);
      }
    }]);
    ng1Module.run(['$injector', '$rootScope', (ng1Injector, rootScope) => {
      UpgradeNg1ComponentAdapterBuilder.resolve(this.ng1ComponentsToBeUpgraded, ng1Injector).then(() => {
        // At this point we have ng1 injector and we have prepared
        // ng1 components to be upgraded, we now can bootstrap ng2.
        let DynamicNgUpgradeModule = class DynamicNgUpgradeModule {
          ngDoBootstrap() {}
        };
        DynamicNgUpgradeModule = __decorate([NgModule({
          jit: true,
          providers: [{
            provide: $INJECTOR,
            useFactory: () => ng1Injector
          }, {
            provide: $COMPILE,
            useFactory: () => ng1Injector.get($COMPILE)
          }, this.upgradedProviders],
          imports: [resolveForwardRef(this.ng2AppModule)]
        })], DynamicNgUpgradeModule);
        platformRef.bootstrapModule(DynamicNgUpgradeModule, [this.compilerOptions, {
          ngZone
        }]).then(ref => {
          this.moduleRef = ref;
          ngZone.run(() => {
            if (rootScopePrototype) {
              rootScopePrototype.$apply = original$applyFn; // restore original $apply
              while (delayApplyExps.length) {
                rootScope.$apply(delayApplyExps.shift());
              }
              rootScopePrototype = null;
            }
          });
        }).then(() => ng2BootstrapDeferred.resolve(ng1Injector), onError).then(() => {
          let subscription = ngZone.onMicrotaskEmpty.subscribe({
            next: () => {
              if (rootScope.$$phase) {
                if (typeof ngDevMode === 'undefined' || ngDevMode) {
                  console.warn('A digest was triggered while one was already in progress. This may mean that something is triggering digests outside the Angular zone.');
                }
                return rootScope.$evalAsync(() => {});
              }
              return rootScope.$digest();
            }
          });
          rootScope.$on('$destroy', () => {
            subscription.unsubscribe();
          });
          // Destroy the AngularJS app once the Angular `PlatformRef` is destroyed.
          // This does not happen in a typical SPA scenario, but it might be useful for
          // other use-cases where disposing of an Angular/AngularJS app is necessary
          // (such as Hot Module Replacement (HMR)).
          // See https://github.com/angular/angular/issues/39935.
          platformRef.onDestroy(() => destroyApp(ng1Injector));
        });
      }).catch(e => ng2BootstrapDeferred.reject(e));
    }]);
    return {
      ng1Module,
      ng2BootstrapDeferred,
      ngZone
    };
  }
}
/**
 * Use `UpgradeAdapterRef` to control a hybrid AngularJS / Angular application.
 *
 * @deprecated Deprecated since v5. Use `upgrade/static` instead, which also supports
 * [Ahead-of-Time compilation](tools/cli/aot-compiler).
 * @publicApi
 */
class UpgradeAdapterRef {
  constructor() {
    /* @internal */
    this._readyFn = null;
    this.ng1RootScope = null;
    this.ng1Injector = null;
    this.ng2ModuleRef = null;
    this.ng2Injector = null;
  }
  /* @internal */
  _bootstrapDone(ngModuleRef, ng1Injector) {
    this.ng2ModuleRef = ngModuleRef;
    this.ng2Injector = ngModuleRef.injector;
    this.ng1Injector = ng1Injector;
    this.ng1RootScope = ng1Injector.get($ROOT_SCOPE);
    this._readyFn && this._readyFn(this);
  }
  /**
   * Register a callback function which is notified upon successful hybrid AngularJS / Angular
   * application has been bootstrapped.
   *
   * The `ready` callback function is invoked inside the Angular zone, therefore it does not
   * require a call to `$apply()`.
   */
  ready(fn) {
    this._readyFn = fn;
  }
  /**
   * Dispose of running hybrid AngularJS / Angular application.
   */
  dispose() {
    this.ng1Injector.get($ROOT_SCOPE).$destroy();
    this.ng2ModuleRef.destroy();
  }
}

export { UpgradeAdapter, UpgradeAdapterRef, VERSION };
//# sourceMappingURL=angular-upgrade.js.map
