text: /*!
   * Angular Material Design
   * https://github.com/angular/material
   * @license MIT
   * v1.0.0-rc1-master-325d83e
   */
  (function( window, angular, undefined ){
  "use strict";
  
  /**
   * @ngdoc module
   * @name material.components.dialog
   */
  angular
    .module('material.components.dialog', [
      'material.core',
      'material.components.backdrop'
    ])
    .directive('mdDialog', MdDialogDirective)
    .provider('$mdDialog', MdDialogProvider);
  
  function MdDialogDirective($$rAF, $mdTheming, $mdDialog) {
    return {
      restrict: 'E',
      link: function(scope, element, attr) {
        $mdTheming(element);
        $$rAF(function() {
          var images;
          var content = element[0].querySelector('md-dialog-content');
  
          if (content) {
            images = content.getElementsByTagName('img');
            addOverflowClass();
            //-- delayed image loading may impact scroll height, check after images are loaded
            angular.element(images).on('load', addOverflowClass);
          }
  
          scope.$on('$destroy', function() {
            $mdDialog.destroy();
          });
  
          /**
           *
           */
          function addOverflowClass() {
            element.toggleClass('md-content-overflow', content.scrollHeight > content.clientHeight);
          }
  
  
        });
      }
    };
  }
  MdDialogDirective.$inject = ["$$rAF", "$mdTheming", "$mdDialog"];
  
  /**
   * @ngdoc service
   * @name $mdDialog
   * @module material.components.dialog
   *
   * @description
   * `$mdDialog` opens a dialog over the app to inform users about critical information or require
   *  them to make decisions. There are two approaches for setup: a simple promise API
   *  and regular object syntax.
   *
   * ## Restrictions
   *
   * - The dialog is always given an isolate scope.
   * - The dialog's template must have an outer `<md-dialog>` element.
   *   Inside, use an `<md-dialog-content>` element for the dialog's content, and use
   *   an element with class `md-actions` for the dialog's actions.
   * - Dialogs must cover the entire application to keep interactions inside of them.
   * Use the `parent` option to change where dialogs are appended.
   *
   * ## Sizing
   * - Complex dialogs can be sized with `flex="percentage"`, i.e. `flex="66"`.
   * - Default max-width is 80% of the `rootElement` or `parent`.
   *
   * ## Css
   * - `.md-dialog-content` - class that sets the padding on the content as the spec file
   *
   * @usage
   * <hljs lang="html">
   * <div  ng-app="demoApp" ng-controller="EmployeeController">
   *   <div>
   *     <md-button ng-click="showAlert()" class="md-raised md-warn">
   *       Employee Alert!
   *       </md-button>
   *   </div>
   *   <div>
   *     <md-button ng-click="showDialog($event)" class="md-raised">
   *       Custom Dialog
   *       </md-button>
   *   </div>
   *   <div>
   *     <md-button ng-click="closeAlert()" ng-disabled="!hasAlert()" class="md-raised">
   *       Close Alert
   *     </md-button>
   *   </div>
   *   <div>
   *     <md-button ng-click="showGreeting($event)" class="md-raised md-primary" >
   *       Greet Employee
   *       </md-button>
   *   </div>
   * </div>
   * </hljs>
   *
   * ### JavaScript: object syntax
   * <hljs lang="js">
   * (function(angular, undefined){
   *   "use strict";
   *
   *   angular
   *    .module('demoApp', ['ngMaterial'])
   *    .controller('AppCtrl', AppController);
   *
   *   function AppController($scope, $mdDialog) {
   *     var alert;
   *     $scope.showAlert = showAlert;
   *     $scope.showDialog = showDialog;
   *     $scope.items = [1, 2, 3];
   *
   *     // Internal method
   *     function showAlert() {
   *       alert = $mdDialog.alert({
   *         title: 'Attention',
   *         content: 'This is an example of how easy dialogs can be!',
   *         ok: 'Close'
   *       });
   *
   *       $mdDialog
   *         .show( alert )
   *         .finally(function() {
   *           alert = undefined;
   *         });
   *     }
   *
   *     function showDialog($event) {
   *        var parentEl = angular.element(document.body);
   *        $mdDialog.show({
   *          parent: parentEl,
   *          targetEvent: $event,
   *          template:
   *            '<md-dialog aria-label="List dialog">' +
   *            '  <md-dialog-content>'+
   *            '    <md-list>'+
   *            '      <md-list-item ng-repeat="item in items">'+
   *            '       <p>Number {{item}}</p>' +
   *            '      </md-item>'+
   *            '    </md-list>'+
   *            '  </md-dialog-content>' +
   *            '  <div class="md-actions">' +
   *            '    <md-button ng-click="closeDialog()" class="md-primary">' +
   *            '      Close Dialog' +
   *            '    </md-button>' +
   *            '  </div>' +
   *            '</md-dialog>',
   *          locals: {
   *            items: $scope.items
   *          },
   *          controller: DialogController
   *       });
   *       function DialogController($scope, $mdDialog, items) {
   *         $scope.items = items;
   *         $scope.closeDialog = function() {
   *           $mdDialog.hide();
   *         }
   *       }
   *     }
   *   }
   * })(angular);
   * </hljs>
   *
   * ### JavaScript: promise API syntax, custom dialog template
   * <hljs lang="js">
   * (function(angular, undefined){
   *   "use strict";
   *
   *   angular
   *     .module('demoApp', ['ngMaterial'])
   *     .controller('EmployeeController', EmployeeEditor)
   *     .controller('GreetingController', GreetingController);
   *
   *   // Fictitious Employee Editor to show how to use simple and complex dialogs.
   *
   *   function EmployeeEditor($scope, $mdDialog) {
   *     var alert;
   *
   *     $scope.showAlert = showAlert;
   *     $scope.closeAlert = closeAlert;
   *     $scope.showGreeting = showCustomGreeting;
   *
   *     $scope.hasAlert = function() { return !!alert };
   *     $scope.userName = $scope.userName || 'Bobby';
   *
   *     // Dialog #1 - Show simple alert dialog and cache
   *     // reference to dialog instance
   *
   *     function showAlert() {
   *       alert = $mdDialog.alert()
   *         .title('Attention, ' + $scope.userName)
   *         .content('This is an example of how easy dialogs can be!')
   *         .ok('Close');
   *
   *       $mdDialog
   *           .show( alert )
   *           .finally(function() {
   *             alert = undefined;
   *           });
   *     }
   *
   *     // Close the specified dialog instance and resolve with 'finished' flag
   *     // Normally this is not needed, just use '$mdDialog.hide()' to close
   *     // the most recent dialog popup.
   *
   *     function closeAlert() {
   *       $mdDialog.hide( alert, "finished" );
   *       alert = undefined;
   *     }
   *
   *     // Dialog #2 - Demonstrate more complex dialogs construction and popup.
   *
   *     function showCustomGreeting($event) {
   *         $mdDialog.show({
   *           targetEvent: $event,
   *           template:
   *             '<md-dialog>' +
   *
   *             '  <md-dialog-content>Hello {{ employee }}!</md-dialog-content>' +
   *
   *             '  <div class="md-actions">' +
   *             '    <md-button ng-click="closeDialog()" class="md-primary">' +
   *             '      Close Greeting' +
   *             '    </md-button>' +
   *             '  </div>' +
   *             '</md-dialog>',
   *           controller: 'GreetingController',
   *           onComplete: afterShowAnimation,
   *           locals: { employee: $scope.userName }
   *         });
   *
   *         // When the 'enter' animation finishes...
   *
   *         function afterShowAnimation(scope, element, options) {
   *            // post-show code here: DOM element focus, etc.
   *         }
   *     }
   *
   *     // Dialog #3 - Demonstrate use of ControllerAs and passing $scope to dialog
   *     //             Here we used ng-controller="GreetingController as vm" and
   *     //             $scope.vm === <controller instance>
   *
   *     function showCustomGreeting() {
   *
   *        $mdDialog.show({
   *           clickOutsideToClose: true,
   *
   *           scope: $scope,        // use parent scope in template
   *           preserveScope: true,  // do not forget this if use parent scope
  
   *           // Since GreetingController is instantiated with ControllerAs syntax
   *           // AND we are passing the parent '$scope' to the dialog, we MUST
   *           // use 'vm.<xxx>' in the template markup
   *
   *           template: '<md-dialog>' +
   *                     '  <md-dialog-content>' +
   *                     '     Hi There {{vm.employee}}' +
   *                     '  </md-dialog-content>' +
   *                     '</md-dialog>',
   *
   *           controller: function DialogController($scope, $mdDialog) {
   *             $scope.closeDialog = function() {
   *               $mdDialog.hide();
   *             }
   *           }
   *        });
   *     }
   *
   *   }
   *
   *   // Greeting controller used with the more complex 'showCustomGreeting()' custom dialog
   *
   *   function GreetingController($scope, $mdDialog, employee) {
   *     // Assigned from construction <code>locals</code> options...
   *     $scope.employee = employee;
   *
   *     $scope.closeDialog = function() {
   *       // Easily hides most recent dialog shown...
   *       // no specific instance reference is needed.
   *       $mdDialog.hide();
   *     };
   *   }
   *
   * })(angular);
   * </hljs>
   */
  
  /**
   * @ngdoc method
   * @name $mdDialog#alert
   *
   * @description
   * Builds a preconfigured dialog with the specified message.
   *
   * @returns {obj} an `$mdDialogPreset` with the chainable configuration methods:
   *
   * - $mdDialogPreset#title(string) - sets title to string
   * - $mdDialogPreset#content(string) - sets content / message to string
   * - $mdDialogPreset#ok(string) - sets okay button text to string
   * - $mdDialogPreset#theme(string) - sets the theme of the dialog
   *
   */
  
  /**
   * @ngdoc method
   * @name $mdDialog#confirm
   *
   * @description
   * Builds a preconfigured dialog with the specified message. You can call show and the promise returned
   * will be resolved only if the user clicks the confirm action on the dialog.
   *
   * @returns {obj} an `$mdDialogPreset` with the chainable configuration methods:
   *
   * Additionally, it supports the following methods:
   *
   * - $mdDialogPreset#title(string) - sets title to string
   * - $mdDialogPreset#content(string) - sets content / message to string
   * - $mdDialogPreset#ok(string) - sets okay button text to string
   * - $mdDialogPreset#cancel(string) - sets cancel button text to string
   * - $mdDialogPreset#theme(string) - sets the theme of the dialog
   *
   */
  
  /**
   * @ngdoc method
   * @name $mdDialog#show
   *
   * @description
   * Show a dialog with the specified options.
   *
   * @param {object} optionsOrPreset Either provide an `$mdDialogPreset` returned from `alert()`, and
   * `confirm()`, or an options object with the following properties:
   *   - `templateUrl` - `{string=}`: The url of a template that will be used as the content
   *   of the dialog.
   *   - `template` - `{string=}`: Same as templateUrl, except this is an actual template string.
   *   - `autoWrap` - `{boolean=}`: Whether or not to automatically wrap the template with a
   *     `<md-dialog>` tag if one is not provided. Defaults to true. Can be disabled if you provide a
   *     custom dialog directive.
   *   - `targetEvent` - `{DOMClickEvent=}`: A click's event object. When passed in as an option,
   *     the location of the click will be used as the starting point for the opening animation
   *     of the the dialog.
   *   - `openFrom` - `{string|Element|object}`: The query selector, DOM element or the Rect object
   *     that is used to determine the bounds (top, left, height, width) from which the Dialog will
   *     originate.
   *   - `closeTo` - `{string|Element|object}`: The query selector, DOM element or the Rect object
   *     that is used to determine the bounds (top, left, height, width) to which the Dialog will
   *     target.
   *   - `scope` - `{object=}`: the scope to link the template / controller to. If none is specified,
   *     it will create a new isolate scope.
   *     This scope will be destroyed when the dialog is removed unless `preserveScope` is set to true.
   *   - `preserveScope` - `{boolean=}`: whether to preserve the scope when the element is removed. Default is false
   *   - `disableParentScroll` - `{boolean=}`: Whether to disable scrolling while the dialog is open.
   *     Default true.
   *   - `hasBackdrop` - `{boolean=}`: Whether there should be an opaque backdrop behind the dialog.
   *     Default true.
   *   - `clickOutsideToClose` - `{boolean=}`: Whether the user can click outside the dialog to
   *     close it. Default false.
   *   - `escapeToClose` - `{boolean=}`: Whether the user can press escape to close the dialog.
   *     Default true.
   *   - `focusOnOpen` - `{boolean=}`: An option to override focus behavior on open. Only disable if
   *     focusing some other way, as focus management is required for dialogs to be accessible.
   *     Defaults to true.
   *   - `controller` - `{string=}`: The controller to associate with the dialog. The controller
   *     will be injected with the local `$mdDialog`, which passes along a scope for the dialog.
   *   - `locals` - `{object=}`: An object containing key/value pairs. The keys will be used as names
   *     of values to inject into the controller. For example, `locals: {three: 3}` would inject
   *     `three` into the controller, with the value 3. If `bindToController` is true, they will be
   *     copied to the controller instead.
   *   - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in.
   *     These values will not be available until after initialization.
   *   - `resolve` - `{object=}`: Similar to locals, except it takes promises as values, and the
   *     dialog will not open until all of the promises resolve.
   *   - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.
   *   - `parent` - `{element=}`: The element to append the dialog to. Defaults to appending
   *     to the root element of the application.
   *   - `onShowing` `{function=} Callback function used to announce the show() action is
   *     starting.
   *   - `onComplete` `{function=}`: Callback function used to announce when the show() action is
   *     finished.
   *   - `onRemoving` `{function=}`: Callback function used to announce the close/hide() action is
   *     starting. This allows developers to run custom animations in parallel the close animations.
   *
   * @returns {promise} A promise that can be resolved with `$mdDialog.hide()` or
   * rejected with `$mdDialog.cancel()`.
   */
  
  /**
   * @ngdoc method
   * @name $mdDialog#hide
   *
   * @description
   * Hide an existing dialog and resolve the promise returned from `$mdDialog.show()`.
   *
   * @param {*=} response An argument for the resolved promise.
   *
   * @returns {promise} A promise that is resolved when the dialog has been closed.
   */
  
  /**
   * @ngdoc method
   * @name $mdDialog#cancel
   *
   * @description
   * Hide an existing dialog and reject the promise returned from `$mdDialog.show()`.
   *
   * @param {*=} response An argument for the rejected promise.
   *
   * @returns {promise} A promise that is resolved when the dialog has been closed.
   */
  
  function MdDialogProvider($$interimElementProvider) {
  
    advancedDialogOptions.$inject = ["$mdDialog", "$mdTheming"];
    dialogDefaultOptions.$inject = ["$mdDialog", "$mdAria", "$mdUtil", "$mdConstant", "$animate", "$document", "$window", "$rootElement"];
    return $$interimElementProvider('$mdDialog')
      .setDefaults({
        methods: ['disableParentScroll', 'hasBackdrop', 'clickOutsideToClose', 'escapeToClose', 'targetEvent', 'closeTo', 'openFrom', 'parent'],
        options: dialogDefaultOptions
      })
      .addPreset('alert', {
        methods: ['title', 'content', 'ariaLabel', 'ok', 'theme', 'css'],
        options: advancedDialogOptions
      })
      .addPreset('confirm', {
        methods: ['title', 'content', 'ariaLabel', 'ok', 'cancel', 'theme', 'css'],
        options: advancedDialogOptions
      });
  
    /* ngInject */
    function advancedDialogOptions($mdDialog, $mdTheming) {
      return {
        template: [
          '<md-dialog md-theme="{{ dialog.theme }}" aria-label="{{ dialog.ariaLabel }}" ng-class="dialog.css">',
          ' <md-dialog-content class="md-dialog-content" role="document" tabIndex="-1">',
          '   <h2 class="md-title">{{ dialog.title }}</h2>',
          '   <div class="md-dialog-content-body" md-template="::dialog.mdContent"></div>',
          ' </md-dialog-content>',
          ' <div class="md-actions">',
          '   <md-button ng-if="dialog.$type == \'confirm\'"' +
          '     ng-click="dialog.abort()" class="md-primary">',
          '     {{ dialog.cancel }}',
          '   </md-button>',
          '   <md-button ng-click="dialog.hide()" class="md-primary" md-autofocus="dialog.$type!=\'confirm\'">',
          '     {{ dialog.ok }}',
          '   </md-button>',
          ' </div>',
          '</md-dialog>'
        ].join('').replace(/\s\s+/g, ''),
        controller: function mdDialogCtrl() {
          this.hide = function() {
            $mdDialog.hide(true);
          };
          this.abort = function() {
            $mdDialog.cancel();
          };
        },
        controllerAs: 'dialog',
        bindToController: true,
        theme: $mdTheming.defaultTheme()
      };
    }
  
    /* ngInject */
    function dialogDefaultOptions($mdDialog, $mdAria, $mdUtil, $mdConstant, $animate, $document, $window, $rootElement) {
      return {
        hasBackdrop: true,
        isolateScope: true,
        onShow: onShow,
        onRemove: onRemove,
        clickOutsideToClose: false,
        escapeToClose: true,
        targetEvent: null,
        closeTo: null,
        openFrom: null,
        focusOnOpen: true,
        disableParentScroll: true,
        autoWrap: true,
        transformTemplate: function(template, options) {
          return '<div class="md-dialog-container">' + validatedTemplate(template) + '</div>';
  
          /**
           * The specified template should contain a <md-dialog> wrapper element....
           */
          function validatedTemplate(template) {
            if (options.autoWrap && !/<\/md-dialog>/g.test(template)) {
              return '<md-dialog>' + (template || '') + '</md-dialog>';
            } else {
              return template || '';
            }
          }
        }
      };
  
      /**
       * Show method for dialogs
       */
      function onShow(scope, element, options, controller) {
        angular.element($document[0].body).addClass('md-dialog-is-showing');
  
        wrapSimpleContent();
  
        captureParentAndFromToElements(options);
        configureAria(element.find('md-dialog'), options);
        showBackdrop(scope, element, options);
  
        return dialogPopIn(element, options)
          .then(function() {
            activateListeners(element, options);
            lockScreenReader(element, options);
            focusOnOpen();
          });
  
        /**
         * For alerts, focus on content... otherwise focus on
         * the close button (or equivalent)
         */
        function focusOnOpen() {
          if (options.focusOnOpen) {
            var target = $mdUtil.findFocusTarget(element) || findCloseButton();
            target.focus();
          }
  
          /**
           *  If no element with class dialog-close, try to find the last
           *  button child in md-actions and assume it is a close button
           */
          function findCloseButton() {
            var closeButton = element[0].querySelector('.dialog-close');
            if (!closeButton) {
              var actionButtons = element[0].querySelectorAll('.md-actions button');
              closeButton = actionButtons[actionButtons.length - 1];
            }
            return angular.element(closeButton);
          }
        }
  
        /**
         * Wrap any simple content [specified via .content("")] in <p></p> tags.
         * otherwise accept HTML content within the dialog content area...
         * NOTE: Dialog uses the md-template directive to safely inject HTML content.
         */
        function wrapSimpleContent() {
          if ( controller ) {
            var HTML_END_TAG = /<\/[\w-]*>/gm;
            var content = controller.content || options.content || "";
  
            var hasHTML = HTML_END_TAG.test(content);
            if (!hasHTML) {
              content = $mdUtil.supplant("<p>{0}</p>", [content]);
            }
  
            // Publish updated dialog content body... to be compiled by mdTemplate directive
            controller.mdContent = content;
          }
        }
  
      }
  
      /**
       * Remove function for all dialogs
       */
      function onRemove(scope, element, options) {
        options.deactivateListeners();
        options.unlockScreenReader();
        options.hideBackdrop(options.$destroy);
  
        // For navigation $destroy events, do a quick, non-animated removal,
        // but for normal closes (from clicks, etc) animate the removal
  
        return !!options.$destroy ? detachAndClean() : animateRemoval().then( detachAndClean );
  
        /**
         * For normal closes, animate the removal.
         * For forced closes (like $destroy events), skip the animations
         */
        function animateRemoval() {
          return dialogPopOut(element, options);
        }
  
        /**
         * Detach the element
         */
        function detachAndClean() {
          angular.element($document[0].body).removeClass('md-dialog-is-showing');
          element.remove();
  
          if (!options.$destroy) options.origin.focus();
        }
      }
  
      /**
       * Capture originator/trigger/from/to element information (if available)
       * and the parent container for the dialog; defaults to the $rootElement
       * unless overridden in the options.parent
       */
      function captureParentAndFromToElements(options) {
            options.origin = angular.extend({
              element: null,
              bounds: null,
              focus: angular.noop
            }, options.origin || {});
  
            options.parent   = getDomElement(options.parent, $rootElement);
            options.closeTo  = getBoundingClientRect(getDomElement(options.closeTo));
            options.openFrom = getBoundingClientRect(getDomElement(options.openFrom));
  
            if ( options.targetEvent ) {
              options.origin   = getBoundingClientRect(options.targetEvent.target, options.origin);
            }
  
            /**
             * Identify the bounding RECT for the target element
             *
             */
            function getBoundingClientRect (element, orig) {
              var source = angular.element((element || {}));
              if (source && source.length) {
                // Compute and save the target element's bounding rect, so that if the
                // element is hidden when the dialog closes, we can shrink the dialog
                // back to the same position it expanded from.
                //
                // Checking if the source is a rect object or a DOM element
                var bounds = {top:0,left:0,height:0,width:0};
                var hasFn = angular.isFunction(source[0].getBoundingClientRect);
  
                return angular.extend(orig || {}, {
                    element : hasFn ? source : undefined,
                    bounds  : hasFn ? source[0].getBoundingClientRect() : angular.extend({}, bounds, source[0]),
                    focus   : angular.bind(source, source.focus),
                });
              }
            }
  
            /**
             * If the specifier is a simple string selector, then query for
             * the DOM element.
             */
            function getDomElement(element, defaultElement) {
              if (angular.isString(element)) {
                var simpleSelector = element,
                  container = $document[0].querySelectorAll(simpleSelector);
                  element = container.length ? container[0] : null;
              }
  
              // If we have a reference to a raw dom element, always wrap it in jqLite
              return angular.element(element || defaultElement);
            }
  
  
          }
  
      /**
       * Listen for escape keys and outside clicks to auto close
       */
      function activateListeners(element, options) {
        var window = angular.element($window);
        var onWindowResize = $mdUtil.debounce(function(){
          stretchDialogContainerToViewport(element, options);
        }, 60);
  
        var removeListeners = [];
        var smartClose = function() {
          // Only 'confirm' dialogs have a cancel button... escape/clickOutside will
          // cancel or fallback to hide.
          var closeFn = ( options.$type == 'alert' ) ? $mdDialog.hide : $mdDialog.cancel;
          $mdUtil.nextTick(closeFn, true);
        };
  
        if (options.escapeToClose) {
          var target = options.parent;
          var keyHandlerFn = function(ev) {
            if (ev.keyCode === $mdConstant.KEY_CODE.ESCAPE) {
              ev.stopPropagation();
              ev.preventDefault();
  
              smartClose();
            }
          };
  
          // Add keydown listeners
          element.on('keydown', keyHandlerFn);
          target.on('keydown', keyHandlerFn);
          window.on('resize', onWindowResize);
  
          // Queue remove listeners function
          removeListeners.push(function() {
  
            element.off('keydown', keyHandlerFn);
            target.off('keydown', keyHandlerFn);
            window.off('resize', onWindowResize);
  
          });
        }
        if (options.clickOutsideToClose) {
          var target = element;
          var sourceElem;
  
          // Keep track of the element on which the mouse originally went down
          // so that we can only close the backdrop when the 'click' started on it.
          // A simple 'click' handler does not work,
          // it sets the target object as the element the mouse went down on.
          var mousedownHandler = function(ev) {
            sourceElem = ev.target;
          };
  
          // We check if our original element and the target is the backdrop
          // because if the original was the backdrop and the target was inside the dialog
          // we don't want to dialog to close.
          var mouseupHandler = function(ev) {
            if (sourceElem === target[0] && ev.target === target[0]) {
              ev.stopPropagation();
              ev.preventDefault();
  
              smartClose();
            }
          };
  
          // Add listeners
          target.on('mousedown', mousedownHandler);
          target.on('mouseup', mouseupHandler);
  
          // Queue remove listeners function
          removeListeners.push(function() {
            target.off('mousedown', mousedownHandler);
            target.off('mouseup', mouseupHandler);
          });
        }
  
        // Attach specific `remove` listener handler
        options.deactivateListeners = function() {
          removeListeners.forEach(function(removeFn) {
            removeFn();
          });
          options.deactivateListeners = null;
        };
      }
  
      /**
       * Show modal backdrop element...
       */
      function showBackdrop(scope, element, options) {
  
        if (options.disableParentScroll) {
          // !! DO this before creating the backdrop; since disableScrollAround()
          //    configures the scroll offset; which is used by mdBackDrop postLink()
          options.restoreScroll = $mdUtil.disableScrollAround(element, options.parent);
        }
  
        if (options.hasBackdrop) {
          options.backdrop = $mdUtil.createBackdrop(scope, "md-dialog-backdrop md-opaque");
          $animate.enter(options.backdrop, options.parent);
        }
  
        /**
         * Hide modal backdrop element...
         */
        options.hideBackdrop = function hideBackdrop($destroy) {
          if (options.backdrop) {
            if ( !!$destroy ) options.backdrop.remove();
            else              $animate.leave(options.backdrop);
          }
  
          if (options.disableParentScroll) {
            options.restoreScroll();
            delete options.restoreScroll;
          }
  
          options.hideBackdrop = null;
        }
      }
  
      /**
       * Inject ARIA-specific attributes appropriate for Dialogs
       */
      function configureAria(element, options) {
  
        var role = (options.$type === 'alert') ? 'alertdialog' : 'dialog';
        var dialogContent = element.find('md-dialog-content');
        var dialogId = element.attr('id') || ('dialog_' + $mdUtil.nextUid());
  
        element.attr({
          'role': role,
          'tabIndex': '-1'
        });
  
        if (dialogContent.length === 0) {
          dialogContent = element;
        }
  
        dialogContent.attr('id', dialogId);
        element.attr('aria-describedby', dialogId);
  
        if (options.ariaLabel) {
          $mdAria.expect(element, 'aria-label', options.ariaLabel);
        }
        else {
          $mdAria.expectAsync(element, 'aria-label', function() {
            var words = dialogContent.text().split(/\s+/);
            if (words.length > 3) words = words.slice(0, 3).concat('...');
            return words.join(' ');
          });
        }
      }
  
      /**
       * Prevents screen reader interaction behind modal window
       * on swipe interfaces
       */
      function lockScreenReader(element, options) {
        var isHidden = true;
  
        // get raw DOM node
        walkDOM(element[0]);
  
        options.unlockScreenReader = function() {
          isHidden = false;
          walkDOM(element[0]);
  
          options.unlockScreenReader = null;
        };
  
        /**
         * Walk DOM to apply or remove aria-hidden on sibling nodes
         * and parent sibling nodes
         *
         */
        function walkDOM(element) {
          while (element.parentNode) {
            if (element === document.body) {
              return;
            }
            var children = element.parentNode.children;
            for (var i = 0; i < children.length; i++) {
              // skip over child if it is an ascendant of the dialog
              // or a script or style tag
              if (element !== children[i] && !isNodeOneOf(children[i], ['SCRIPT', 'STYLE'])) {
                children[i].setAttribute('aria-hidden', isHidden);
              }
            }
  
            walkDOM(element = element.parentNode);
          }
        }
      }
  
      /**
       * Ensure the dialog container fill-stretches to the viewport
       */
      function stretchDialogContainerToViewport(container, options) {
  
        var isFixed = $window.getComputedStyle($document[0].body).position == 'fixed';
        var backdrop = options.backdrop ? $window.getComputedStyle(options.backdrop[0]) : null;
        var height = backdrop ? Math.min($document[0].body.clientHeight, Math.ceil(Math.abs(parseInt(backdrop.height, 10)))) : 0;
  
        container.css({
          top: (isFixed ? $mdUtil.scrollTop(options.parent) : 0) + 'px',
          height: height ? height + 'px' : '100%'
        });
  
        return container;
      }
  
      /**
       *  Dialog open and pop-in animation
       */
      function dialogPopIn(container, options) {
  
        // Add the `md-dialog-container` to the DOM
        options.parent.append(container);
        stretchDialogContainerToViewport(container, options);
  
        var dialogEl = container.find('md-dialog');
        var animator = $mdUtil.dom.animator;
        var buildTranslateToOrigin = animator.calculateZoomToOrigin;
        var translateOptions = {transitionInClass: 'md-transition-in', transitionOutClass: 'md-transition-out'};
        var from = animator.toTransformCss(buildTranslateToOrigin(dialogEl, options.openFrom || options.origin));
        var to = animator.toTransformCss("");  // defaults to center display (or parent or $rootElement)
  
        return animator
          .translate3d(dialogEl, from, to, translateOptions)
          .then(function(animateReversal) {
            // Build a reversal translate function synched to this translation...
            options.reverseAnimate = function() {
              delete options.reverseAnimate;
  
              if (options.closeTo) {
                // Using the opposite classes to create a close animation to the closeTo element
                translateOptions = {transitionInClass: 'md-transition-out', transitionOutClass: 'md-transition-in'};
                from = to;
                to = animator.toTransformCss(buildTranslateToOrigin(dialogEl, options.closeTo));
  
                return animator
                  .translate3d(dialogEl, from, to,translateOptions);
              }
  
              return animateReversal(
                animator.toTransformCss(
                  // in case the origin element has moved or is hidden,
                  // let's recalculate the translateCSS
                  buildTranslateToOrigin(dialogEl, options.origin)
                )
              );
  
            };
            return true;
          });
      }
  
      /**
       * Dialog close and pop-out animation
       */
      function dialogPopOut(container, options) {
        return options.reverseAnimate();
      }
  
      /**
       * Utility function to filter out raw DOM nodes
       */
      function isNodeOneOf(elem, nodeTypeArray) {
        if (nodeTypeArray.indexOf(elem.nodeName) !== -1) {
          return true;
        }
      }
  
    }
  }
  MdDialogProvider.$inject = ["$$interimElementProvider"];
  
  })(window, window.angular);