{"version":3,"sources":["webpack:///./node_modules/angular-material/angular-material.js","webpack:///./node_modules/angular-material-bottom-sheet-collapsible/bottomSheetCollapsible.js","webpack:///./node_modules/angular-material/angular-material.css","webpack:///./node_modules/angular-animate/index.js","webpack:///./node_modules/angular-material-bottom-sheet-collapsible/bottomSheetCollapsible.css","webpack:///./node_modules/angular-aria/angular-aria.js","webpack:///./node_modules/angular-material/index.js","webpack:///./node_modules/angular-aria/index.js","webpack:///./node_modules/angular-animate/angular-animate.js"],"names":["window","angular","undefined","module","DetectNgTouch","$log","$injector","has","warn","MdCoreConfigure","$provide","$mdThemingProvider","decorator","rAFDecorator","qDecorator","theme","primaryPalette","accentPalette","warnPalette","backgroundPalette","$delegate","throttle","cb","queuedArgs","alreadyQueued","queueCb","context","arguments","this","apply","Array","prototype","slice","call","resolve","when","$inject","config","run","MdAutofocusDirective","$parse","restrict","link","pre","scope","element","attr","attrExp","mdAutoFocus","mdAutofocus","mdSidenavFocus","updateExpression","$watch","value","isUndefined","toggleClass","directive","factory","rgbaToHex","color","match","length","parseInt","toString","toUpperCase","hexToRgba","hex","substr","dig","red","green","blue","rgbToRgba","replace","rgbaToRgb","prefixTestEl","document","createElement","vendorPrefix","testElement","prop","vendorRegex","style","exec","getVendorPrefix","isWebkit","test","SPECIAL_CHARS_REGEXP","vendorProperty","name","ucPrefix","matches","separator","letter","offset","lcPrefix","charAt","toLowerCase","substring","hasStyleProperty","property","isDefined","self","isInputKey","e","keyCode","isNumPadKey","location","isMetaKey","isFnLockKey","isNavigationKey","kc","KEY_CODE","SPACE","ENTER","UP_ARROW","DOWN_ARROW","indexOf","hasModifierKey","ctrlKey","metaKey","altKey","ELEMENT_MAX_PIXELS","BEFORE_NG_ARIA","COMMA","SEMICOLON","ESCAPE","PAGE_UP","PAGE_DOWN","END","HOME","LEFT_ARROW","RIGHT_ARROW","TAB","BACKSPACE","DELETE","CSS","TRANSITIONEND","ANIMATIONEND","TRANSFORM","TRANSFORM_ORIGIN","TRANSITION","TRANSITION_DURATION","ANIMATION_PLAY_STATE","ANIMATION_DURATION","ANIMATION_NAME","ANIMATION_TIMING","ANIMATION_DIRECTION","MEDIA","MEDIA_PRIORITY","MdIterator","items","reloop","trueFn","isArray","_items","concat","count","inRange","contains","itemAt","index","findBy","key","val","filter","item","add","isNumber","splice","remove","first","last","next","bind","findSubsequentItem","previous","hasPrevious","hasNext","backwards","validate","limit","curIndex","nextIndex","foundItem","iterator","mdMediaFactory","$mdConstant","$rootScope","$window","queries","mqls","results","normalizeCache","$mdMedia","getResponsiveAttribute","attrs","attrName","i","mediaName","normalizedName","getNormalizedName","getQuery","watchResponsiveAttributes","attrNames","watchFn","unwatchFns","forEach","push","$observe","fn","query","validated","result","matchMedia","addListener","onQueryChange","media","$evalAsync","$normalize","MdPrefixer","initialAttributes","buildSelector","PREFIXES","_buildSelector","_buildList","buildList","hasAttribute","attribute","_getNativeElement","prefixedAttrs","removeAttribute","prefixedAttribute","attributes","prefix","map","join","nodeType","prefixer","UtilFactory","isIos","isAndroid","isFirefox","nextUniqueId","navigator","userAgent","vendor","opera","$document","$timeout","$compile","$$mdAnimate","$interpolate","$rootElement","$$rAF","startSymbol","endSymbol","usesStandardSymbols","node","body","hasComputedStyle","target","expectedVal","hasValue","computedStyles","getComputedStyle","validateCssValue","String","hasPx","hasPercent","$mdUtil","dom","now","performance","Date","getTime","getModelOption","ngModelCtrl","optionName","$options","getOption","isRtl","hasOwnProperty","dir","bidi","lValue","rValue","ltr","elem","css","bidiProperty","lProperty","rProperty","clientRect","offsetParent","isOffsetRect","getNode","nodeRect","getBoundingClientRect","offsetRect","left","top","width","height","nodesToArray","nodes","getViewportTop","disableScrollAround","_count","_viewPortTop","scrollY","pageYOffset","findFocusTarget","containerEl","attributeVal","elToFocus","AUTO_FOCUS","scanForFocusable","selector","elFound","querySelectorAll","it","hasClass","parent","options","Math","max","_restoreScroll","restoreBody","documentElement","prevDocumentStyle","cssText","prevBodyStyle","viewportTop","clientWidth","hasVerticalScrollbar","scrollHeight","clientHeight","scrollElement","scrollTop","position","overflow","disableBodyScroll","restoreElement","elementToDisable","scrollMaskOptions","scrollMask","wrappedElementToDisable","disableScrollMask","append","preventDefault","$event","on","off","parentNode","removeChild","disableElementScroll","enableScrolling","restoreFn","floatingScrollbars","cached","tempNode","children","appendChild","offsetWidth","childNodes","forceFocus","addEventListener","focusOnClick","ev","$focus","focus","stopImmediatePropagation","removeEventListener","newEvent","createEvent","initMouseEvent","$material","dispatchEvent","createBackdrop","addClass","supplant","template","values","pattern","a","b","p","split","r","s","fakeNgModel","$fake","$setTouched","noop","$setViewValue","$viewValue","$render","$viewChangeListeners","$isEmpty","$parsers","$formatters","debounce","func","wait","invokeApply","timer","args","cancel","delay","recent","time","start","valueOnUse","getter","params","Object","defineProperty","get","nextUid","disconnectScope","$root","$$destroyed","$parent","$$disconnected","$$childHead","$$nextSibling","$$childTail","$$prevSibling","reconnectScope","child","getSiblings","tagName","upperCasedTagName","sibling","getClosest","el","validateWith","onlyParent","isString","nodeName","elementContains","Node","arg","compareDocumentPosition","extractElementByName","scanDeep","warnNotFound","found","scanTree","outerHTML","len","scanLevel","j","numChild","scanChildren","initOptionalProperties","defaults","$$isolateBindings","binding","optional","attrIsDefined","nextTick","callback","digest","timeout","queue","queueItem","$digest","processTemplate","getParentWithPointerEvents","getNearestContentElement","current","checkStickySupport","stickyProp","testEl","stickyProps","parseAttributeBoolean","negatedCheck","isParentFormSubmitted","form","controller","$submitted","animateScrollTo","scrollEnd","duration","scrollStart","scrollChange","scrollingDown","startTime","scrollChunk","newPosition","easeDuration","currentTime","change","ts","ease","uniq","array","getInnerHTML","serializer","XMLSerializer","serializeToString","getOuterHTML","msie","documentMode","getTouchAction","vendorPrefixes","getEventPath","event","path","currentTarget","parentElement","sanitize","term","isDisabled","isVisible","hasGeometry","visibility","isTabbable","frameElement","getFrameElement","getWindow","getTabIndexValue","tabIndexValue","isPotentiallyTabbableIOS","tabIndex","isFocusable","isPotentiallyFocusable","isHiddenInput","isNativeFormElement","isAnchorWithHref","hasValidTabIndex","inputType","type","getAttribute","isNaN","offsetHeight","getClientRects","error","ownerDocument","defaultView","isInputElement","isAnchorElement","getFirstTabbableElement","root","tabbableChild","ELEMENT_NODE","getLastTabbableElement","animator","blur","$q","$animateCss","translate3d","from","to","transitionInClass","removeClass","transitionOutClass","then","reverseTranslate","newFrom","waitTransitionEnd","opts","TIMEOUT","reject","styles","cachedTransitionStyles","transitionDuration","transition","transitionProperty","finished","calculateTransformValues","originator","container","origin","bounds","originBnds","copyRect","dialogRect","dialogCenterPt","centerPointFor","originCenterPt","centerX","x","centerY","y","scaleX","round","min","scaleY","calculateZoomToOrigin","buildZoom","calculateSlideToOrigin","buildSlide","toCss","raw","convertToVendor","toTransformCss","transform","addTransition","source","destination","right","bottom","rect","targetRect","AnimateDomUtils","version","minor","WEBKIT","WebkitAppearance","PREFIX","TRANSITION_EVENTS","ANIMATION_EVENTS","$$AnimateRunnerFactory","$$rAFMutex","AnimateRunner","host","setHost","_doneCallbacks","_runInAnimationFrame","_state","done","progress","getPromise","promise","status","resolveHandler","rejectHandler","handler","pause","resume","end","_resolve","complete","response","all","runners","onProgress","runner","camelCase","str","passed","$$AnimateRunner","$$forceReflow","$$jqLite","$animate","applyClasses","parseMaxTime","maxValue","parseFloat","cancelLastRAFRequest","rafWaitQueue","applyAnimationFromStyles","applyAnimationToStyles","getDomNode","blockTransition","bool","temporaryStyles","areAnimationsAllowed","enabled","hasCompleteStyles","hasCompleteClasses","transitionStyle","keyframeStyle","hasCompleteAnimation","events","eventFn","animationClosed","close","entry","timings","cs","tdr","adr","tdy","ady","animationDuration","animationDelay","transitionDelay","computeTimings","moreStyles","easing","maxDelayTime","maxDuration","maxDurationTime","stopPropagation","originalEvent","timeStamp","elapsedTime","toFixed","pageWidth","applyAnimationStyles","MdAriaService","showWarnings","expect","expectAsync","expectWithText","content","getText","expectWithoutText","hasAriaLabel","parentHasAriaLabel","level","performCheck","defaultValue","hasChildren","hasChildNodes","hasAttr","currentStyle","display","childHasAttribute","trim","defaultValueGetter","walker","createTreeWalker","NodeFilter","SHOW_TEXT","text","nextNode","isAriaHiddenNode","textContent","provider","disableWarnings","$get","MdCompilerProvider","MdCompilerService","$templateRequest","$controller","compile","contentElement","_prepareContentElement","_compileTemplate","_fetchContentElement","cleanup","restore","locals","templateUrl","extend","transformTemplate","identity","invoke","$$ngTemplate","html","contents","_compileElement","ngLinkFn","compileData","$scope","injectLocals","$element","ctrl","_createController","isFunction","$onDestroy","$on","data","bindToController","controllerAs","$onInit","contentEl","createRestoreFn","querySelector","nextSibling","nextElementSibling","insertBefore","MdGesture","attachToDocument","pointer","lastPointer","HANDLERS","maxClickDistance","forceSkipClickHijack","disableAllGestures","lastLabelClickPos","isInitialized","MdGestureProvider","$$MdGestureHandler","touchActionProperty","hasJQuery","jQuery","definition","register","handlerName","Error","keys","registerElement","isHijackingClicks","checkDistanceAndEmit","eventName","distance","state","maxDistance","onEnd","canFocus","onStart","onCancel","registeredParent","pos","onMove","dx","dy","sqrt","minDistance","horizontal","cancelMultiplier","onSetup","oldTouchAction","onCleanup","shouldStartDrag","shouldCancel","dragPointer","dispatchDragMove","abs","distanceX","distanceY","makeStartPointer","updatePointerState","isRunning","minVelocity","eventType","velocityX","directionX","velocityY","directionY","GestureHandler","$mdGesture","isKeyClick","webkitForce","clientX","clientY","isIonicTap","isInputEventFromLabelClick","mouseInputHijacker","typesMatch","endTime","runHandlers","activeElement","handlerEvent","point","getEventPoint","startPointer","startX","pageX","startY","pageY","touches","changedTouches","isContentEditable","srcEvent","eventPointer","eventObj","Event","screenX","screenY","shiftKey","trigger","MouseEvent","bubbles","cancelable","Number","button","buttons","relatedTarget","detail","CustomEvent","initCustomEvent","parentTarget","getNearestParent","parentTargetOptions","move","onDestroy","disableAll","skipClickHijack","setMaxClickDistance","clickDistance","MdInteractionService","pointerEvent","bodyElement","isBuffering","bufferTimeout","lastInteractionType","lastInteractionTime","inputHandler","onInputEvent","bufferedInputHandler","onBufferInputEvent","inputEventMap","iePointerMap","2","3","4","initializeEvents","deregister","service","pointerType","getLastInteractionType","isUserInvoked","checkDelay","InterimElementFactory","createInterimElementProvider","interimFactoryName","EXPOSED_METHODS","customMethods","providerConfig","presets","setDefaults","optionsFactory","methods","addPreset","argOption","addMethod","$$interimElement","defaultMethods","defaultOptions","interimElementService","publicService","hide","show","_options","destroy","invokeFactory","presetDefaults","presetMethods","Preset","$type","methodName","isObject","defaultVal","$mdCompiler","$mdTheming","$exceptionHandler","showPromises","hidePromises","showingInterims","interimElement","InterimElement","hideAction","multiple","promiseArray","showAction","catch","reason","finally","deferred","fault","waitForInterim","closeAll","reverse","closeElement","closeTo","interim","pop","cancelAction","targetEl","shift","parentEl","filtered","$injector_","callbackFn","fnArguments","preserveScope","cancelAutoHide","$new","isolateScope","onShow","enter","onRemove","leave","configureScopeAndTransitions","defer","rejectAll","onCompiling","skipCompile","compileElement","compiledData","findParent","themable","linkElement","cleanupElement","notifyShowing","onShowing","notifyComplete","onComplete","startAutoHide","message","showElement","isCancelled","triggerHandler","$destroy","hideElement","resolveAll","autoHideTimer","hideDelay","announceRemoving","onRemoving","action","SUFFIXES","WHITESPACE","FLEX_OPTIONS","LAYOUT_OPTIONS","ALIGNMENT_MAIN_AXIS","ALIGNMENT_CROSS_AXIS","breakpoints","detectDisabledLayouts","disableLayoutDirective","priority","attributeWithoutValue","className","_$mdUtil_","_$interpolate_","_$log_","linkFn","validateAttributeValue","getNormalizedAttrValue","buildUpdateFn","translateToCssClass","validateAttributeUsage","usage","updateFn","origValue","needsInterpolation","findIn","axis","attrValue","main","cross","extractAlignAxis","fallback","normalizedAttr","list","replaceWith","PREFIX_REGEXP","API_WITH_VALUES","API_NO_VALUES","directiveNormalize","_","mqb","fullName","translateWithValueToCssClass","lastClass","newValue","updateClassWithValue","unwatch","attributeWithObserve","disableLayouts","registerLayoutAPI","MdLiveAnnouncer","_$timeout","_liveElement","_createLiveElement","_announceTimeout","announce","politeness","setAttribute","liveEl","classList","head","metaElements","mapExistingElement","getElementsByName","setMeta","newMeta","getMeta","ComponentRegistry","instances","pendings","notFoundError","handle","msgContext","getInstances","isValidID","instance","$$mdHandle","dfd","MdButtonInkRipple","$mdInkRipple","attach","isMenuItem","fitRipple","center","dimBackground","optionsForElement","MdCheckboxInkRipple","MdListInkRipple","outline","rippleSize","InkRippleCtrl","InkRippleDirective","isDisabledGlobally","disableInkRipple","instantiate","rippleOptions","attrNoDirective","$mdButtonInkRipple","$mdCheckboxInkRipple","$mdColorUtil","mousedown","ripples","lastRipple","createContainer","createRipple","setColor","bindEvents","autoCleanup","cleanupFn","_color","_parseColor","inkRipple","colorElement","calculateColor","multiplier","colorUtil","handleMousedown","handleMouseup","handleTouchmove","srcElement","layerRect","layerX","layerY","offsetX","offsetY","clearRipples","deleteRipples","fadeInComplete","clearTimeout","isRippleAllowed","ripple","size","fit","pow","getSize","background","backgroundColor","borderColor","DURATION","removeRipple","fadeOutComplete","MdTabInkRipple","constant","detectDisabledThemes","disableTheming","ThemingDirective","ThemableDirective","ThemingProvider","generateAllThemes","themeConfig","PALETTES","GENERATED","DARK_FOREGROUND","LIGHT_FOREGROUND","DARK_SHADOW","DARK_CONTRAST_COLOR","colorToRgbaArray","LIGHT_CONTRAST_COLOR","STRONG_LIGHT_CONTRAST_COLOR","THEME_COLOR_TYPES","LIGHT_DEFAULT_HUES","DARK_DEFAULT_HUES","DARK_CONTRAST_OPACITY","LIGHT_CONTRAST_OPACITY","STRONG_LIGHT_CONTRAST_OPACITY","colorType","defaultDefaultHues","VALID_HUE_VALUES","generateOnDemand","registeredStyles","nonce","$mdColorPalette","$$mdMetaProvider","ThemingService","themingProvider","THEMES","alwaysWatchTheme","defaultTheme","enableBrowserColor","hue","palette","colors","removeChrome","removeWindows","setBrowserColor","definePalette","checkPaletteValid","extendPalette","registerTheme","configuration","registerStyles","setNonce","nonceValue","generateThemesOnDemand","onDemand","setDefaultTheme","alwaysWatch","_LIGHT_DEFAULT_HUES","_DARK_DEFAULT_HUES","_PALETTES","_THEMES","_parseRules","parseRules","_rgba","rgba","missingColors","field","inheritFrom","parentTheme","Theme","hues","setDark","isDark","foregroundPalette","foregroundShadow","newDefaultHues","oldDefaultHues","newDefaults","oldDefaults","hueName","dark","defaultHues","paletteName","hueValue","applyTheme","inherit","updateThemeClass","$mdTheme","watchTheme","$shouldWatch","isAsyncTheme","clearNameWatcher","registerChanges","registered","oldTheme","generateTheme","defineTheme","primary","primaryHues","accent","accentHues","warnHues","backgroundHues","themeName","registeredCallbacks","mdTheme","hasInterpolation","lastIndexOf","oneTimeBind","getTheme","interpolation","$setTheme","ALWAYS_WATCH","setParsedTheme","rules","checkValidPalette","themeNameRegex","RegExp","hueRegex","defaultBgHue","defaultBgContrastType","contrastType","contrast","opacity","regexColorType","colorDetails","generatedRules","newRule","matchedColorType","hueType","rulesByType","firstChild","firstElementChild","themeCss","defaultContrast","contrastDefaultColor","lightColors","contrastLightColors","strongLightColors","contrastStrongLightColors","darkColors","contrastDarkColors","getContrastColor","getOpacityValues","rgbValue","getContrastType","currentRule","openedCurlyBrackets","closedCurlyBrackets","character","textInQuotes","splitCss","rule","styleStrings","styleContent","createTextNode","clr","grn","blu","rgbArray","copy","MdAutocompleteCtrl","$attrs","$mdLiveAnnouncer","itemParts","itemsExpr","itemExpr","elements","cache","noBlur","selectedItemWatchers","hasFocus","fetchesInProgress","enableWrapScroll","inputModelCtrl","debouncedOnResize","hidden","positionDropdown","mode","oldHidden","scrollContainerElement","scrollContainer","reportMessages","ReportType","wrap","handleTouchOutsidePanel","getDefaultIndex","updateActiveOption","updateScroll","set","oldValue","itemName","loading","activeOption","id","isRequired","isReadonly","hasNotFound","selectedMessage","noMatchMessage","singleMatchMessage","multipleMatchStartMessage","multipleMatchEndMessage","defaultEscapeOptions","keydown","hasSelection","onListLeave","select","hasEscapeOption","searchText","clearSelectedItem","clearSearchText","doBlur","shouldHide","evalAttr","isSearchable","isMinLengthMet","handleQuery","clear","listEnter","listLeave","focusInput","focusInputElement","getCurrentDisplayValue","registerSelectedItemWatcher","unregisterSelectedItemWatcher","notFoundVisible","loadingIsVisible","selectedItem","clearButton","disableVirtualRepeat","handleSearchText","selectedItemChange","snapWrap","snap","find","gatherSnapWrap","scroller","ul","input","li","getElementsByTagName","$","obj","getAngularElements","detach","pin","autofocus","inputAriaDescribedBy","floatingLabel","inputAriaLabel","inputAriaLabelledBy","placeholder","updateModelValidators","requireMatch","$setValidity","dropdownHeight","dropdownItems","hrect","vrect","bot","inputContainer","getVerticalOffset","dropdownPosition","bottomSpace","topSpace","mdFloatingLabel","INPUT_PADDING","minWidth","maxWidth","maxHeight","dropdown","selectedOption","previousSelectedItem","getDisplayValue","watcher","handleSelectedItemChange","displayValue","itemChange","getItemAsNameVal","previousSearchText","textChange","setLoading","forceBlur","getMinLength","minLength","itemText","getItemText","autoselect","hasMatches","shouldShow","option","escapeOptions","ngModel","isPolite","types","messages","getCountMessage","selected","containerHeight","offsetTop","scrollTo","optionHeight","updateVirtualScroll","textLength","noCache","handleResults","$eval","isList","isPromise","onResultsRetrieved","handleAsyncResults","fetchResults","selectOnMatch","isMatching","matchInsensitive","MdAutocomplete","$$mdSvgRegistry","REPEAT_MODES","getRepeatMode","modeStr","inputName","inputMinlength","inputMaxlength","menuClass","menuContainerClass","inputClass","inputId","mdMode","tElement","tAttrs","mdClearButton","templateTag","noItemsTemplate","itemTemplate","empty","getItemTemplate","leftover","tabindex","mdClose","repeatMode","isVirtualRepeatDisabled","getContainer","mdMenuContainerClass","getContainerClosingTags","MdAutocompleteItemScopeDirective","tAttr","transclude","scopeDigesting","newScopeDigesting","$mdAutocompleteCtrl","newScope","watchVariable","variable","alias","$$postDigest","clone","after","terminal","MdHighlightCtrl","regex","init","unsafeTermFn","unsafeContentFn","flags","mdHighlightFlags","unregisterFn","contentText","onRender","prevState","createRegex","applyRegex","tokens","resolveTokens","token","isMatch","tokenEl","string","lastIndex","appendToken","targetText","startFlag","endFlag","regexTerm","MdHighlight","termExpr","mdHighlightText","unsafeContentExpr","bodyStyles","resize","viewportHeight","resizeHandler","MdBottomSheetDirective","$mdBottomSheet","MdBottomSheetProvider","$$interimElementProvider","bottomSheetDefaults","backdrop","isLockedOpen","clickOutsideToClose","escapeToClose","cleanupGestures","onDragStart","onDrag","onDragEnd","distanceRemaining","registerGestures","disableBackdrop","disableParentScroll","restoreScroll","focusable","rootElementKeyupCallback","MdAnchorDirective","MdButtonDirective","$mdAria","$mdInteraction","isAnchor","ngDisabled","disabled","href","ngHref","ngLink","uiSref","mdCardDirective","MdCheckboxDirective","inputDirective","require","$set","post","ctrls","isIndeterminate","containerCtrl","formCtrl","labelHasLink","labelId","label","listener","isErrorGetter","$invalid","$touched","setInvalid","mdIndeterminate","setIndeterminateState","ngChecked","expr","htmlAttr","valueOpts","true","false","skipToggle","$apply","viewValue","ngClick","checked","0","submit","which","click","MdChipCtrl","isEditing","parentController","enableChipEdit","chipKeyDown","chipMouseDoubleClick","getChipContent","chipContents","getElementsByClassName","getContentElement","getChipIndex","goOutOfEditMode","contentEditable","chipIndex","updateChipContents","selectedChip","focusChip","removeChipAndFocusInput","selectNodeContents","range","selection","createTextRange","moveToElementText","getSelection","createRange","removeAllRanges","addRange","goInEditMode","MdChip","chipsController","chipController","chipContentElement","resetSelectedChip","$applyAsync","shouldFocusLastChip","focusLastChipThenInput","MdChipRemove","removeChip","$$replacedScope","$index","MdChipTransclude","$mdChipsCtrl","$chip","newHtml","mdChipTransclude","MdChipsCtrl","userInputNgModelCtrl","autocompleteCtrl","userInputElement","mdEnableChipEdit","addOnBlur","mdAddOnBlur","containerHint","containerEmptyHint","deleteHint","deleteButtonLabel","chipBuffer","useTransformChip","useOnAdd","useOnRemove","wrapperId","contentIds","ariaTabIndex","chipAppendDelay","deRegister","addedMessage","removedMessage","setupStaticChips","$watchCollection","setupInputAria","setupWrapperAria","$destroyFn","removeAttr","wrapper","staticChips","inputKeydown","getChipBuffer","isDefaultPrevented","getCursorPosition","selectAndFocusChipSafe","separatorKeys","hasMaxChipsReached","appendChip","resetChipBuffer","selectionStart","selectionEnd","updateNgModel","isEditingChip","_isChipObject","chip","isRemovable","readonly","removable","chipKeydown","removeAndSelectAdjacentChip","onFocus","getPlaceholder","secondaryPlaceholder","selIndex","getAdjacentChipIndex","newChip","transformChip","transformedChip","some","equals","chipContent","onAdd","useTransformChipExpression","useOnAddExpression","useOnRemoveExpression","useOnSelectExpression","useOnSelect","maxChips","validateModel","$validate","skipValidation","removed","$setDirty","selectChip","onSelect","configureNgModel","onInputFocus","inputHasFocus","onInputBlur","shouldAddOnBlur","configureInput","inputElement","isTouched","$dirty","isDirty","configureUserInput","scopeApplyFn","configureAutocomplete","isModelValid","$modelValue","$valid","isAutocompleteShowing","contentIdFor","MdChips","templates","chips","default","userTemplate","chipTemplate","getTemplateByQuery","chipRemoveTemplate","chipContentsTemplate","chipInputTemplate","controllers","mdChipsCtrl","mdCloseIcon","mdCancel","mdTransformChip","mdOnAdd","mdOnRemove","mdOnSelect","autocompleteEl","compiledStaticChips","prepend","chipAppendDelayString","ngChange","MdContactChipsCtrl","setupChipsAria","setupAutocompleteAria","chipsCtrl","autocompleteInput","queryContact","contactQuery","contactName","MdContactChips","contactChipsController","contactImage","contactEmail","contacts","highlightFlags","MdColorsDirective","MdColorsService","STATIC_COLOR_EXPRESSION","colorPalettes","applyThemeColors","colorExpression","rgbColors","hasColorProperty","themeColors","extractColorOptions","hasBackground","parseColor","getThemeColor","expression","hasTheme","rgbValues","parts","extractPalette","extractHue","isTwoWord","scheme","hueNumber","availableThemes","usedTheme","$mdColors","tElem","shouldWatch","rawColorExpression","mdColors","bindOnce","isStatic","hasWatchAttr","mdColorsWatch","shouldColorsWatch","mdThemeController","lastColors","parseColors","cleanElement","unregisterChanges","mdContentDirective","$broadcast","$materialScrollFixed","calendarDirective","minDate","maxDate","dateFilter","monthFilter","_mode","_currentView","CalendarCtrl","MODE_MAP","day","month","$$mdDateUtil","$mdDateLocale","$filter","dateUtil","ngDateFilter","today","createDateAtMidnight","SELECTED_DATE_CLASS","TODAY_CLASS","FOCUSED_DATE_CLASS","displayDate","selectedDate","firstRenderableDate","lastRenderableDate","scrollbarWidth","standaloneMode","handleKeyElement","boundKeyHandler","handleKeyEvent","major","currentView","convertedDate","isValidDate","removeLocalTzAndReparseDate","setNgModelValue","date","timezone","focusDate","$emit","getTimezoneOffset","setCurrentView","newView","isDate","previousFocus","cellId","getDateId","cell","getElementById","rootElement","changeSelectedDate","selectedDateClass","prevDateCell","dateCell","getActionFromKeyEvent","hideVerticalScrollbar","childCtrl","setWidth","calendarScroller","paddingRight","namespace","getFullYear","getMonth","getDate","updateVirtualRepeat","virtualRepeatResizeListener","$$phase","CalendarMonthCtrl","dateLocale","isMonthTransitionInProgress","cellClickHandler","timestamp","getTimestampFromNode","calendarCtrl","headerClickHandler","initialize","getMonthDistance","attachScopeListeners","getSelectedMonthIndex","changeDisplayDate","buildWeekHeader","animationPromise","animateDateChange","monthDistance","firstDayOfWeek","shortDays","row","th","incrementDays","incrementMonths","getFirstDateOfMonth","getLastDateOfMonth","clampDate","mdCalendarMonthBodyDirective","ARROW_ICON","mdTabsArrow","CalendarMonthBodyCtrl","monthCtrl","monthBodyCtrl","arrowIcon","cloneNode","generateContent","focusAfterAppend","buildCalendarForMonth","buildDateCell","opt_date","longDateFormatter","isSameDay","cellText","dates","isDateEnabled","selectionIndicator","isDateWithinRange","buildDateRow","rowNumber","weekNumberFormatter","opt_dateInMonth","firstDayOfMonth","firstDayOfTheWeek","getLocaleDay_","numberOfDaysInMonth","getNumberOfDaysInMonth","monthBody","createDocumentFragment","isFinalMonth","blankCellOffset","monthLabelCell","monthLabelCellContent","monthHeaderFormatter","monthFormatter","monthLabelRow","dayOfWeek","iterationDate","d","setDate","whitespaceRow","getDay","CalendarYearCtrl","onTimestampSelected","getYearDistance","getFocusedYearIndex","changeDate","CalendarYearBodyCtrl","yearCtrl","yearBodyCtrl","incrementYears","buildCalendarForYear","buildMonthCell","year","buildBlankCell","firstOfMonth","isSameMonthAndYear","shortMonths","isMonthWithinRange","yearBody","firstRow","labelCell","secondRow","DateLocaleProvider","months","days","formatDate","parseDate","isDateComplete","msgCalendar","msgOpenCalendar","$locale","defaultShortDays","DATETIME_FORMATS","SHORTDAY","defaultDates","defaultFirstRenderableDate","defaultLastRendereableDate","MONTH","SHORTMONTH","DAY","localeTime","toLocaleTimeString","getHours","dateString","number","getDateInNextMonth","getDateInPreviousMonth","isInNextMonth","startDate","endDate","isInPreviousMonth","previousMonth","getDateMidpoint","d1","d2","getWeekOfMonth","floor","numberOfDays","setDateTimeToMidnight","dateAtMidnight","minDateAtMidnight","maxDateAtMidnight","numberOfYears","boundDate","dateValue","formattedDate","numberOfMonths","dateInTargetMonth","setHours","opt_value","datePickerDirective","hiddenIcons","mdHideIcons","inputAriaDescribedby","inputAriaLabelledby","ariaLabelValue","ariaLabel","mdPlaceholder","ngModelOptions","calendarButton","mdCalendar","triangleButton","HAS_TRIANGLE_ICON_CLASS","isOpen","debounceInterval","DatePickerCtrl","mdDatePickerCtrl","mdInputContainer","parentForm","mdNoAsterisk","spacer","setHasPlaceholder","INPUT_CONTAINER_CLASS","HAS_CALENDAR_ICON_CLASS","parentSubmittedWatcher","isSubmitted","updateErrorState","OPEN_CLASS","IS_MOBILE_REGEX","ngInputElement","calendarPane","inputMask","isFocused","setDisabled","isCalendarOpen","openOnFocus","calendarPaneOpenedFrom","calendarPaneId","bodyClickHandler","handleBodyClick","windowEventName","windowEventHandler","closeCalendarPane","windowBlurHandler","handleWindowBlur","leftMargin","topMargin","detachCalendarPane","mdIsOpen","shouldBeOpen","openCalendarPane","locale","installPropertyInterceptors","attachChangeListeners","attachInteractionListeners","parsedValue","parse","onExternalChange","unshift","updateOn","setModelValue","resizeInputElement","handleInputEvent","keyCodes","setPointerCapture","pointerId","valueOf","clearErrorState","parsedDate","isInputValid","inputString","attachCalendarPane","elementRect","bodyRect","paneTop","paneLeft","viewportLeft","scrollLeft","viewportBottom","innerHeight","viewportRight","innerWidth","scale","inputFocusedOnWindowBlur","resetInputFocused","focusCalendar","reset","getCalendarCtrl","setFocused","setHasValue","MdDialogDirective","$mdDialog","images","addOverflowClass","MdDialogProvider","topFocusTrap","bottomFocusTrap","removeFocusTrap","MdDialogController","dialogDefaultOptions","advancedDialogOptions","isPrompt","initialValue","abort","keypress","invalidPrompt","required","hasBackdrop","targetEvent","themeCtrl","themeWatch","newTheme","detectTheming","dialogElement","captureParentAndFromToElements","configureAria","showBackdrop","activateListeners","dialogPopIn","isHidden","walkDOM","parents","getParents","unlockScreenReader","lockScreenReader","focusOnOpen","mdHtmlContent","htmlContent","mdTextContent","deactivateListeners","hideBackdrop","detachAndClean","reverseAnimate","clearAnimate","dialogPopOut","reverseContainerStretch","originInteraction","openFrom","autoWrap","fullscreen","validatedTemplate","orig","hasFn","getDomElement","defaultElement","onWindowResize","stretchDialogContainerToViewport","removeListeners","smartClose","closeFn","keyHandlerFn","sourceElem","mousedownHandler","mouseupHandler","removeFn","role","dialogContent","existingDialogId","dialogContentId","title","words","focusHandler","lastFocusableElement","isElement","isFixed","ceil","previousStyles","parentTop","dialogEl","buildTranslateToOrigin","translateOptions","animateReversal","MdDividerDirective","MdFabActionsDirective","actionItemButtons","hasNgRepeat","MdFabController","closeTimeout","initialAnimationAttempts","parseEvents","closestButton","getClosestTrigger","toggle","getClosestAction","handleItemClick","resetActionIndex","currentActionIndex","fireInitialAnimations","disableKeyboard","keyPressed","checkForOutsideClick","closestTrigger","closestActions","direction","doActionNext","doActionPrev","doKeyLeft","doKeyUp","doKeyRight","doKeyDown","doShift","focusAction","actions","getActionsElement","previousActionIndex","open","eventTypes","newDir","oldDir","toAdd","toRemove","setClass","MdFabSpeedDialFlingAnimation","delayDone","runAnimation","triggerElement","variablesElement","startZIndex","zIndex","webkitTransform","triggerItemHeightOffset","triggerItemWidthOffset","scrollWidth","newTranslate","MdFabSpeedDialScaleAnimation","offsetDelay","animation","MdFabToolbarAnimation","backgroundElement","toolbarElement","iconElement","getPropertyValue","borderRadius","pointerEvents","GridListDirective","$mdGridLayout","GridListController","mdOnLayout","layoutDelegate","tilesInvalidated","tiles","ele","$$mdDestroyed","props","tileSpans","tileElements","col","colCount","getColumnCount","rowMode","getRowMode","rowHeight","getRowHeight","gutter","applyDefaultUnit","lastLayoutProps","tilePositions","rowCount","grid","getGridStyle","ps","getTileStyle","spans","reflow","invalidateLayout","unwatchAttrs","layoutIfMediaMatch","watchMedia","removeListener","exprStr","UNIT","POSITION","DIMENSION","hShare","hGutterShare","hUnit","share","gutterShare","unit","span","paddingTop","marginTop","vShare","vUnit","paddingBottom","whRatio","layoutInvalidated","$timeout_","GridLayoutFactory","defaultAnimator","GridTileAnimator","GridLayout","animateWith","customAnimator","layoutInfo","gridStyles","layoutTime","mapTime","reflowTime","curCol","curRow","spaceTracker","tracker","newSpaceTracker","positioning","reserveSpace","nextRow","findEnd","adjustRow","cols","by","calculateGridFor","info","animatorFn","tileCount","totalTime","t","GridTileDirective","gridCtrl","invalidateTiles","newIdx","oldIdx","GridTileCaptionDirective","layout","$mdIcon","$sce","lastFontIcon","mdFontIcon","lastFontSet","fontSet","mdFontSet","mdSvgIcon","mdSvgSrc","fontIconChanged","ariaHidden","alt","$attr","attrVal","svg","MdIconService","MdIconProvider","defaultViewBoxSize","defaultFontSet","fontSets","ConfigurationItem","url","viewBoxSize","iconCache","svgCache","urlRegex","dataUrlRegex","Icon","prepare","getIcon","getTrustedUrl","transformClone","loadByURL","cacheIcon","loadByID","loadFromIconSet","cacheElement","cacheSuffix","svgUrlQuerySelector","xlinkHrefValue","newUid","svgUrlAttributes","isIeSvg","innerHTML","isFinite","descendantElem","refItem","updateSvgIdReferences","referencedElement","referencingElement","svgElement","icon","iconConfig","setName","iconSetConfig","iconName","announceIdNotFound","msg","atob","loadByDataUrl","err","statusText","loadByHttpUrl","viewbox","iconSet","defaultIconSet","defaultIconSize","iconSize","mdInputContainerDirective","inputTextareaDirective","mdMaxlengthDirective","placeholderDirective","ngMessageDirective","mdSelectOnFocusDirective","mdInputInvalidMessagesAnimation","ngMessagesAnimation","ngMessageAnimation","inputModule","mdNoFloat","mdAutoHide","hasVisibiltyDirective","visibilityDirectives","ContainerCtrl","INPUT_TAGS","LEFT_SELECTORS","reduce","selectors","isel","RIGHT_SELECTORS","hasLeftIcon","hasRightIcon","iconNotRemoved","mdIsError","delegateClick","hasPlaceholder","isInvalid","hasLabelAndInput","hasNgModel","errorsSpacer","placeholderText","step","isAutogrowing","isDragging","startHeight","dragGestureHandler","onMouseDown","disableAutogrow","attachResizeHandle","minRows","rows","NaN","maxRows","scopeResizeListener","growTextarea","lineHeight","formattersListener","line","originalPadding","padding","listenerIndex","handleHiddenChange","wasHidden","setupTextarea","inputCheckValue","ngValue","ngModelPipelineCheckValue","validity","badInput","maxlength","mdMaxlength","charCountEl","ngTrim","isPasswordInput","calculateInputValueLength","renderCharCount","$validators","modelValue","elementVal","noFloat","newLabel","preventMouseUp","onMouseUp","_mdMocksIncluded","getElement","getMessagesElement","isInsideInputContainer","initMessageElement","DOCUMENT_FRAGMENT_NODE","isInsideFragment","saveSharedServices","showInputMessages","hideInputMessages","showMessage","hideMessage","animators","getInputElement","structural","_$$AnimateRunner_","_$animateCss_","mdListDirective","tEl","mdListItemDirective","proxiedTypes","hasProxiedElement","proxyElement","secondaryItemsWrapper","secondaryItems","itemContainer","ngDblclick","ngAttrUiSref","wrapIn","buttonWrap","moveAttributes","listItemInner","eq","extraAttrs","copiedAttrs","hasClickEvent","secondaryItem","buttonWrapper","isProxiedElement","wrapSecondaryItem","toggleTypes","labelElement","setupToggleAria","menuEl","isEndAligned","xAxisPosition","menuOpenButton","setupProxiedMenu","proxies","firstElement","clickChild","hasClick","noProxies","attachRipple","proxy","mouseActive","proxyOnBlur","clickChildKeypressListener","keypressEvent","clickEvent","forbiddenControls","eventBubblePath","maxPath","isEventFromControl","MdListController","$mdListInkRipple","MenuController","$mdMenu","menuContainer","nestLevel","mdNestLevel","setMenuContainer","isInMenuBar","mdMenuBarCtrl","nestedMenus","onIsOpenChanged","menuContainerId","disableHoverListener","openMenuTimeout","menuItems","deregisterScopeListeners","enableHoverListener","currentlyOpenMenu","isAlreadyOpening","registerContainerProxy","triggerContainerProxy","handleMenuItemHover","handleMenuItemMouseLeave","nestedMenu","focusableTarget","mdMenuCtrl","preserveElement","$mdMenuIsOpen","focusMenuContainer","focusTarget","containerProxy","skipFocus","closeOpts","eventDetails","restoreFocusTo","positionMode","attachment","mdPositionMode","offsets","mdOffset","MenuDirective","templateElement","triggerEl","isButtonTrigger","INVALID_PREFIX","nestingDepth","menuContents","MenuProvider","menuDefaultOptions","alreadyOpen","isRemoved","menuContentEl","sanitizeAndConfigure","cleanupResizing","repositionMenu","calculateMenuPosition","startRepositioningOnResize","showMenu","cleanupInteraction","onMenuKeyDown","captureClickListener","childrenLen","childIndex","handled","focusMenuItem","parentMenu","hasAnyAttribute","closestMenu","activateInteraction","cleanupBackdrop","onBackdropClick","animateRemoval","toNode","detachElement","didFocus","currentItem","attemptFocus","alignTarget","containerNode","openMenuNode","openMenuNodeRect","boundryNodeRect","menuStyle","originNode","originNodeRect","alignTargetRect","existingOffsets","firstVisibleChild","transformOrigin","rtl","willFitRight","MenuBarController","BOUND_MENU_METHODS","deregisterFns","handleKeyDown","parentToolbar","getMenus","enableOpenOnHover","rootMenus","disableOpenOnHover","setKeyboardMode","openOnHoverEnabled","handleParentClick","handleMenuHover","scheduleOpenHoveredMenu","menuCtrl","scheduleOpenMenu","pendingMenuOpen","newMenu","newMenuCtrl","currentMenu","wasOpen","openFocusedMenu","focusMenu","menus","focusedIndex","getFocusedMenuIndex","getOpenMenuIndex","changed","menu","getFocusedMenu","focusedEl","openMenu","MenuBarDirective","templateEl","templateAttrs","ariaRole","contentEls","MenuItemController","iconEl","buttonEl","initClickListeners","clearNgAria","handleClick","isSelected","newVal","MenuItemDirective","setDefault","iconTemplate","mdChecked","mdPreventMenuClose","MdNavBar","MdNavBarController","onResize","updateSelectedTabInkBar","navBarAriaLabel","_$scope","_$mdConstant","mdSelectedNavItem","_navBarEl","_inkbar","deregisterTabWatch","newLength","_initTabs","MdNavItem","MdNavItemController","navigationAttribute","buttonTemplate","hasNavClick","mdNavClick","hasNavHref","mdNavHref","hasNavSref","mdNavSref","hasSrefOpts","srefOpts","disconnect","mdNavItem","mdNavBar","navButton","onKeydown","_focused","targetNode","observer","MutationObserver","mutationList","attributeName","observe","attributeFilter","navItemAriaLabel","_$element","_selected","_updateTabs","tabs","_getTabs","sameTab","newIndex","newTab","_getTabByName","oldTab","setSelected","_updateInkBarStyles","_moveFocus","tab","tabEl","getButtonEl","offsetLeft","tabWidth","navBarWidth","translate","_getSelectedTab","_findTab","getName","getFocusedTab","startIndex","_findTabReverse","_focusFirstTab","tabToFocus","_isEnabled","_focusLastTab","_focusNextTab","focusedTabIndex","_focusPreviousTab","focusedTab","getNgClassMap","MdPanelService","definePreset","getAllPresets","clearPresets","_presets","FOCUS_TRAP_TEMPLATE","preset","coerceToArray","_defaultConfigOptions","propagateContainerEvents","_wrapTemplate","trapFocus","_config","_$rootElement","_$rootScope","_$injector","_$window","_$mdUtil","_trackedPanels","_groups","create","MdPanelAnimation","xPosition","MdPanelPosition","yPosition","interceptorTypes","MdPanelRef","closeReasons","absPosition","_$q","_$mdCompiler","_$mdTheming","_$animate","_$mdPanel","_$log","_$$rAF","panelContainer","panelEl","innerWrapper","isAttached","_removeListeners","_topFocusTrap","_bottomFocusTrap","_backdropRef","_interceptors","_compilerCleanup","_restoreCache","classes","_isRTL","_absolute","_relativeToEl","_top","_bottom","_left","_right","_translateX","_translateY","_positions","_actualPosition","_openFrom","_closeTo","_animationClass","_openDuration","_closeDuration","_rawDuration","queryResult","validatePosition","positionMap","positionKeys","positionValues","addUnits","_getPresetByName","trackedPanel","attachTo","panelRef","groupName","group","addToGroup","newPanelPosition","newPanelAnimation","newPanelGroup","panels","openPanels","maxOpen","Infinity","setGroupMaxOpen","_openCountExceedsMaxOpen","_closeFirstOpenedPanel","origTemplate","_wrapContentElement","outerWrapper","CLOSE","_done","_simpleBind","closeReason","_callInterceptors","onCloseSuccess","onDomAdded","_createBackdrop","_createPanel","_addEventListeners","onDomRemoved","_removeEventListeners","removeFromGroup","onOpenComplete","_animateOpen","_focusOnOpen","_animateClose","_compile","mdPanelRef","_configureTrapFocus","_addStyles","hideAndResolve","_setTheming","_updatePosition","updatePosition","positionConfig","_setPanelPosition","TOP","getTop","BOTTOM","getBottom","LEFT","getLeft","RIGHT","getRight","backdropAnimation","withAnimation","backdropConfig","panelClass","_configureEscapeToClose","_configureClickOutsideToClose","_configureScrollListener","sourceEl","CLICK_OUTSIDE","debouncedUpdatePosition","onScroll","updateAnimation","animationConfig","animateOpen","animateClose","registerInterceptor","interceptors","removeInterceptor","removeAllInterceptors","reduceRight","interceptor","CENTER","ALIGN_START","ALIGN_END","OFFSET_START","OFFSET_END","ALIGN_TOPS","ALIGN_BOTTOMS","ABOVE","BELOW","viewportMargin","absolute","_setPosition","positions","centerHorizontally","centerVertically","relativeTo","addPanelPosition","withOffsetX","withOffsetY","getTransform","_reduceTranslateValues","_setTransform","_isOnscreen","openIndex","closeIndex","output","parsedValues","getComputedTranslations","getActualPosition","translateFn","translation","translationValue","_calculatePanelPosition","_constrainToViewport","margin","initialTop","initialLeft","viewportWidth","_reverseXPosition","_bidi","panelBounds","panelWidth","panelHeight","targetBounds","targetLeft","targetRight","targetWidth","targetTop","targetBottom","targetHeight","SLIDE","SCALE","FADE","_getPanelAnimationTarget","toSeconds","_getBoundingClientRect","cssClass","_fixBounds","animationOptions","panelTransform","openTo","openSlide","openScale","reverseAnimationOptions","closeFrom","closeSlide","closeScale","MdProgressCircularDirective","$mdProgressCircular","$interval","rAF","requestAnimationFrame","webkitRequestAnimationFrame","cAF","cancelAnimationFrame","webkitCancelAnimationFrame","webkitCancelRequestAnimationFrame","mdDiameter","MdProgressCircularLink","lastDrawFrame","interval","startIndeterminate","endIndeterminate","iterationCount","lastAnimationId","renderCircle","animateFrom","animateTo","changeInValue","diameter","strokeWidth","getStroke","easeFn","rotation","dashLimit","renderFrame","getDashOffset","animateIndeterminate","easeFnIndeterminate","durationIndeterminate","startIndeterminateAnimation","cleanupIndeterminateAnimation","$watchGroup","newValues","oldValues","getSvgArc","getDashLength","clamp","dimensions","indeterminate","radius","arcRadius","maxArcLength","getSpinnerCircumference","progressSize","parsed","PI","progressConfig","linearEase","materialEase","easingPresets","configure","c","tc","MdProgressLinearDirective","postLink","lastMode","toVendorCSS","bar1","bar2","animateIndicator","validateMode","percentValue","mdRadioGroupDirective","mdRadioButtonDirective","incrementSelection","freeze","PREVIOUS","CURRENT","NEXT","RadioGroupController","_ngModelCtrl","render","rbRender","_radioButtonRenderFns","setViewValue","getViewValue","selectCurrent","changeSelectedButton","selectNext","selectPrevious","setActiveDescendant","radioId","radioGroupController","setFocus","keyboardEvent","radioButtons","getRadioButtons","increment","lastChecked","SelectDirective","SelectMenuDirective","OptionDirective","SelectProvider","OptionController","selectNextId","CHECKBOX_SELECTION_INDICATOR","$mdSelect","isMultiple","valueEl","mdContentEl","mdOnOpen","autofillClone","newEl","multipleContent","selectTemplate","stopMdMultipleWatch","selectContainer","selectScope","selectMenuCtrl","untouched","mdSelectCtrl","selectValueElement","disableAsterisk","userDefinedLabelledby","ariaLabelledby","listboxContentElement","initialPlaceholder","selectLabel","stopInvalidWatch","mdContainerClass","findSelectContainer","originalRender","syncSelectValueText","stopPlaceholderObserver","stopRequiredObserver","setSelectValueText","useDefaultText","isSelectLabelFromUser","setIsPlaceholder","mdSelectedText","mdSelectedHtml","getTrustedHtml","isPlaceholder","_mdSelectIsOpen","triggerClose","mdOnClose","labelText","initAriaLabel","stopSelectedLabelsWatcher","getSelectedLabels","stopMdMultipleObserver","parser","prevVal","selectMenu","setMultipleAttrs","setMultiple","Boolean","stopDisabledObserver","openSelect","handleKeypress","ariaAttrs","containerId","listboxContentId","shouldHandleKey","optNodeForKeyboardSearch","optionCtrl","deselect","hashKey","refreshViewValue","selectCtrl","loadingAsync","SelectMenuController","clickListener","mouseEvent","optionHashKey","hashGetter","defaultIsEmpty","clearSearchTimeout","optNodes","optText","searchStr","renderMultiple","newSelectedValues","oldSelected","newSelectedHashes","hash","renderSingular","updateOptionSetSizeAndPosition","loaded","delayedRender","validateArray","modelBinding","search","setTimeout","parentAttrs","getId","$$mdSelectId","hashedValue","trackByOption","trackBy","$value","optionKeys","$setPristine","mapFn","selectedOptionEls","rippleContainer","checkboxContainer","addOption","$$rawModelValue","removeOption","prevValHashes","prevValItem","every","newValItem","newValItemHash","prevValHash","hasDefinedValue","setOptionValue","prevAttempt","oldHashKey","newHashKey","selectDefaultOptions","$$loadingAsyncDone","positionAndFocusMenu","watchAsyncLoad","selectMenuElement","selectEl","optionNodes","showDropDown","dropDown","selectMenuController","checkCloseMenu","restoreFocus","focusOption","focusedNode","optNode","focusOptionNode","newOption","optionsArray","prevOption","clickOnScrollbar","mouseOnScrollbar","updates","calculateMenuPositions","activateResizing","nodeToFocus","previousNode","menuController","listboxContentNode","scrollBottom","nodeBottom","animationRunner","destroyListener","mdSelect","announceClosed","centeredNode","selectNode","contentNode","parentRect","spaceAvailable","SELECT_EDGE_MARGIN","selectedNode","optgroupNodes","isScrollable","oldDisplay","calculateScrollable","fontSize","selectMenuRect","centeredRect","centeredStyle","paddingLeft","scrollBuffer","containerRect","n","char","fromCharCode","isNonUsefulKey","setupLabelElement","createDirective","targetValue","multiElement","unregister","SidenavService","$mdComponentRegistry","errorMsg","shouldWait","waitFor","waitForInstance","enableWait","falseFn","rejectFn","onClose","addLegacyAPI","SidenavDirective","sidenavCtrl","lastParentOverFlow","disableCloseEvents","triggeringInteractionType","previousContainerStyles","disableScrollTarget","triggeringElement","isLockedOpenParsed","mdIsLockedOpen","ngWindow","onKeyDown","mdDisableScrollTarget","isLocked","restorePositioning","focusEl","willOpen","drawerEl","positionStyle","updateContainerPositions","$toggleOpen","onCloseCb","SidenavController","rawId","mdComponentId","hasDataBinding","componentId","SliderDirective","slider","setDisable","initialMaxWidth","stopDisabledWatch","fitInputWidthToTextLength","computedStyle","newMaxWidth","thumb","thumbText","thumbContainer","trackContainer","activeTrack","tickContainer","throttledRefreshDimensions","refreshSliderDimensions","vertical","mdVertical","discrete","mdDiscrete","invert","mdInvert","updateMin","updateMax","updateStep","updateRound","updateAll","ngModelRender","changeAmount","updateValue","numSteps","tickCanvas","tickCtx","getContext","getSliderDimensions","sliderDimensions","trackTicksStyle","fillStyle","fillRect","redrawTicks","clearRect","clearTicks","closestVal","minMaxValidator","stepValidator","percentToValue","positionToPercent","setSliderPercent","valueToPercent","setSliderFromEvent","debouncedUpdateAll","percent","minValue","formattedValue","thumbPosition","activeTrackPercent","doSlide","calc","MdSticky","browserStickySupport","stickyClone","contentCtrl","$$sticky","debouncedRefreshElements","refreshElements","isScrolling","lastScrollTime","loopScrollEvent","setupAugmentedScrollEvents","isScrollingDown","prevScrollTop","setCurrentItem","prev","refreshPosition","sort","currentScrollTop","setStickyState","amount","translateY","setupSticky","cloneElement","MdSubheaderDirective","$mdSticky","getContent","getDirective","DirectiveFactory","directiveName","$target","MdSwitch","mdCheckboxDirective","checkboxDirective","checkboxLink","disabledGetter","drag","switchContainer","labelContainer","isInverted","decreasePageOffset","currentOffset","firstVisibleTabOffset","canvas","tabOffsets","getTabOffsets","increasePageOffset","firstHiddenTabOffset","maxOffset","getTotalTabsWidth","sum","active","tabClass","getTabElementIndex","insertTab","getIndex","refreshIndex","updateTabOrder","removeTab","MdTabScroll","mdTabScroll","MdTabsController","$mdTabInkRipple","MdTabsPaginationService","locked","destroyed","defineBooleanAttribute","handleWindowResize","handleStretchTabs","getElements","stretchTabs","shouldPaginate","shouldStretchTabs","updateInkBarStyles","handleCenterTabs","shouldCenterTabs","handleMaxTabWidth","newWidth","oldWidth","dummies","handleShouldPaginate","maxTabWidth","getMaxTabWidth","adjustOffset","selectedIndex","handleHasContent","hasContent","handleOffsetChange","paging","handleFocusIndexChange","oldIndex","redirectFocus","handleSelectedIndexChange","getNearestSafeIndex","lastSelectedIndex","updateHeightFromContent","canSkipClick","focusIndex","noSelectClick","fixOffset","updatePagination","handleInkBar","inkBar","handleDynamicHeight","nextButton","prevButton","centerTabs","noPagination","canvasWidth","calcTabsWidth","containerWidth","incrementIndex","inc","styleTabItemFocus","tabWidthsBefore","tabWidthsIncluding","dynamicHeight","tabContent","contentHeight","tabsHeight","newHeight","currentHeight","fromHeight","toHeight","previousTotalWidth","previousWidthOfTabItems","noInkBar","totalWidth","totalWidthOfTabItems","ink","updateInkBarClassName","handleResizeWhenVisible","lastTab","defineOneWayBinding","tabContentPrefix","navigationHint","$mdTabsTemplate","tabData","hasLoaded","proto","isActive","isLeft","isRight","shouldRender","processQueue","updateHasContent","setAriaControls","scroll","deltaY","deltaX","nextPage","canPageForward","newOffset","previousPage","canPageBack","focusItem","getFocusedTabId","MdTabs","MdTabsDummyWrapper","mutationCallback","childList","subtree","characterData","debounced","MdTabsTemplate","compileScope","enableDisconnect","reconnect","connected","MdToastDirective","$mdToast","MdToastProvider","MdToastController","toastDefaultOptions","activeToastContent","newContent","highlightAction","highlightClasses","highlightClass","actionKey","actionHint","dismissHint","SWIPE_EVENTS","isSmScreen","onSwipe","swipe","openClass","toastOpenClass","toastClass","toast","verticalPositionDefined","positionClasses","templateRoot","mdToolbarDirective","mdScrollShrink","toolbarHeight","disableScrollShrink","shrinkSpeedFactor","mdShrinkSpeedFactor","debouncedContentScroll","onContentScroll","debouncedUpdateHeight","updateToolbarHeight","onMdContentLoad","shrinkWithScroll","closestContent","enableScrollShrink","ngShow","ngHide","newContentEl","hasWhiteFrame","setupScrollShrink","MdTooltipDirective","$mdPanel","$$mdTooltipRegistry","LEAVE_EVENTS","TOOLTIP_DIRECTIONS","mdZIndex","mdDelay","mdVisible","mdAutohide","mdDirection","panelPosition","showTimeout","tooltipId","elementFocusedOnWindowBlur","addAriaLabel","interpolatedText","setVisible","queued","visibleWatcher","onVisibleChanged","panelAnimation","panelConfig","showTooltip","attributeObserver","mutations","mutation","isDisabledMutation","windowScrollEventHandler","windowBlurEventHandler","enterEventHandler","leaveEventHandler","one","mousedownEventHandler","onElementDestroy","configureWatchers","listeners","useCapture","handlers","globalEventHandler","currentHandler","MdTruncateController","virtualRepeatContainerTemplate","VirtualRepeatContainerController","VirtualRepeatController","VirtualRepeatDirective","ForceHeightDirective","scrollSize","scrollOffset","repeater","autoShrink","autoShrinkMin","mdAutoShrinkMin","originalSize","offsetSize","mdOffsetSize","oldElementSize","maxElementPixels","mdTopIndex","bindTopIndex","topIndex","assign","scrollToIndex","sizer","offsetter","boundUpdateSize","updateSize","debouncedUpdateSize","jWindow","mdVirtualRepeat","repeatName","repeatListExpression","extraName","mdExtraName","$transclude","link_","$browser","mdOnDemand","browserCheckUrlChange","$$checkUrlChange","newStartIndex","newEndIndex","newVisibleEnd","endIndex","itemSize","mdItemSize","isFirstRender","isVirtualRepeatUpdating_","itemsLength","unwatchItemSize_","blocks","pooledBlocks","cleanupBlocks_","VirtualRepeatModelArrayLike","model","getItemAtIndex","getLength","mdForceHeight","repeaterCtrl","handleScroll_","isHorizontal","setSize_","dimension","getDimensionName_","unsetSize_","containerUpdated","getScrollSize","sizeScroller_","crossDimension","numChildren","sizerChild","autoShrink_","shrinkSize","getItemSize","currentSize","_originalSize","setScrollSize","itemsSize","getScrollOffset","resetScroll","maxSize","numItems","getItemCount","Block","rawRepeatListExpression","sized","repeatListExpression_","block","readItemSize_","getBlock_","poolBlock_","repeatList","virtualList","$$includeIndexes","oldItems","virtualRepeatUpdate_","updateIndexes_","lengthChanged","previousScrollOffset","blockIndex","newStartBlocks","newEndBlocks","updateBlock_","maxIndex","domFragmentFromBlocks_","firstRenderStartIndex","mdStartIndex","new","updateScope_","fragment","containerLength","MdWhiteframeDirective","oldClass","elevation","newClass","$updateClass","ngMaterial","full","MdBottomSheetCollapsibleDirective","$mdBottomSheetCollapsible","MdBottomSheetCollapsibleProvider","bottomSheetCollapsibleDefaults","bottomSheetCollapsible","BottomSheetCollapsible","onLoad","setHalfway","deregisterDrag","LHeight","MHeight","dragging","setExpanded","setMinimized","getState","composedPath","STATE_VELOCITY","api","__esModule","exports","ngAriaModule","angularVersion","ariaChecked","ariaReadonly","ariaDisabled","ariaRequired","ariaInvalid","ariaValue","bindKeydown","bindRoleForClick","watchExpr","ariaAttr","nativeAriaNodeNames","negate","ariaCamelName","isNodeOneOf","boolVal","newConfig","$$watchExpr","nodeTypeArray","$aria","shouldAttachAttr","allowNonAriaNodes","shouldAttachRole","shape","getShape","needsTabIndex","ngAriaWatchModelValue","needsAriaValuemin","needsAriaValuemax","needsAriaValuenow","ngMessages","ngKeydown","ngKeypress","ngKeyup","TRANSITION_PROP","TRANSITIONEND_EVENT","ANIMATION_PROP","ANIMATIONEND_EVENT","ontransitionend","onwebkittransitionend","onanimationend","onwebkitanimationend","ANIMATION_DELAY_PROP","ANIMATION_DURATION_PROP","TRANSITION_DELAY_PROP","TRANSITION_DURATION_PROP","ngMinErr","$$minErr","assertArg","mergeClasses","pendClasses","fix","isPrefix","klass","stripCommentsFromElement","jqLite","extractElementNode","elm","applyAnimationClassesFactory","$$addClass","$$removeClass","prepareAnimationOptions","$$prepared","domOperation","$$domOperationFired","mergeAnimationDetails","oldAnimation","newAnimation","newOptions","existing","splitClassesToLookup","allow","resolveElementClasses","preparationClasses","concatWithSpace","realDomOperation","blockKeyframeAnimations","applyBlock","applyInlineStyle","styleTuple","helpers","$$AnimateChildrenDirective","ngAnimateChildren","setData","DETECT_CSS_PROPERTIES","animationIterationCount","DETECT_STAGGER_CSS_PROPERTIES","getCssDelayStyle","isKeyframeAnimation","computeCssStyles","properties","detectedStyles","formalStyleName","actualStyleName","truthyTimingValue","getCssTransitionDurationStyle","applyOnlyDuration","registerRestorableStyles","backup","$AnimateCssProvider","$animateProvider","$$animateCache","$sniffer","$$rAFScheduler","$$animateQueue","applyAnimationClasses","waitUntilQuiet","flush","cacheKey","allowNoDuration","hasDuration","put","computeCachedCssStyles","aD","tD","maxDelay","initialOptions","restoreStyles","closeAndReturnNoopAnimator","animationPaused","animationCompleted","runnerHost","packageStyles","animations","transitions","method","isStructural","structuralClassName","addRemoveClassName","applyClassesEarly","hasToStyles","stagger","containsCachedAnimationWithoutDuration","staggerVal","staggerCacheKey","staggerClassName","computeCachedCssStaggerStyles","$$skipPreparationClasses","durationStyle","itemIndex","staggerIndex","isFirst","skipBlocking","fullClassName","relativeDelay","hasTransitions","hasAnimations","hasTransitionAll","applyTransitionDuration","applyAnimationDuration","applyTransitionDelay","applyAnimationDelay","recalculateTimingStyles","delayStyle","activeClasses","blockKeyframeAnimation","cleanupStyles","applyBlocking","$$willAnimate","endFn","cancelFn","rejected","setProperty","removeProperty","onDone","onAnimationProgress","animationTimerData","removeData","$manualTimeStamp","playPause","playAnimation","arr","maxStagger","triggerAnimationStart","easeProp","easeVal","timerTime","animationsData","setupFallbackTimer","currentTimerData","expectedEndTime","onAnimationExpired","$$AnimateCssDriverProvider","$$animationProvider","drivers","bodyNode","rootNode","rootBodyElement","animationDetails","anchors","fromAnimation","prepareRegularAnimation","toAnimation","anchorAnimations","anchor","outAnchor","inAnchor","startingClasses","filterCssClasses","getClassVal","animatorIn","animatorOut","calculateAnchorStyles","prepareOutAnimation","prepareInAnimation","startingAnimator","currentAnimation","coords","endingClasses","getUniqueValues","NG_IN_ANCHOR_CLASS_NAME","NG_OUT_ANCHOR_CLASS_NAME","prepareAnchoredAnimation","animationRunners","prepareFromToAnchorAnimation","$$AnimateJsProvider","before","afterFn","beforeFn","classesToAdd","classesToRemove","lookupAnimations","packageAnimations","closeActiveAnimations","chain","applyOptions","endAnimations","success","cancelled","executeAnimationFn","groupEventedAnimations","fnName","operations","ani","endProgressCb","resolved","onAnimationComplete","animateFn","flagMap","animationFactory","$$registeredAnimations","$$AnimateJsDriverProvider","$$animateJs","prepareAnimation","endFnFactory","$$AnimateQueueProvider","skip","getEventData","hasMatchingClasses","newClassString","currentClassString","currentClassMap","classString","makeTruthyCssClassMap","isAllowed","ruleType","previousAnimation","hasAnimationClasses","and","nA","nR","cA","cR","$$Map","$$animation","$$isDocumentHidden","activeAnimationsLookup","disabledElementsLookup","animationsEnabled","removeFromDisabledElementsLookup","evt","delete","deregisterWatch","totalPendingRequests","isEmpty","callbackRegistry","customFilter","classNameFilter","returnTrue","isAnimatableByFilter","isAnimatableClassName","normalizeAnimationDetails","filterFromRegistry","matchContainer","matchCallback","cleanupEventListeners","phase","entries","originalElement","runInNextPostDigestOrNow","postDigestCalled","documentHidden","skipAnimations","existingAnimation","hasExistingAnimation","animateChildren","bodyNodeDetected","rootNodeDetected","parentAnimationDetected","elementDisabled","parentHost","details","parentNodeDisabled","notifyProgress","closeChildAnimations","applyGeneratedPreparationClasses","isValidAnimation","clearElementAnimationState","counter","markElementAnimationState","animationCancelled","realRunner","callbacks","targetParentNode","findCallbacks","clearGeneratedClasses","queueAnimation","argCount","hasElement","$$AnimationProvider","getRunner","animationQueue","tempClasses","setRunner","beforeStart","prepareClassName","handleDestroyedElement","groupedAnimations","preparedAnimations","refLookup","enterOrMove","anchorNodes","getAnchorNodes","animationID","usedIndicesLookup","anchorGroups","lookupKey","cssClassesIntersection","indexKey","groupAnimations","toBeSortedAnimations","animationEntry","extraClasses","domNode","startAnimationFn","operation","driverName","driver","invokeFirstDriver","newRunner","update","updateAnimationRunners","finalAnimations","tree","lookup","processNode","remainingLevelEntries","nextLevelEntries","childEntry","flatten","processed","parentEntry","elementNode","sortAnimations","innerArray","aa","removeRunner","previousElement","previousScope","ngAnimateSwap","childScope","scheduler","tasks","KEY","parentCounter","isValid","total"],"mappings":"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","file":"vendors~lazy-material.455a52482e79cdd5ebbe.bundle.js","sourcesContent":["/*!\n * AngularJS Material Design\n * https://github.com/angular/material\n * @license MIT\n * v1.2.2\n */\n(function( window, angular, undefined ){\n\"use strict\";\n\n(function(){\n\"use strict\";\n\nangular.module('ngMaterial', [\"ng\",\"ngAnimate\",\"ngAria\",\"material.core\",\"material.core.animate\",\"material.core.gestures\",\"material.core.interaction\",\"material.core.layout\",\"material.core.meta\",\"material.core.theming.palette\",\"material.core.theming\",\"material.components.autocomplete\",\"material.components.backdrop\",\"material.components.bottomSheet\",\"material.components.button\",\"material.components.card\",\"material.components.checkbox\",\"material.components.chips\",\"material.components.colors\",\"material.components.content\",\"material.components.datepicker\",\"material.components.dialog\",\"material.components.divider\",\"material.components.fabActions\",\"material.components.fabShared\",\"material.components.fabSpeedDial\",\"material.components.fabToolbar\",\"material.components.gridList\",\"material.components.icon\",\"material.components.input\",\"material.components.list\",\"material.components.menu\",\"material.components.menuBar\",\"material.components.navBar\",\"material.components.panel\",\"material.components.progressCircular\",\"material.components.progressLinear\",\"material.components.radioButton\",\"material.components.select\",\"material.components.showHide\",\"material.components.sidenav\",\"material.components.slider\",\"material.components.sticky\",\"material.components.subheader\",\"material.components.swipe\",\"material.components.switch\",\"material.components.tabs\",\"material.components.toast\",\"material.components.toolbar\",\"material.components.tooltip\",\"material.components.truncate\",\"material.components.virtualRepeat\",\"material.components.whiteframe\"]);\n})();\n(function(){\n\"use strict\";\n\n/**\n * Initialization function that validates environment\n * requirements.\n */\nDetectNgTouch.$inject = [\"$log\", \"$injector\"];\nMdCoreConfigure.$inject = [\"$provide\", \"$mdThemingProvider\"];\nrAFDecorator.$inject = [\"$delegate\"];\nqDecorator.$inject = [\"$delegate\"];\nangular\n  .module('material.core', [\n    'ngAnimate',\n    'material.core.animate',\n    'material.core.layout',\n    'material.core.interaction',\n    'material.core.gestures',\n    'material.core.theming'\n  ])\n  .config(MdCoreConfigure)\n  .run(DetectNgTouch);\n\n\n/**\n * Detect if the ng-Touch module is also being used.\n * Warn if detected.\n * @ngInject\n */\nfunction DetectNgTouch($log, $injector) {\n  if ($injector.has('$swipe')) {\n    var msg = \"\" +\n      \"You are using the ngTouch module. \\n\" +\n      \"AngularJS Material already has mobile click, tap, and swipe support... \\n\" +\n      \"ngTouch is not supported with AngularJS Material!\";\n    $log.warn(msg);\n  }\n}\n\n/**\n * @ngInject\n */\nfunction MdCoreConfigure($provide, $mdThemingProvider) {\n\n  $provide.decorator('$$rAF', ['$delegate', rAFDecorator]);\n  $provide.decorator('$q', ['$delegate', qDecorator]);\n\n  $mdThemingProvider.theme('default')\n    .primaryPalette('indigo')\n    .accentPalette('pink')\n    .warnPalette('deep-orange')\n    .backgroundPalette('grey');\n}\n\n/**\n * @ngInject\n */\nfunction rAFDecorator($delegate) {\n  /**\n   * Use this to throttle events that come in often.\n   * The throttled function will always use the *last* invocation before the\n   * coming frame.\n   *\n   * For example, window resize events that fire many times a second:\n   * If we set to use an raf-throttled callback on window resize, then\n   * our callback will only be fired once per frame, with the last resize\n   * event that happened before that frame.\n   *\n   * @param {function} cb function to debounce\n   */\n  $delegate.throttle = function(cb) {\n    var queuedArgs, alreadyQueued, queueCb, context;\n    return function debounced() {\n      queuedArgs = arguments;\n      context = this;\n      queueCb = cb;\n      if (!alreadyQueued) {\n        alreadyQueued = true;\n        $delegate(function() {\n          queueCb.apply(context, Array.prototype.slice.call(queuedArgs));\n          alreadyQueued = false;\n        });\n      }\n    };\n  };\n  return $delegate;\n}\n\n/**\n * @ngInject\n */\nfunction qDecorator($delegate) {\n  /**\n   * Adds a shim for $q.resolve for AngularJS version that don't have it,\n   * so we don't have to think about it.\n   *\n   * via https://github.com/angular/angular.js/pull/11987\n   */\n\n  // TODO(crisbeto): this won't be necessary once we drop AngularJS 1.3\n  if (!$delegate.resolve) {\n    $delegate.resolve = $delegate.when;\n  }\n  return $delegate;\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMdAutofocusDirective.$inject = [\"$parse\"];angular.module('material.core')\n  .directive('mdAutofocus', MdAutofocusDirective);\n\n/**\n * @ngdoc directive\n * @name mdAutofocus\n * @module material.core.util\n *\n * @description\n *\n * `[md-autofocus]` provides an optional way to identify the focused element when a `$mdDialog`,\n * `$mdBottomSheet`, `$mdMenu` or `$mdSidenav` opens or upon page load for input-like elements.\n *\n * When one of these opens, it will find the first nested element with the `[md-autofocus]`\n * attribute directive and optional expression. An expression may be specified as the directive\n * value to enable conditional activation of the autofocus.\n *\n * @usage\n *\n * ### Dialog\n * <hljs lang=\"html\">\n * <md-dialog>\n *   <form>\n *     <md-input-container>\n *       <label for=\"testInput\">Label</label>\n *       <input id=\"testInput\" type=\"text\" md-autofocus>\n *     </md-input-container>\n *   </form>\n * </md-dialog>\n * </hljs>\n *\n * ### Bottomsheet\n * <hljs lang=\"html\">\n * <md-bottom-sheet class=\"md-list md-has-header\">\n *  <md-subheader>Comment Actions</md-subheader>\n *  <md-list>\n *    <md-list-item ng-repeat=\"item in items\">\n *\n *      <md-button md-autofocus=\"$index == 2\">\n *        <md-icon md-svg-src=\"{{item.icon}}\"></md-icon>\n *        <span class=\"md-inline-list-icon-label\">{{ item.name }}</span>\n *      </md-button>\n *\n *    </md-list-item>\n *  </md-list>\n * </md-bottom-sheet>\n * </hljs>\n *\n * ### Autocomplete\n * <hljs lang=\"html\">\n *   <md-autocomplete\n *       md-autofocus\n *       md-selected-item=\"selectedItem\"\n *       md-search-text=\"searchText\"\n *       md-items=\"item in getMatches(searchText)\"\n *       md-item-text=\"item.display\">\n *     <span md-highlight-text=\"searchText\">{{item.display}}</span>\n *   </md-autocomplete>\n * </hljs>\n *\n * ### Sidenav\n * <hljs lang=\"html\">\n * <div layout=\"row\" ng-controller=\"MyController\">\n *   <md-sidenav md-component-id=\"left\" class=\"md-sidenav-left\">\n *     Left Nav!\n *   </md-sidenav>\n *\n *   <md-content>\n *     Center Content\n *     <md-button ng-click=\"openLeftMenu()\">\n *       Open Left Menu\n *     </md-button>\n *   </md-content>\n *\n *   <md-sidenav md-component-id=\"right\"\n *     md-is-locked-open=\"$mdMedia('min-width: 333px')\"\n *     class=\"md-sidenav-right\">\n *     <form>\n *       <md-input-container>\n *         <label for=\"testInput\">Test input</label>\n *         <input id=\"testInput\" type=\"text\"\n *                ng-model=\"data\" md-autofocus>\n *       </md-input-container>\n *     </form>\n *   </md-sidenav>\n * </div>\n * </hljs>\n **/\nfunction MdAutofocusDirective($parse) {\n  return {\n    restrict: 'A',\n    link: {\n      pre: preLink\n    }\n  };\n\n  function preLink(scope, element, attr) {\n    var attrExp = attr.mdAutoFocus || attr.mdAutofocus || attr.mdSidenavFocus;\n\n    // Initially update the expression by manually parsing the expression as per $watch source.\n    updateExpression($parse(attrExp)(scope));\n\n    // Only watch the expression if it is not empty.\n    if (attrExp) {\n      scope.$watch(attrExp, updateExpression);\n    }\n\n    /**\n     * Updates the autofocus class which is used to determine whether the attribute\n     * expression evaluates to true or false.\n     * @param {string|boolean} value Attribute Value\n     */\n    function updateExpression(value) {\n\n      // Rather than passing undefined to the jqLite toggle class function we explicitly set the\n      // value to true. Otherwise the class will be just toggled instead of being forced.\n      if (angular.isUndefined(value)) {\n        value = true;\n      }\n\n      element.toggleClass('md-autofocus', !!value);\n    }\n  }\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.core.colorUtil\n * @description\n * Color Util\n */\nangular\n  .module('material.core')\n  .factory('$mdColorUtil', ColorUtilFactory);\n\nfunction ColorUtilFactory() {\n  /**\n   * Converts hex value to RGBA string\n   * @param color {string}\n   * @returns {string}\n   */\n  function hexToRgba (color) {\n    var hex   = color[ 0 ] === '#' ? color.substr(1) : color,\n      dig   = hex.length / 3,\n      red   = hex.substr(0, dig),\n      green = hex.substr(dig, dig),\n      blue  = hex.substr(dig * 2);\n    if (dig === 1) {\n      red += red;\n      green += green;\n      blue += blue;\n    }\n    return 'rgba(' + parseInt(red, 16) + ',' + parseInt(green, 16) + ',' + parseInt(blue, 16) + ',0.1)';\n  }\n\n  /**\n   * Converts rgba value to hex string\n   * @param {string} color\n   * @returns {string}\n   */\n  function rgbaToHex(color) {\n    color = color.match(/^rgba?[\\s+]?\\([\\s+]?(\\d+)[\\s+]?,[\\s+]?(\\d+)[\\s+]?,[\\s+]?(\\d+)[\\s+]?/i);\n\n    var hex = (color && color.length === 4) ? \"#\" +\n    (\"0\" + parseInt(color[1],10).toString(16)).slice(-2) +\n    (\"0\" + parseInt(color[2],10).toString(16)).slice(-2) +\n    (\"0\" + parseInt(color[3],10).toString(16)).slice(-2) : '';\n\n    return hex.toUpperCase();\n  }\n\n  /**\n   * Converts an RGB color to RGBA\n   * @param {string} color\n   * @returns {string}\n   */\n  function rgbToRgba (color) {\n    return color.replace(')', ', 0.1)').replace('(', 'a(');\n  }\n\n  /**\n   * Converts an RGBA color to RGB\n   * @param {string} color\n   * @returns {string}\n   */\n  function rgbaToRgb (color) {\n    return color\n      ? color.replace('rgba', 'rgb').replace(/,[^),]+\\)/, ')')\n      : 'rgb(0,0,0)';\n  }\n\n  return {\n    rgbaToHex: rgbaToHex,\n    hexToRgba: hexToRgba,\n    rgbToRgba: rgbToRgba,\n    rgbaToRgb: rgbaToRgb\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\nangular.module('material.core')\n.factory('$mdConstant', MdConstantFactory);\n\n/**\n * Factory function that creates the grab-bag $mdConstant service.\n * @ngInject\n */\nfunction MdConstantFactory() {\n\n  var prefixTestEl = document.createElement('div');\n  var vendorPrefix = getVendorPrefix(prefixTestEl);\n  var isWebkit = /webkit/i.test(vendorPrefix);\n  var SPECIAL_CHARS_REGEXP = /([:\\-_]+(.))/g;\n\n  /**\n   * @param {string} name CSS property name\n   * @return {string} the property name supported by the browser\n   */\n  function vendorProperty(name) {\n    // Add a dash between the prefix and name, to be able to transform the string into camelcase.\n    var prefixedName = vendorPrefix + '-' + name;\n    var ucPrefix = camelCase(prefixedName);\n    var lcPrefix = ucPrefix.charAt(0).toLowerCase() + ucPrefix.substring(1);\n\n    return hasStyleProperty(prefixTestEl, name)     ? name     :       // The current browser supports the un-prefixed property\n           hasStyleProperty(prefixTestEl, ucPrefix) ? ucPrefix :       // The current browser only supports the prefixed property.\n           hasStyleProperty(prefixTestEl, lcPrefix) ? lcPrefix : name; // Some browsers are only supporting the prefix in lowercase.\n  }\n\n  function hasStyleProperty(testElement, property) {\n    return angular.isDefined(testElement.style[property]);\n  }\n\n  /**\n   * @param {!string} input value to convert to camelCase\n   * @return {string} camelCased version of the input string\n   */\n  function camelCase(input) {\n    return input.replace(SPECIAL_CHARS_REGEXP, function(matches, separator, letter, offset) {\n      return offset ? letter.toUpperCase() : letter;\n    });\n  }\n\n  function getVendorPrefix(testElement) {\n    var prop, match;\n    var vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/;\n\n    for (prop in testElement.style) {\n      if (match = vendorRegex.exec(prop)) {\n        return match[0];\n      }\n    }\n  }\n\n  var self = {\n    isInputKey : function(e) { return (e.keyCode >= 31 && e.keyCode <= 90); },\n    isNumPadKey : function(e) { return (3 === e.location && e.keyCode >= 97 && e.keyCode <= 105); },\n    isMetaKey: function(e) { return (e.keyCode >= 91 && e.keyCode <= 93); },\n    isFnLockKey: function(e) { return (e.keyCode >= 112 && e.keyCode <= 145); },\n    isNavigationKey : function(e) {\n      var kc = self.KEY_CODE, NAVIGATION_KEYS =  [kc.SPACE, kc.ENTER, kc.UP_ARROW, kc.DOWN_ARROW];\n      return (NAVIGATION_KEYS.indexOf(e.keyCode) != -1);\n    },\n    hasModifierKey: function(e) {\n      return e.ctrlKey || e.metaKey || e.altKey;\n    },\n\n    /**\n     * Maximum size, in pixels, that can be explicitly set to an element. The actual value varies\n     * between browsers, but IE11 has the very lowest size at a mere 1,533,917px. Ideally we could\n     * compute this value, but Firefox always reports an element to have a size of zero if it\n     * goes over the max, meaning that we'd have to binary search for the value.\n     */\n    ELEMENT_MAX_PIXELS: 1533917,\n\n    /**\n     * Priority for a directive that should run before the directives from ngAria.\n     */\n    BEFORE_NG_ARIA: 210,\n\n    /**\n     * Common Keyboard actions and their associated keycode.\n     */\n    KEY_CODE: {\n      COMMA: 188,\n      SEMICOLON : 186,\n      ENTER: 13,\n      ESCAPE: 27,\n      SPACE: 32,\n      PAGE_UP: 33,\n      PAGE_DOWN: 34,\n      END: 35,\n      HOME: 36,\n      LEFT_ARROW : 37,\n      UP_ARROW : 38,\n      RIGHT_ARROW : 39,\n      DOWN_ARROW : 40,\n      TAB : 9,\n      BACKSPACE: 8,\n      DELETE: 46\n    },\n\n    /**\n     * Vendor prefixed CSS properties to be used to support the given functionality in older browsers\n     * as well.\n     */\n    CSS: {\n      /* Constants */\n      TRANSITIONEND: 'transitionend' + (isWebkit ? ' webkitTransitionEnd' : ''),\n      ANIMATIONEND: 'animationend' + (isWebkit ? ' webkitAnimationEnd' : ''),\n\n      TRANSFORM: vendorProperty('transform'),\n      TRANSFORM_ORIGIN: vendorProperty('transformOrigin'),\n      TRANSITION: vendorProperty('transition'),\n      TRANSITION_DURATION: vendorProperty('transitionDuration'),\n      ANIMATION_PLAY_STATE: vendorProperty('animationPlayState'),\n      ANIMATION_DURATION: vendorProperty('animationDuration'),\n      ANIMATION_NAME: vendorProperty('animationName'),\n      ANIMATION_TIMING: vendorProperty('animationTimingFunction'),\n      ANIMATION_DIRECTION: vendorProperty('animationDirection')\n    },\n\n    /**\n     * As defined in core/style/_variables.scss\n     *\n     * $layout-breakpoint-xs:     600px !default;\n     * $layout-breakpoint-sm:     960px !default;\n     * $layout-breakpoint-md:     1280px !default;\n     * $layout-breakpoint-lg:     1920px !default;\n     *\n     */\n    MEDIA: {\n      'xs'        : '(max-width: 599px)'                         ,\n      'gt-xs'     : '(min-width: 600px)'                         ,\n      'sm'        : '(min-width: 600px) and (max-width: 959px)'  ,\n      'gt-sm'     : '(min-width: 960px)'                         ,\n      'md'        : '(min-width: 960px) and (max-width: 1279px)' ,\n      'gt-md'     : '(min-width: 1280px)'                        ,\n      'lg'        : '(min-width: 1280px) and (max-width: 1919px)',\n      'gt-lg'     : '(min-width: 1920px)'                        ,\n      'xl'        : '(min-width: 1920px)'                        ,\n      'landscape' : '(orientation: landscape)'                   ,\n      'portrait'  : '(orientation: portrait)'                    ,\n      'print' : 'print'\n    },\n\n    MEDIA_PRIORITY: [\n      'xl',\n      'gt-lg',\n      'lg',\n      'gt-md',\n      'md',\n      'gt-sm',\n      'sm',\n      'gt-xs',\n      'xs',\n      'landscape',\n      'portrait',\n      'print'\n    ]\n  };\n\n  return self;\n}\n\n})();\n(function(){\n\"use strict\";\n\n  angular\n    .module('material.core')\n    .config([\"$provide\", function($provide){\n       $provide.decorator('$mdUtil', ['$delegate', function ($delegate){\n           /**\n            * Inject the iterator facade to easily support iteration and accessors\n            * @see iterator below\n            */\n           $delegate.iterator = MdIterator;\n\n           return $delegate;\n         }\n       ]);\n     }]);\n\n  /**\n   * iterator is a list facade to easily support iteration and accessors/\n   *\n   * @param {any[]} items Array list which this iterator will enumerate\n   * @param {boolean=} reloop enables iterator to consider the list as an endless loop\n   * @return {{add: add, next: (function()), last: (function(): any|null), previous: (function()), count: (function(): number), hasNext: (function(*=): Array.length|*|number|boolean), inRange: (function(*): boolean), remove: remove, contains: (function(*=): *|boolean), itemAt: (function(*=): any|null), findBy: (function(*, *): *[]), hasPrevious: (function(*=): Array.length|*|number|boolean), items: (function(): *[]), indexOf: (function(*=): number), first: (function(): any|null)}}\n   * @constructor\n   */\n  function MdIterator(items, reloop) {\n    var trueFn = function() { return true; };\n\n    if (items && !angular.isArray(items)) {\n      items = Array.prototype.slice.call(items);\n    }\n\n    reloop = !!reloop;\n    var _items = items || [];\n\n    // Published API\n    return {\n      items: getItems,\n      count: count,\n\n      inRange: inRange,\n      contains: contains,\n      indexOf: indexOf,\n      itemAt: itemAt,\n\n      findBy: findBy,\n\n      add: add,\n      remove: remove,\n\n      first: first,\n      last: last,\n      next: angular.bind(null, findSubsequentItem, false),\n      previous: angular.bind(null, findSubsequentItem, true),\n\n      hasPrevious: hasPrevious,\n      hasNext: hasNext\n    };\n\n    /**\n     * Publish copy of the enumerable set\n     * @returns {Array|*}\n     */\n    function getItems() {\n      return [].concat(_items);\n    }\n\n    /**\n     * Determine length of the list\n     * @returns {Array.length|*|number}\n     */\n    function count() {\n      return _items.length;\n    }\n\n    /**\n     * Is the index specified valid\n     * @param index\n     * @returns {Array.length|*|number|boolean}\n     */\n    function inRange(index) {\n      return _items.length && (index > -1) && (index < _items.length);\n    }\n\n    /**\n     * Can the iterator proceed to the next item in the list; relative to\n     * the specified item.\n     *\n     * @param item\n     * @returns {Array.length|*|number|boolean}\n     */\n    function hasNext(item) {\n      return item ? inRange(indexOf(item) + 1) : false;\n    }\n\n    /**\n     * Can the iterator proceed to the previous item in the list; relative to\n     * the specified item.\n     *\n     * @param item\n     * @returns {Array.length|*|number|boolean}\n     */\n    function hasPrevious(item) {\n      return item ? inRange(indexOf(item) - 1) : false;\n    }\n\n    /**\n     * Get item at specified index/position\n     * @param index\n     * @returns {*}\n     */\n    function itemAt(index) {\n      return inRange(index) ? _items[index] : null;\n    }\n\n    /**\n     * Find all elements matching the key/value pair\n     * otherwise return null\n     *\n     * @param val\n     * @param key\n     *\n     * @return array\n     */\n    function findBy(key, val) {\n      return _items.filter(function(item) {\n        return item[key] === val;\n      });\n    }\n\n    /**\n     * Add item to list\n     * @param item\n     * @param index\n     * @returns {*}\n     */\n    function add(item, index) {\n      if (!item) return -1;\n\n      if (!angular.isNumber(index)) {\n        index = _items.length;\n      }\n\n      _items.splice(index, 0, item);\n\n      return indexOf(item);\n    }\n\n    /**\n     * Remove item from list...\n     * @param item\n     */\n    function remove(item) {\n      if (contains(item)){\n        _items.splice(indexOf(item), 1);\n      }\n    }\n\n    /**\n     * Get the zero-based index of the target item\n     * @param item\n     * @returns {*}\n     */\n    function indexOf(item) {\n      return _items.indexOf(item);\n    }\n\n    /**\n     * Boolean existence check\n     * @param item\n     * @returns {boolean}\n     */\n    function contains(item) {\n      return item && (indexOf(item) > -1);\n    }\n\n    /**\n     * Return first item in the list\n     * @returns {*}\n     */\n    function first() {\n      return _items.length ? _items[0] : null;\n    }\n\n    /**\n     * Return last item in the list...\n     * @returns {*}\n     */\n    function last() {\n      return _items.length ? _items[_items.length - 1] : null;\n    }\n\n    /**\n     * Find the next item. If reloop is true and at the end of the list, it will go back to the\n     * first item. If given, the `validate` callback will be used to determine whether the next item\n     * is valid. If not valid, it will try to find the next item again.\n     *\n     * @param {boolean} backwards Specifies the direction of searching (forwards/backwards)\n     * @param {*} item The item whose subsequent item we are looking for\n     * @param {Function=} validate The `validate` function\n     * @param {integer=} limit The recursion limit\n     *\n     * @returns {*} The subsequent item or null\n     */\n    function findSubsequentItem(backwards, item, validate, limit) {\n      validate = validate || trueFn;\n\n      var curIndex = indexOf(item);\n      while (true) {\n        if (!inRange(curIndex)) return null;\n\n        var nextIndex = curIndex + (backwards ? -1 : 1);\n        var foundItem = null;\n        if (inRange(nextIndex)) {\n          foundItem = _items[nextIndex];\n        } else if (reloop) {\n          foundItem = backwards ? last() : first();\n          nextIndex = indexOf(foundItem);\n        }\n\n        if ((foundItem === null) || (nextIndex === limit)) return null;\n        if (validate(foundItem)) return foundItem;\n\n        if (angular.isUndefined(limit)) limit = nextIndex;\n\n        curIndex = nextIndex;\n      }\n    }\n  }\n\n\n})();\n(function(){\n\"use strict\";\n\n\nmdMediaFactory.$inject = [\"$mdConstant\", \"$rootScope\", \"$window\"];angular.module('material.core')\n.factory('$mdMedia', mdMediaFactory);\n\n/**\n * @ngdoc service\n * @name $mdMedia\n * @module material.core\n *\n * @description\n * `$mdMedia` is used to evaluate whether a given media query is true or false given the\n * current device's screen / window size. The media query will be re-evaluated on resize, allowing\n * you to register a watch.\n *\n * `$mdMedia` also has pre-programmed support for media queries that match the layout breakpoints:\n *\n *  <table class=\"md-api-table\">\n *    <thead>\n *    <tr>\n *      <th>Breakpoint</th>\n *      <th>mediaQuery</th>\n *    </tr>\n *    </thead>\n *    <tbody>\n *    <tr>\n *      <td>xs</td>\n *      <td>(max-width: 599px)</td>\n *    </tr>\n *    <tr>\n *      <td>gt-xs</td>\n *      <td>(min-width: 600px)</td>\n *    </tr>\n *    <tr>\n *      <td>sm</td>\n *      <td>(min-width: 600px) and (max-width: 959px)</td>\n *    </tr>\n *    <tr>\n *      <td>gt-sm</td>\n *      <td>(min-width: 960px)</td>\n *    </tr>\n *    <tr>\n *      <td>md</td>\n *      <td>(min-width: 960px) and (max-width: 1279px)</td>\n *    </tr>\n *    <tr>\n *      <td>gt-md</td>\n *      <td>(min-width: 1280px)</td>\n *    </tr>\n *    <tr>\n *      <td>lg</td>\n *      <td>(min-width: 1280px) and (max-width: 1919px)</td>\n *    </tr>\n *    <tr>\n *      <td>gt-lg</td>\n *      <td>(min-width: 1920px)</td>\n *    </tr>\n *    <tr>\n *      <td>xl</td>\n *      <td>(min-width: 1920px)</td>\n *    </tr>\n *    <tr>\n *      <td>landscape</td>\n *      <td>landscape</td>\n *    </tr>\n *    <tr>\n *      <td>portrait</td>\n *      <td>portrait</td>\n *    </tr>\n *    <tr>\n *      <td>print</td>\n *      <td>print</td>\n *    </tr>\n *    </tbody>\n *  </table>\n *\n *  See Material Design's <a href=\"https://material.google.com/layout/responsive-ui.html\">Layout - Adaptive UI</a> for more details.\n *\n *  <a href=\"https://material.io/archive/guidelines/layout/responsive-ui.html#\">\n *  <img src=\"https://material-design.storage.googleapis.com/publish/material_v_4/material_ext_publish/0B8olV15J7abPSGFxemFiQVRtb1k/layout_adaptive_breakpoints_01.png\" width=\"100%\" height=\"100%\"></img>\n *  </a>\n *\n * @returns {boolean} a boolean representing whether or not the given media query is true or false.\n *\n * @usage\n * <hljs lang=\"js\">\n * app.controller('MyController', function($mdMedia, $scope) {\n *   $scope.$watch(function() { return $mdMedia('lg'); }, function(big) {\n *     $scope.bigScreen = big;\n *   });\n *\n *   $scope.screenIsSmall = $mdMedia('sm');\n *   $scope.customQuery = $mdMedia('(min-width: 1234px)');\n *   $scope.anotherCustom = $mdMedia('max-width: 300px');\n * });\n * </hljs>\n */\n\n/* @ngInject */\nfunction mdMediaFactory($mdConstant, $rootScope, $window) {\n  var queries = {};\n  var mqls = {};\n  var results = {};\n  var normalizeCache = {};\n\n  $mdMedia.getResponsiveAttribute = getResponsiveAttribute;\n  $mdMedia.getQuery = getQuery;\n  $mdMedia.watchResponsiveAttributes = watchResponsiveAttributes;\n\n  return $mdMedia;\n\n  function $mdMedia(query) {\n    var validated = queries[query];\n    if (angular.isUndefined(validated)) {\n      validated = queries[query] = validate(query);\n    }\n\n    var result = results[validated];\n    if (angular.isUndefined(result)) {\n      result = add(validated);\n    }\n\n    return result;\n  }\n\n  function validate(query) {\n    return $mdConstant.MEDIA[query] ||\n           ((query.charAt(0) !== '(') ? ('(' + query + ')') : query);\n  }\n\n  function add(query) {\n    var result = mqls[query];\n    if (!result) {\n      result = mqls[query] = $window.matchMedia(query);\n    }\n\n    result.addListener(onQueryChange);\n    return (results[result.media] = !!result.matches);\n  }\n\n  function onQueryChange(query) {\n    $rootScope.$evalAsync(function() {\n      results[query.media] = !!query.matches;\n    });\n  }\n\n  function getQuery(name) {\n    return mqls[name];\n  }\n\n  function getResponsiveAttribute(attrs, attrName) {\n    for (var i = 0; i < $mdConstant.MEDIA_PRIORITY.length; i++) {\n      var mediaName = $mdConstant.MEDIA_PRIORITY[i];\n      if (!mqls[queries[mediaName]].matches) {\n        continue;\n      }\n\n      var normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName);\n      if (attrs[normalizedName]) {\n        return attrs[normalizedName];\n      }\n    }\n\n    // fallback on unprefixed\n    return attrs[getNormalizedName(attrs, attrName)];\n  }\n\n  function watchResponsiveAttributes(attrNames, attrs, watchFn) {\n    var unwatchFns = [];\n    attrNames.forEach(function(attrName) {\n      var normalizedName = getNormalizedName(attrs, attrName);\n      if (angular.isDefined(attrs[normalizedName])) {\n        unwatchFns.push(\n            attrs.$observe(normalizedName, angular.bind(void 0, watchFn, null)));\n      }\n\n      for (var mediaName in $mdConstant.MEDIA) {\n        normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName);\n        if (angular.isDefined(attrs[normalizedName])) {\n          unwatchFns.push(\n              attrs.$observe(normalizedName, angular.bind(void 0, watchFn, mediaName)));\n        }\n      }\n    });\n\n    return function unwatch() {\n      unwatchFns.forEach(function(fn) { fn(); });\n    };\n  }\n\n  // Improves performance dramatically\n  function getNormalizedName(attrs, attrName) {\n    return normalizeCache[attrName] ||\n        (normalizeCache[attrName] = attrs.$normalize(attrName));\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\nangular\n  .module('material.core')\n  .config([\"$provide\", function($provide) {\n    $provide.decorator('$mdUtil', ['$delegate', function ($delegate) {\n\n      // Inject the prefixer into our original $mdUtil service.\n      $delegate.prefixer = MdPrefixer;\n\n      return $delegate;\n    }]);\n  }]);\n\n/**\n * @param {string|string[]} initialAttributes\n * @param {boolean} buildSelector\n * @return {string|string[]|{buildSelector: (function(string|string[]): string),\n *   buildList: (function(string|string[]): string[]),\n *   hasAttribute: (function(JQLite|Element, string): HTMLElement),\n *   removeAttribute: (function(JQLite|Element, string): void)}}\n * @constructor\n */\nfunction MdPrefixer(initialAttributes, buildSelector) {\n  var PREFIXES = ['data', 'x'];\n\n  if (initialAttributes) {\n    // The prefixer also accepts attributes as a parameter, and immediately builds a list or selector for\n    // the specified attributes.\n    return buildSelector ? _buildSelector(initialAttributes) : _buildList(initialAttributes);\n  }\n\n  return {\n    buildList: _buildList,\n    buildSelector: _buildSelector,\n    hasAttribute: _hasAttribute,\n    removeAttribute: _removeAttribute\n  };\n\n  function _buildList(attributes) {\n    attributes = angular.isArray(attributes) ? attributes : [attributes];\n\n    attributes.forEach(function(item) {\n      PREFIXES.forEach(function(prefix) {\n        attributes.push(prefix + '-' + item);\n      });\n    });\n\n    return attributes;\n  }\n\n  function _buildSelector(attributes) {\n    attributes = angular.isArray(attributes) ? attributes : [attributes];\n\n    return _buildList(attributes)\n      .map(function(item) {\n        return '[' + item + ']';\n      })\n      .join(',');\n  }\n\n  function _hasAttribute(element, attribute) {\n    element = _getNativeElement(element);\n\n    if (!element) {\n      return false;\n    }\n\n    var prefixedAttrs = _buildList(attribute);\n\n    for (var i = 0; i < prefixedAttrs.length; i++) {\n      if (element.hasAttribute(prefixedAttrs[i])) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  function _removeAttribute(element, attribute) {\n    element = _getNativeElement(element);\n\n    if (!element) {\n      return;\n    }\n\n    _buildList(attribute).forEach(function(prefixedAttribute) {\n      element.removeAttribute(prefixedAttribute);\n    });\n  }\n\n  /**\n   * Transforms a jqLite or DOM element into a HTML element.\n   * This is useful when supporting jqLite elements and DOM elements at\n   * same time.\n   * @param element {JQLite|Element} Element to be parsed\n   * @returns {HTMLElement} Parsed HTMLElement\n   */\n  function _getNativeElement(element) {\n    element =  element[0] || element;\n\n    if (element.nodeType) {\n      return element;\n    }\n  }\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/*\n * This var has to be outside the angular factory, otherwise when\n * there are multiple material apps on the same page, each app\n * will create its own instance of this array and the app's IDs\n * will not be unique.\n */\nUtilFactory.$inject = [\"$document\", \"$timeout\", \"$compile\", \"$rootScope\", \"$$mdAnimate\", \"$interpolate\", \"$log\", \"$rootElement\", \"$window\", \"$$rAF\"];\nvar nextUniqueId = 0, isIos, isAndroid, isFirefox;\n\n// Support material-tools builds.\nif (window.navigator) {\n  var userAgent = window.navigator.userAgent || window.navigator.vendor || window.opera;\n  isIos = userAgent.match(/ipad|iphone|ipod/i);\n  isAndroid = userAgent.match(/android/i);\n  isFirefox = userAgent.match(/(firefox|minefield)/i);\n}\n\n/**\n * @ngdoc module\n * @name material.core.util\n * @description\n * Util\n */\nangular\n.module('material.core')\n.factory('$mdUtil', UtilFactory);\n\n/**\n * @ngInject\n */\nfunction UtilFactory($document, $timeout, $compile, $rootScope, $$mdAnimate, $interpolate, $log,\n                     $rootElement, $window, $$rAF) {\n  // Setup some core variables for the processTemplate method\n  var startSymbol = $interpolate.startSymbol(),\n    endSymbol = $interpolate.endSymbol(),\n    usesStandardSymbols = ((startSymbol === '{{') && (endSymbol === '}}'));\n\n  // Polyfill document.contains for IE11.\n  document.contains || (document.contains = function (node) {\n    return document.body.contains(node);\n  });\n\n  /**\n   * Checks if the target element has the requested style by key\n   * @param {DOMElement|JQLite} target Target element\n   * @param {string} key Style key\n   * @param {string=} expectedVal Optional expected value\n   * @returns {boolean} Whether the target element has the style or not\n   */\n  var hasComputedStyle = function (target, key, expectedVal) {\n    var hasValue = false;\n\n    if (target && target.length) {\n      var computedStyles = $window.getComputedStyle(target[0]);\n      hasValue = angular.isDefined(computedStyles[key]) &&\n        (expectedVal ? computedStyles[key] == expectedVal : true);\n    }\n\n    return hasValue;\n  };\n\n  function validateCssValue(value) {\n    return !value ? '0' :\n      hasPx(value) || hasPercent(value) ? value : value + 'px';\n  }\n\n  function hasPx(value) {\n    return String(value).indexOf('px') > -1;\n  }\n\n  function hasPercent(value) {\n    return String(value).indexOf('%') > -1;\n  }\n\n  var $mdUtil = {\n    dom: {},\n    isIos: isIos,\n    isAndroid: isAndroid,\n    now: window.performance && window.performance.now ?\n      angular.bind(window.performance, window.performance.now) : Date.now || function() {\n      return new Date().getTime();\n    },\n\n    /**\n     * Cross-version compatibility method to retrieve an option of a ngModel controller,\n     * which supports the breaking changes in the AngularJS snapshot (SHA 87a2ff76af5d0a9268d8eb84db5755077d27c84c).\n     * @param {!ngModel.NgModelController} ngModelCtrl\n     * @param {!string} optionName\n     * @returns {string|number|boolean|Object|undefined}\n     */\n    getModelOption: function (ngModelCtrl, optionName) {\n      if (!ngModelCtrl.$options) {\n        return;\n      }\n\n      var $options = ngModelCtrl.$options;\n\n      // The newer versions of AngularJS introduced a getOption function and made the option values\n      // no longer visible on the $options object.\n      return $options.getOption ? $options.getOption(optionName) : $options[optionName];\n    },\n\n    /**\n     * Determines the current 'dir'ectional value based on the value of 'dir'\n     * attribute of the element. If that is not defined, it will try to use\n     * a 'dir' attribute of the body or html tag.\n     *\n     * @param {Object=} attrs a hash object with key-value pairs of normalized\n     *     attribute names and their corresponding attribute values.\n     * @returns {boolean} true if the element's passed in attributes,\n     *     the document, or the body indicates RTL mode, false otherwise.\n     */\n    isRtl: function(attrs) {\n      var dir = angular.isDefined(attrs) && attrs.hasOwnProperty('dir') && attrs.dir;\n\n      switch (dir) {\n        case 'ltr':\n          return false;\n\n        case 'rtl':\n          return true;\n      }\n\n      return ($document[0].dir === 'rtl' || $document[0].body.dir === 'rtl');\n    },\n\n    /**\n     * Bi-directional accessor/mutator used to easily update an element's\n     * property based on the current 'dir'ectional value.\n     */\n    bidi: function(element, property, lValue, rValue) {\n      var ltr = !this.isRtl();\n\n      // If accessor\n      if (arguments.length == 0) return ltr ? 'ltr' : 'rtl';\n\n      // If mutator\n      var elem = angular.element(element);\n\n      if (ltr && angular.isDefined(lValue)) {\n        elem.css(property, validateCssValue(lValue));\n      }\n      else if (!ltr && angular.isDefined(rValue)) {\n        elem.css(property, validateCssValue(rValue));\n      }\n    },\n\n    bidiProperty: function (element, lProperty, rProperty, value) {\n      var ltr = !this.isRtl();\n\n      var elem = angular.element(element);\n\n      if (ltr && angular.isDefined(lProperty)) {\n        elem.css(lProperty, validateCssValue(value));\n        elem.css(rProperty, '');\n      }\n      else if (!ltr && angular.isDefined(rProperty)) {\n        elem.css(rProperty, validateCssValue(value));\n        elem.css(lProperty, '');\n      }\n    },\n\n    clientRect: function(element, offsetParent, isOffsetRect) {\n      var node = getNode(element);\n      offsetParent = getNode(offsetParent || node.offsetParent || document.body);\n      var nodeRect = node.getBoundingClientRect();\n\n      // The user can ask for an offsetRect: a rect relative to the offsetParent,\n      // or a clientRect: a rect relative to the page\n      var offsetRect = isOffsetRect ?\n        offsetParent.getBoundingClientRect() :\n        {left: 0, top: 0, width: 0, height: 0};\n      return {\n        left: nodeRect.left - offsetRect.left,\n        top: nodeRect.top - offsetRect.top,\n        width: nodeRect.width,\n        height: nodeRect.height\n      };\n    },\n    offsetRect: function(element, offsetParent) {\n      return $mdUtil.clientRect(element, offsetParent, true);\n    },\n\n    /**\n     * Annoying method to copy nodes to an array, thanks to IE.\n     * @param nodes\n     * @return {Array}\n     */\n    nodesToArray: function(nodes) {\n      var results = [], i;\n      nodes = nodes || [];\n\n      for (i = 0; i < nodes.length; ++i) {\n        results.push(nodes.item(i));\n      }\n      return results;\n    },\n\n    /**\n     * Determines the absolute position of the viewport.\n     * Useful when making client rectangles absolute.\n     * @returns {number}\n     */\n    getViewportTop: function() {\n      // If body scrolling is disabled, then use the cached viewport top value, otherwise get it\n      // fresh from the $window.\n      if ($mdUtil.disableScrollAround._count && $mdUtil.disableScrollAround._viewPortTop) {\n        return $mdUtil.disableScrollAround._viewPortTop;\n      } else {\n        return $window.scrollY || $window.pageYOffset || 0;\n      }\n    },\n\n    /**\n     * Finds the proper focus target by searching the DOM.\n     *\n     * @param {!JQLite} containerEl\n     * @param {string=} attributeVal\n     * @returns {JQLite|undefined}\n     */\n    findFocusTarget: function(containerEl, attributeVal) {\n      var AUTO_FOCUS = this.prefixer('md-autofocus', true);\n      var elToFocus;\n\n      elToFocus = scanForFocusable(containerEl, attributeVal || AUTO_FOCUS);\n\n      // Scan for fallback to 'universal' API\n      if (!elToFocus) {\n        elToFocus = scanForFocusable(containerEl, AUTO_FOCUS);\n      }\n\n      return elToFocus;\n\n      /**\n       * Can target and nested children for specified Selector (attribute)\n       * whose value may be an expression that evaluates to True/False.\n       * @param {!JQLite} target\n       * @param {!string} selector\n       * @return {JQLite|undefined}\n       */\n      function scanForFocusable(target, selector) {\n        var elFound, items = target[0].querySelectorAll(selector);\n\n        // Find the last child element with the focus attribute\n        if (items && items.length) {\n          items.length && angular.forEach(items, function(it) {\n            it = angular.element(it);\n\n            // Check the element for the md-autofocus class to ensure any associated expression\n            // evaluated to true.\n            var isFocusable = it.hasClass('md-autofocus');\n            if (isFocusable) elFound = it;\n          });\n        }\n        return elFound;\n      }\n    },\n\n    /**\n     * Disables scroll around the passed parent element.\n     * @param {Element|JQLite=} element Origin Element (not used)\n     * @param {Element|JQLite=} parent Element to disable scrolling within.\n     *   Defaults to body if none supplied.\n     * @param {Object=} options Object of options to modify functionality\n     *   - disableScrollMask Boolean of whether or not to create a scroll mask element or\n     *     use the passed parent element.\n     */\n    disableScrollAround: function(element, parent, options) {\n      options = options || {};\n\n      $mdUtil.disableScrollAround._count = Math.max(0, $mdUtil.disableScrollAround._count || 0);\n      $mdUtil.disableScrollAround._count++;\n\n      if ($mdUtil.disableScrollAround._restoreScroll) {\n        return $mdUtil.disableScrollAround._restoreScroll;\n      }\n\n      var body = $document[0].body;\n      var restoreBody = disableBodyScroll();\n      var restoreElement = disableElementScroll(parent, options);\n\n      return $mdUtil.disableScrollAround._restoreScroll = function() {\n        if (--$mdUtil.disableScrollAround._count <= 0) {\n          delete $mdUtil.disableScrollAround._viewPortTop;\n          restoreBody();\n          restoreElement();\n          delete $mdUtil.disableScrollAround._restoreScroll;\n        }\n      };\n\n      /**\n       * Creates a virtual scrolling mask to prevent touchmove, keyboard, scrollbar clicking,\n       * and wheel events.\n       * @param {!Element|!JQLite} elementToDisable\n       * @param {Object=} scrollMaskOptions Object of options to modify functionality\n       *   - disableScrollMask Boolean of whether or not to create a scroll mask element or\n       *     use the passed parent element.\n       * @returns {Function}\n       */\n      function disableElementScroll(elementToDisable, scrollMaskOptions) {\n        var scrollMask;\n        var wrappedElementToDisable = angular.element(elementToDisable || body);\n\n        if (scrollMaskOptions.disableScrollMask) {\n          scrollMask = wrappedElementToDisable;\n        } else {\n          scrollMask = angular.element(\n            '<div class=\"md-scroll-mask\">' +\n            '  <div class=\"md-scroll-mask-bar\"></div>' +\n            '</div>');\n          wrappedElementToDisable.append(scrollMask);\n        }\n\n        /**\n         * @param {Event} $event\n         */\n        function preventDefault($event) {\n          $event.preventDefault();\n        }\n\n        scrollMask.on('wheel touchmove', preventDefault);\n\n        return function restoreElementScroll() {\n          scrollMask.off('wheel touchmove', preventDefault);\n\n          if (!scrollMaskOptions.disableScrollMask && scrollMask[0].parentNode) {\n            scrollMask[0].parentNode.removeChild(scrollMask[0]);\n          }\n        };\n      }\n\n      // Converts the body to a position fixed block and translate it to the proper scroll position\n      function disableBodyScroll() {\n        var documentElement = $document[0].documentElement;\n\n        var prevDocumentStyle = documentElement.style.cssText || '';\n        var prevBodyStyle = body.style.cssText || '';\n\n        var viewportTop = $mdUtil.getViewportTop();\n        $mdUtil.disableScrollAround._viewPortTop = viewportTop;\n        var clientWidth = body.clientWidth;\n        var hasVerticalScrollbar = body.scrollHeight > body.clientHeight + 1;\n\n        // Scroll may be set on <html> element (for example by overflow-y: scroll)\n        // but Chrome is reporting the scrollTop position always on <body>.\n        // scrollElement will allow to restore the scrollTop position to proper target.\n        var scrollElement = documentElement.scrollTop > 0 ? documentElement : body;\n\n        if (hasVerticalScrollbar) {\n          angular.element(body).css({\n            position: 'fixed',\n            width: '100%',\n            top: -viewportTop + 'px'\n          });\n        }\n\n        if (body.clientWidth < clientWidth) {\n          body.style.overflow = 'hidden';\n        }\n\n        return function restoreScroll() {\n          // Reset the inline style CSS to the previous.\n          body.style.cssText = prevBodyStyle;\n          documentElement.style.cssText = prevDocumentStyle;\n\n          // The scroll position while being fixed\n          scrollElement.scrollTop = viewportTop;\n        };\n      }\n\n    },\n\n    enableScrolling: function() {\n      var restoreFn = this.disableScrollAround._restoreScroll;\n      restoreFn && restoreFn();\n    },\n\n    floatingScrollbars: function() {\n      if (this.floatingScrollbars.cached === undefined) {\n        var tempNode = angular.element('<div><div></div></div>').css({\n          width: '100%',\n          'z-index': -1,\n          position: 'absolute',\n          height: '35px',\n          'overflow-y': 'scroll'\n        });\n        tempNode.children().css('height', '60px');\n\n        $document[0].body.appendChild(tempNode[0]);\n        this.floatingScrollbars.cached =\n          (tempNode[0].offsetWidth === tempNode[0].childNodes[0].offsetWidth);\n        tempNode.remove();\n      }\n      return this.floatingScrollbars.cached;\n    },\n\n    /**\n     * Mobile safari only allows you to set focus in click event listeners.\n     * @param {Element|JQLite} element to focus\n     */\n    forceFocus: function(element) {\n      var node = element[0] || element;\n\n      document.addEventListener('click', function focusOnClick(ev) {\n        if (ev.target === node && ev.$focus) {\n          node.focus();\n          ev.stopImmediatePropagation();\n          ev.preventDefault();\n          node.removeEventListener('click', focusOnClick);\n        }\n      }, true);\n\n      var newEvent = document.createEvent('MouseEvents');\n      newEvent.initMouseEvent('click', false, true, window, {}, 0, 0, 0, 0,\n        false, false, false, false, 0, null);\n      newEvent.$material = true;\n      newEvent.$focus = true;\n      node.dispatchEvent(newEvent);\n    },\n\n    /**\n     * facade to build md-backdrop element with desired styles\n     * NOTE: Use $compile to trigger backdrop postLink function\n     */\n    createBackdrop: function(scope, addClass) {\n      return $compile($mdUtil.supplant('<md-backdrop class=\"{0}\">', [addClass]))(scope);\n    },\n\n    /**\n     * supplant() method from Crockford's `Remedial Javascript`\n     * Equivalent to use of $interpolate; without dependency on\n     * interpolation symbols and scope. Note: the '{<token>}' can\n     * be property names, property chains, or array indices.\n     */\n    supplant: function(template, values, pattern) {\n      pattern = pattern || /\\{([^{}]*)\\}/g;\n      return template.replace(pattern, function(a, b) {\n        var p = b.split('.'),\n          r = values;\n        try {\n          for (var s in p) {\n            if (p.hasOwnProperty(s)) {\n              r = r[p[s]];\n            }\n          }\n        } catch (e) {\n          r = a;\n        }\n        return (typeof r === 'string' || typeof r === 'number') ? r : a;\n      });\n    },\n\n    fakeNgModel: function() {\n      return {\n        $fake: true,\n        $setTouched: angular.noop,\n        $setViewValue: function(value) {\n          this.$viewValue = value;\n          this.$render(value);\n          this.$viewChangeListeners.forEach(function(cb) {\n            cb();\n          });\n        },\n        $isEmpty: function(value) {\n          return ('' + value).length === 0;\n        },\n        $parsers: [],\n        $formatters: [],\n        $viewChangeListeners: [],\n        $render: angular.noop\n      };\n    },\n\n    /**\n     * @param {Function} func original function to be debounced\n     * @param {number} wait number of milliseconds to delay (since last debounce reset).\n     *  Default value 10 msecs.\n     * @param {Object} scope in which to apply the function after debouncing ends\n     * @param {boolean} invokeApply should the $timeout trigger $digest() dirty checking\n     * @return {Function} A function, that, as long as it continues to be invoked, will not be\n     *  triggered. The function will be called after it stops being called for N milliseconds.\n     */\n    debounce: function(func, wait, scope, invokeApply) {\n      var timer;\n\n      return function debounced() {\n        var context = scope,\n            args = Array.prototype.slice.call(arguments);\n\n        $timeout.cancel(timer);\n        timer = $timeout(function() {\n\n          timer = undefined;\n          func.apply(context, args);\n\n        }, wait || 10, invokeApply);\n      };\n    },\n\n    /**\n     * The function will not be called unless it has been more than `delay` milliseconds since the\n     * last call.\n     * @param {Function} func original function to throttle\n     * @param {number} delay number of milliseconds to delay\n     * @return {Function} a function that can only be triggered every `delay` milliseconds.\n     */\n    throttle: function throttle(func, delay) {\n      var recent;\n      return function throttled() {\n        var context = this;\n        var args = arguments;\n        var now = $mdUtil.now();\n\n        if (!recent || (now - recent > delay)) {\n          func.apply(context, args);\n          recent = now;\n        }\n      };\n    },\n\n    /**\n     * Measures the number of milliseconds taken to run the provided callback\n     * function. Uses a high-precision timer if available.\n     */\n    time: function time(cb) {\n      var start = $mdUtil.now();\n      cb();\n      return $mdUtil.now() - start;\n    },\n\n    /**\n     * Create an implicit getter that caches its `getter()`\n     * lookup value\n     */\n    valueOnUse : function (scope, key, getter) {\n      var value = null, args = Array.prototype.slice.call(arguments);\n      var params = (args.length > 3) ? args.slice(3) : [];\n\n      Object.defineProperty(scope, key, {\n        get: function () {\n          if (value === null) value = getter.apply(scope, params);\n          return value;\n        }\n      });\n    },\n\n    /**\n     * Get a unique ID.\n     *\n     * @returns {string} an unique numeric string\n     */\n    nextUid: function() {\n      return '' + nextUniqueId++;\n    },\n\n    /**\n     * Stop watchers and events from firing on a scope without destroying it,\n     * by disconnecting it from its parent and its siblings' linked lists.\n     * @param {Object} scope to disconnect\n     */\n    disconnectScope: function disconnectScope(scope) {\n      if (!scope) return;\n\n      // we can't destroy the root scope or a scope that has been already destroyed\n      if (scope.$root === scope) return;\n      if (scope.$$destroyed) return;\n\n      var parent = scope.$parent;\n      scope.$$disconnected = true;\n\n      // See Scope.$destroy\n      if (parent.$$childHead === scope) parent.$$childHead = scope.$$nextSibling;\n      if (parent.$$childTail === scope) parent.$$childTail = scope.$$prevSibling;\n      if (scope.$$prevSibling) scope.$$prevSibling.$$nextSibling = scope.$$nextSibling;\n      if (scope.$$nextSibling) scope.$$nextSibling.$$prevSibling = scope.$$prevSibling;\n\n      scope.$$nextSibling = scope.$$prevSibling = null;\n\n    },\n\n    /**\n     * Undo the effects of disconnectScope().\n     * @param {Object} scope to reconnect\n     */\n    reconnectScope: function reconnectScope(scope) {\n      if (!scope) return;\n\n      // we can't disconnect the root node or scope already disconnected\n      if (scope.$root === scope) return;\n      if (!scope.$$disconnected) return;\n\n      var child = scope;\n\n      var parent = child.$parent;\n      child.$$disconnected = false;\n      // See Scope.$new for this logic...\n      child.$$prevSibling = parent.$$childTail;\n      if (parent.$$childHead) {\n        parent.$$childTail.$$nextSibling = child;\n        parent.$$childTail = child;\n      } else {\n        parent.$$childHead = parent.$$childTail = child;\n      }\n    },\n\n    /**\n     * Get an element's siblings matching a given tag name.\n     *\n     * @param {JQLite|angular.element|HTMLElement} element Element to start walking the DOM from\n     * @param {string} tagName HTML tag name to match against\n     * @returns {Object[]} JQLite\n     */\n    getSiblings: function getSiblings(element, tagName) {\n      var upperCasedTagName = tagName.toUpperCase();\n      if (element instanceof angular.element) {\n        element = element[0];\n      }\n      var siblings = Array.prototype.filter.call(element.parentNode.children, function(node) {\n        return element !== node && node.tagName.toUpperCase() === upperCasedTagName;\n      });\n      return siblings.map(function (sibling) {\n        return angular.element(sibling);\n      });\n    },\n\n    /**\n     * getClosest replicates jQuery.closest() to walk up the DOM tree until it finds a matching\n     * nodeName.\n     *\n     * @param {Node} el Element to start walking the DOM from\n     * @param {string|function} validateWith If a string is passed, it will be evaluated against\n     * each of the parent nodes' tag name. If a function is passed, the loop will call it with each\n     * of the parents and will use the return value to determine whether the node is a match.\n     * @param {boolean=} onlyParent Only start checking from the parent element, not `el`.\n     * @returns {Node|null} closest matching parent Node or null if not found\n     */\n    getClosest: function getClosest(el, validateWith, onlyParent) {\n      if (angular.isString(validateWith)) {\n        var tagName = validateWith.toUpperCase();\n        validateWith = function(el) {\n          return el.nodeName.toUpperCase() === tagName;\n        };\n      }\n\n      if (el instanceof angular.element) el = el[0];\n      if (onlyParent) el = el.parentNode;\n      if (!el) return null;\n\n      do {\n        if (validateWith(el)) {\n          return el;\n        }\n      } while (el = el.parentNode);\n\n      return null;\n    },\n\n    /**\n     * Build polyfill for the Node.contains feature (if needed)\n     * @param {Node} node\n     * @param {Node} child\n     * @returns {Node}\n     */\n    elementContains: function(node, child) {\n      var hasContains = (window.Node && window.Node.prototype && Node.prototype.contains);\n      var findFn = hasContains ? angular.bind(node, node.contains) : angular.bind(node, function(arg) {\n        // compares the positions of two nodes and returns a bitmask\n        return (node === child) || !!(this.compareDocumentPosition(arg) & 16);\n      });\n\n      return findFn(child);\n    },\n\n    /**\n     * Functional equivalent for $element.filter(‘md-bottom-sheet’)\n     * useful with interimElements where the element and its container are important...\n     *\n     * @param {JQLite} element to scan\n     * @param {string} nodeName of node to find (e.g. 'md-dialog')\n     * @param {boolean=} scanDeep optional flag to allow deep scans; defaults to 'false'.\n     * @param {boolean=} warnNotFound optional flag to enable log warnings; defaults to false\n     */\n    extractElementByName: function(element, nodeName, scanDeep, warnNotFound) {\n      var found = scanTree(element);\n      if (!found && !!warnNotFound) {\n        $log.warn($mdUtil.supplant(\"Unable to find node '{0}' in element '{1}'.\",[nodeName, element[0].outerHTML]));\n      }\n\n      return angular.element(found || element);\n\n      /**\n       * Breadth-First tree scan for element with matching `nodeName`\n       */\n      function scanTree(element) {\n        return scanLevel(element) || (scanDeep ? scanChildren(element) : null);\n      }\n\n      /**\n       * Case-insensitive scan of current elements only (do not descend).\n       */\n      function scanLevel(element) {\n        if (element) {\n          for (var i = 0, len = element.length; i < len; i++) {\n            if (element[i].nodeName.toLowerCase() === nodeName) {\n              return element[i];\n            }\n          }\n        }\n        return null;\n      }\n\n      /**\n       * Scan children of specified node\n       */\n      function scanChildren(element) {\n        var found;\n        if (element) {\n          for (var i = 0, len = element.length; i < len; i++) {\n            var target = element[i];\n            if (!found) {\n              for (var j = 0, numChild = target.childNodes.length; j < numChild; j++) {\n                found = found || scanTree([target.childNodes[j]]);\n              }\n            }\n          }\n        }\n        return found;\n      }\n\n    },\n\n    /**\n     * Give optional properties with no value a boolean true if attr provided or false otherwise\n     */\n    initOptionalProperties: function(scope, attr, defaults) {\n      defaults = defaults || {};\n      angular.forEach(scope.$$isolateBindings, function(binding, key) {\n        if (binding.optional && angular.isUndefined(scope[key])) {\n          var attrIsDefined = angular.isDefined(attr[binding.attrName]);\n          scope[key] = angular.isDefined(defaults[key]) ? defaults[key] : attrIsDefined;\n        }\n      });\n    },\n\n    /**\n     * Alternative to $timeout calls with 0 delay.\n     * nextTick() coalesces all calls within a single frame\n     * to minimize $digest thrashing\n     *\n     * @param {Function} callback function to be called after the tick\n     * @param {boolean=} digest true to call $rootScope.$digest() after callback\n     * @param {Object=} scope associated with callback. If the scope is destroyed, the callback will\n     *  be skipped.\n     * @returns {*}\n     */\n    nextTick: function(callback, digest, scope) {\n      // grab function reference for storing state details\n      var nextTick = $mdUtil.nextTick;\n      var timeout = nextTick.timeout;\n      var queue = nextTick.queue || [];\n\n      // add callback to the queue\n      queue.push({scope: scope, callback: callback});\n\n      // set default value for digest\n      if (digest == null) digest = true;\n\n      // store updated digest/queue values\n      nextTick.digest = nextTick.digest || digest;\n      nextTick.queue = queue;\n\n      // either return existing timeout or create a new one\n      return timeout || (nextTick.timeout = $timeout(processQueue, 0, false));\n\n      /**\n       * Grab a copy of the current queue\n       * Clear the queue for future use\n       * Process the existing queue\n       * Trigger digest if necessary\n       */\n      function processQueue() {\n        var queue = nextTick.queue;\n        var digest = nextTick.digest;\n\n        nextTick.queue = [];\n        nextTick.timeout = null;\n        nextTick.digest = false;\n\n        queue.forEach(function(queueItem) {\n          var skip = queueItem.scope && queueItem.scope.$$destroyed;\n          if (!skip) {\n            queueItem.callback();\n          }\n        });\n\n        if (digest) $rootScope.$digest();\n      }\n    },\n\n    /**\n     * Processes a template and replaces the start/end symbols if the application has\n     * overridden them.\n     *\n     * @param template The template to process whose start/end tags may be replaced.\n     * @returns {*}\n     */\n    processTemplate: function(template) {\n      if (usesStandardSymbols) {\n        return template;\n      } else {\n        if (!template || !angular.isString(template)) return template;\n        return template.replace(/\\{\\{/g, startSymbol).replace(/}}/g, endSymbol);\n      }\n    },\n\n    /**\n     * Scan up dom hierarchy for enabled parent;\n     */\n    getParentWithPointerEvents: function (element) {\n      var parent = element.parent();\n\n      // jqLite might return a non-null, but still empty, parent; so check for parent and length\n      while (hasComputedStyle(parent, 'pointer-events', 'none')) {\n        parent = parent.parent();\n      }\n\n      return parent;\n    },\n\n    getNearestContentElement: function (element) {\n      var current = element.parent()[0];\n      // Look for the nearest parent md-content, stopping at the rootElement.\n      while (current && current !== $rootElement[0] && current !== document.body && current.nodeName.toUpperCase() !== 'MD-CONTENT') {\n        current = current.parentNode;\n      }\n      return current;\n    },\n\n    /**\n     * Checks if the current browser is natively supporting the `sticky` position.\n     * @returns {string} supported sticky property name\n     */\n    checkStickySupport: function() {\n      var stickyProp;\n      var testEl = angular.element('<div>');\n      $document[0].body.appendChild(testEl[0]);\n\n      var stickyProps = ['sticky', '-webkit-sticky'];\n      for (var i = 0; i < stickyProps.length; ++i) {\n        testEl.css({\n          position: stickyProps[i],\n          top: 0,\n          'z-index': 2\n        });\n\n        if (testEl.css('position') == stickyProps[i]) {\n          stickyProp = stickyProps[i];\n          break;\n        }\n      }\n\n      testEl.remove();\n\n      return stickyProp;\n    },\n\n    /**\n     * Parses an attribute value, mostly a string.\n     * By default checks for negated values and returns `false´ if present.\n     * Negated values are: (native falsy) and negative strings like:\n     * `false` or `0`.\n     * @param value Attribute value which should be parsed.\n     * @param negatedCheck When set to false, won't check for negated values.\n     * @returns {boolean}\n     */\n    parseAttributeBoolean: function(value, negatedCheck) {\n      return value === '' || !!value && (negatedCheck === false || value !== 'false' && value !== '0');\n    },\n\n    hasComputedStyle: hasComputedStyle,\n\n    /**\n     * Returns true if the parent form of the element has been submitted.\n     * @param element An AngularJS or HTML5 element.\n     * @returns {boolean}\n     */\n    isParentFormSubmitted: function(element) {\n      var parent = $mdUtil.getClosest(element, 'form');\n      var form = parent ? angular.element(parent).controller('form') : null;\n\n      return form ? form.$submitted : false;\n    },\n\n    /**\n     * Animate the requested element's scrollTop to the requested scrollPosition with basic easing.\n     * @param {!Element} element The element to scroll.\n     * @param {number} scrollEnd The new/final scroll position.\n     * @param {number=} duration Duration of the scroll. Default is 1000ms.\n     */\n    animateScrollTo: function(element, scrollEnd, duration) {\n      var scrollStart = element.scrollTop;\n      var scrollChange = scrollEnd - scrollStart;\n      var scrollingDown = scrollStart < scrollEnd;\n      var startTime = $mdUtil.now();\n\n      $$rAF(scrollChunk);\n\n      function scrollChunk() {\n        var newPosition = calculateNewPosition();\n\n        element.scrollTop = newPosition;\n\n        if (scrollingDown ? newPosition < scrollEnd : newPosition > scrollEnd) {\n          $$rAF(scrollChunk);\n        }\n      }\n\n      function calculateNewPosition() {\n        var easeDuration = duration || 1000;\n        var currentTime = $mdUtil.now() - startTime;\n\n        return ease(currentTime, scrollStart, scrollChange, easeDuration);\n      }\n\n      function ease(currentTime, start, change, duration) {\n        // If the duration has passed (which can occur if our app loses focus due to $$rAF), jump\n        // straight to the proper position\n        if (currentTime > duration) {\n          return start + change;\n        }\n\n        var ts = (currentTime /= duration) * currentTime;\n        var tc = ts * currentTime;\n\n        return start + change * (-2 * tc + 3 * ts);\n      }\n    },\n\n    /**\n     * Provides an easy mechanism for removing duplicates from an array.\n     *\n     *    var myArray = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];\n     *\n     *    $mdUtil.uniq(myArray) => [1, 2, 3, 4]\n     *\n     * @param {Array} array The array whose unique values should be returned.\n     * @returns {Array|void} A copy of the array containing only unique values.\n     */\n    uniq: function(array) {\n      if (!array) { return; }\n\n      return array.filter(function(value, index, self) {\n        return self.indexOf(value) === index;\n      });\n    },\n\n    /**\n     * Gets the inner HTML content of the given HTMLElement.\n     * Only intended for use with SVG or Symbol elements in IE11.\n     * @param {Element} element\n     * @returns {string} the inner HTML of the element passed in\n     */\n    getInnerHTML: function(element) {\n      // For SVG or Symbol elements, innerHTML returns `undefined` in IE.\n      // Reference: https://stackoverflow.com/q/28129956/633107\n      // The XMLSerializer API is supported on IE11 and is the recommended workaround.\n      var serializer = new XMLSerializer();\n\n      return Array.prototype.map.call(element.childNodes, function (child) {\n        return serializer.serializeToString(child);\n      }).join('');\n    },\n\n    /**\n     * Gets the outer HTML content of the given HTMLElement.\n     * Only intended for use with SVG or Symbol elements in IE11.\n     * @param {Element} element\n     * @returns {string} the outer HTML of the element passed in\n     */\n    getOuterHTML: function(element) {\n      // For SVG or Symbol elements, outerHTML returns `undefined` in IE.\n      // Reference: https://stackoverflow.com/q/29888050/633107\n      // The XMLSerializer API is supported on IE11 and is the recommended workaround.\n      var serializer = new XMLSerializer();\n      return serializer.serializeToString(element);\n    },\n\n    /**\n     * Support: IE 9-11 only\n     * documentMode is an IE-only property\n     * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx\n     */\n    msie: window.document.documentMode,\n\n    getTouchAction: function() {\n      var testEl = document.createElement('div');\n      var vendorPrefixes = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];\n\n      for (var i = 0; i < vendorPrefixes.length; i++) {\n        var prefix = vendorPrefixes[i];\n        var property = prefix ? prefix + 'TouchAction' : 'touchAction';\n        if (angular.isDefined(testEl.style[property])) {\n          return property;\n        }\n      }\n    },\n\n    /**\n     * @param {Event} event the event to calculate the bubble path for\n     * @return {EventTarget[]} the set of nodes that this event could bubble up to\n     */\n    getEventPath: function(event) {\n      var path = [];\n      var currentTarget = event.target;\n      while (currentTarget) {\n        path.push(currentTarget);\n        currentTarget = currentTarget.parentElement;\n      }\n      if (path.indexOf(window) === -1 && path.indexOf(document) === -1)\n        path.push(document);\n      if (path.indexOf(window) === -1)\n        path.push(window);\n      return path;\n    },\n\n    /**\n     * Gets the string the user has entered and removes Regex identifiers\n     * @param {string} term\n     * @returns {string} sanitized string\n     */\n    sanitize: function(term) {\n      if (!term) return term;\n      return term.replace(/[\\\\^$*+?.()|{}[]/g, '\\\\$&');\n    },\n\n    /**********************************************************************************************\n     * The following functions were sourced from\n     * https://github.com/angular/components/blob/3c37e4b1c1cb74a3d0a90d173240fc730d21d9d4/src/cdk/a11y/interactivity-checker/interactivity-checker.ts\n     **********************************************************************************************/\n\n    /**\n     * Gets whether an element is disabled.\n     * @param {HTMLElement} element Element to be checked.\n     * @returns {boolean} Whether the element is disabled.\n     */\n    isDisabled: function(element) {\n      // This does not capture some cases, such as a non-form control with a disabled attribute or\n      // a form control inside of a disabled form, but should capture the most common cases.\n      return element.hasAttribute('disabled');\n    },\n\n    /**\n     * Gets whether an element is visible for the purposes of interactivity.\n     *\n     * This will capture states like `display: none` and `visibility: hidden`, but not things like\n     * being clipped by an `overflow: hidden` parent or being outside the viewport.\n     *\n     * @param {HTMLElement} element\n     * @returns {boolean} Whether the element is visible.\n     */\n    isVisible: function(element) {\n      return $mdUtil.hasGeometry(element) && getComputedStyle(element).visibility === 'visible';\n    },\n\n    /**\n     * Gets whether an element can be reached via Tab key.\n     * Assumes that the element has already been checked with isFocusable.\n     * @param {HTMLElement} element Element to be checked.\n     * @returns {boolean} Whether the element is tabbable.\n     */\n    isTabbable: function(element) {\n      var frameElement = $mdUtil.getFrameElement($mdUtil.getWindow(element));\n\n      if (frameElement) {\n        // Frame elements inherit their tabindex onto all child elements.\n        if ($mdUtil.getTabIndexValue(frameElement) === -1) {\n          return false;\n        }\n\n        // Browsers disable tabbing to an element inside of an invisible frame.\n        if (!$mdUtil.isVisible(frameElement)) {\n          return false;\n        }\n      }\n\n      var nodeName = element.nodeName.toLowerCase();\n      var tabIndexValue = $mdUtil.getTabIndexValue(element);\n\n      if (element.hasAttribute('contenteditable')) {\n        return tabIndexValue !== -1;\n      }\n\n      if (nodeName === 'iframe' || nodeName === 'object') {\n        // The frame or object's content may be tabbable depending on the content, but it's\n        // not possibly to reliably detect the content of the frames. We always consider such\n        // elements as non-tabbable.\n        return false;\n      }\n\n      // In iOS, the browser only considers some specific elements as tabbable.\n      if (isIos && !$mdUtil.isPotentiallyTabbableIOS(element)) {\n        return false;\n      }\n\n      if (nodeName === 'audio') {\n        // Audio elements without controls enabled are never tabbable, regardless\n        // of the tabindex attribute explicitly being set.\n        if (!element.hasAttribute('controls')) {\n          return false;\n        }\n        // Audio elements with controls are by default tabbable unless the\n        // tabindex attribute is set to `-1` explicitly.\n        return tabIndexValue !== -1;\n      }\n\n      if (nodeName === 'video') {\n        // For all video elements, if the tabindex attribute is set to `-1`, the video\n        // is not tabbable. Note: We cannot rely on the default `HTMLElement.tabIndex`\n        // property as that one is set to `-1` in Chrome, Edge and Safari v13.1. The\n        // tabindex attribute is the source of truth here.\n        if (tabIndexValue === -1) {\n          return false;\n        }\n        // If the tabindex is explicitly set, and not `-1` (as per check before), the\n        // video element is always tabbable (regardless of whether it has controls or not).\n        if (tabIndexValue !== null) {\n          return true;\n        }\n        // Otherwise (when no explicit tabindex is set), a video is only tabbable if it\n        // has controls enabled. Firefox is special as videos are always tabbable regardless\n        // of whether there are controls or not.\n        return isFirefox || element.hasAttribute('controls');\n      }\n\n      return element.tabIndex >= 0;\n    },\n\n    /**\n     * Gets whether an element can be focused by the user.\n     * @param {HTMLElement} element Element to be checked.\n     * @returns {boolean} Whether the element is focusable.\n     */\n    isFocusable: function(element) {\n      // Perform checks in order of left to most expensive.\n      // Again, naive approach that does not capture many edge cases and browser quirks.\n      return $mdUtil.isPotentiallyFocusable(element) && !$mdUtil.isDisabled(element) &&\n        $mdUtil.isVisible(element);\n    },\n\n    /**\n     * Gets whether an element is potentially focusable without taking current visible/disabled\n     * state into account.\n     * @param {HTMLElement} element\n     * @returns {boolean}\n     */\n    isPotentiallyFocusable: function(element) {\n      // Inputs are potentially focusable *unless* they're type=\"hidden\".\n      if ($mdUtil.isHiddenInput(element)) {\n        return false;\n      }\n\n      return $mdUtil.isNativeFormElement(element) ||\n        $mdUtil.isAnchorWithHref(element) ||\n        element.hasAttribute('contenteditable') ||\n        $mdUtil.hasValidTabIndex(element);\n    },\n\n    /**\n     * Checks whether the specified element is potentially tabbable on iOS.\n     * @param {HTMLElement} element\n     * @returns {boolean}\n     */\n    isPotentiallyTabbableIOS: function(element) {\n      var nodeName = element.nodeName.toLowerCase();\n        var inputType = nodeName === 'input' && element.type;\n\n      return inputType === 'text'\n        || inputType === 'password'\n        || nodeName === 'select'\n        || nodeName === 'textarea';\n    },\n\n    /**\n     * Returns the parsed tabindex from the element attributes instead of returning the\n     * evaluated tabindex from the browsers defaults.\n     * @param {HTMLElement} element\n     * @returns {null|number}\n     */\n    getTabIndexValue: function(element) {\n      if (!$mdUtil.hasValidTabIndex(element)) {\n        return null;\n      }\n\n      // See browser issue in Gecko https://bugzilla.mozilla.org/show_bug.cgi?id=1128054\n      var tabIndex = parseInt(element.getAttribute('tabindex') || '', 10);\n\n      return isNaN(tabIndex) ? -1 : tabIndex;\n    },\n\n    /**\n     * Gets whether an element has a valid tabindex.\n     * @param {HTMLElement} element\n     * @returns {boolean}\n     */\n    hasValidTabIndex: function(element) {\n      if (!element.hasAttribute('tabindex') || element.tabIndex === undefined) {\n        return false;\n      }\n\n      var tabIndex = element.getAttribute('tabindex');\n\n      // IE11 parses tabindex=\"\" as the value \"-32768\"\n      if (tabIndex == '-32768') {\n        return false;\n      }\n\n      return !!(tabIndex && !isNaN(parseInt(tabIndex, 10)));\n    },\n\n    /**\n     * Checks whether the specified element has any geometry / rectangles.\n     * @param {HTMLElement} element\n     * @returns {boolean}\n     */\n    hasGeometry: function(element) {\n      // Use logic from jQuery to check for an invisible element.\n      // See https://github.com/jquery/jquery/blob/8969732518470a7f8e654d5bc5be0b0076cb0b87/src/css/hiddenVisibleSelectors.js#L9\n      return !!(element.offsetWidth || element.offsetHeight ||\n        (typeof element.getClientRects === 'function' && element.getClientRects().length));\n    },\n\n    /**\n     * Returns the frame element from a window object. Since browsers like MS Edge throw errors if\n     * the frameElement property is being accessed from a different host address, this property\n     * should be accessed carefully.\n     * @param {Window} window\n     * @returns {null|HTMLElement}\n     */\n    getFrameElement: function(window) {\n      try {\n        return window.frameElement;\n      } catch (error) {\n        return null;\n      }\n    },\n\n    /**\n     * Gets the parent window of a DOM node with regards of being inside of an iframe.\n     * @param {HTMLElement} node\n     * @returns {Window}\n     */\n    getWindow: function(node) {\n      // ownerDocument is null if `node` itself *is* a document.\n      return node.ownerDocument && node.ownerDocument.defaultView || window;\n    },\n\n    /**\n     * Gets whether an element's\n     * @param {Node} element\n     * @returns {boolean}\n     */\n    isNativeFormElement: function(element) {\n      var nodeName = element.nodeName.toLowerCase();\n      return nodeName === 'input' ||\n        nodeName === 'select' ||\n        nodeName === 'button' ||\n        nodeName === 'textarea';\n    },\n\n    /**\n     * Gets whether an element is an `<input type=\"hidden\">`.\n     * @param {HTMLElement} element\n     * @returns {boolean}\n     */\n    isHiddenInput: function(element) {\n      return $mdUtil.isInputElement(element) && element.type == 'hidden';\n    },\n\n    /**\n     * Gets whether an element is an anchor that has an href attribute.\n     * @param {HTMLElement} element\n     * @returns {boolean}\n     */\n    isAnchorWithHref: function(element) {\n      return $mdUtil.isAnchorElement(element) && element.hasAttribute('href');\n    },\n\n    /**\n     * Gets whether an element is an input element.\n     * @param {HTMLElement} element\n     * @returns {boolean}\n     */\n    isInputElement: function(element) {\n      return element.nodeName.toLowerCase() == 'input';\n    },\n\n    /**\n     * Gets whether an element is an anchor element.\n     * @param {HTMLElement} element\n     * @returns {boolean}\n     */\n    isAnchorElement: function(element) {\n      return element.nodeName.toLowerCase() == 'a';\n    },\n\n    /**********************************************************************************************\n     * The following two functions were sourced from\n     * https://github.com/angular/components/blob/3c37e4b1c1cb74a3d0a90d173240fc730d21d9d4/src/cdk/a11y/focus-trap/focus-trap.ts#L268-L311\n     **********************************************************************************************/\n\n    /**\n     * Get the first tabbable element from a DOM subtree (inclusive).\n     * @param {HTMLElement} root\n     * @returns {HTMLElement|null}\n     */\n    getFirstTabbableElement: function(root) {\n      if ($mdUtil.isFocusable(root) && $mdUtil.isTabbable(root)) {\n        return root;\n      }\n\n      // Iterate in DOM order. Note that IE doesn't have `children` for SVG so we fall\n      // back to `childNodes` which includes text nodes, comments etc.\n      var children = root.children || root.childNodes;\n\n      for (var i = 0; i < children.length; i++) {\n        var tabbableChild = children[i].nodeType === $document[0].ELEMENT_NODE ?\n          $mdUtil.getFirstTabbableElement(children[i]) : null;\n\n        if (tabbableChild) {\n          return tabbableChild;\n        }\n      }\n\n      return null;\n    },\n\n    /**\n     * Get the last tabbable element from a DOM subtree (inclusive).\n     * @param {HTMLElement} root\n     * @returns {HTMLElement|null}\n     */\n    getLastTabbableElement: function(root) {\n      if ($mdUtil.isFocusable(root) && $mdUtil.isTabbable(root)) {\n        return root;\n      }\n\n      // Iterate in reverse DOM order.\n      var children = root.children || root.childNodes;\n\n      for (var i = children.length - 1; i >= 0; i--) {\n        var tabbableChild = children[i].nodeType === $document[0].ELEMENT_NODE ?\n          $mdUtil.getLastTabbableElement(children[i]) : null;\n\n        if (tabbableChild) {\n          return tabbableChild;\n        }\n      }\n\n      return null;\n    }\n  };\n\n  // Instantiate other namespace utility methods\n\n  $mdUtil.dom.animator = $$mdAnimate($mdUtil);\n\n  return $mdUtil;\n\n  function getNode(el) {\n    return el[0] || el;\n  }\n}\n\n/**\n * Since removing jQuery from the demos, some code that uses `element.focus()` is broken.\n * We need to add `element.focus()`, because it's testable unlike `element[0].focus`.\n */\nangular.element.prototype.focus = angular.element.prototype.focus || function() {\n  if (this.length) {\n    this[0].focus();\n  }\n  return this;\n};\n\nangular.element.prototype.blur = angular.element.prototype.blur || function() {\n  if (this.length) {\n    this[0].blur();\n  }\n  return this;\n};\n\n})();\n(function(){\n\"use strict\";\n\n// Polyfill angular < 1.4 (provide $animateCss)\nangular\n  .module('material.core')\n  .factory('$$mdAnimate', [\"$q\", \"$timeout\", \"$mdConstant\", \"$animateCss\", function($q, $timeout, $mdConstant, $animateCss) {\n     // Since $$mdAnimate is injected into $mdUtil... use a wrapper function\n     // to subsequently inject $mdUtil as an argument to the AnimateDomUtils\n     return function($mdUtil) {\n       return AnimateDomUtils($mdUtil, $q, $timeout, $mdConstant, $animateCss);\n     };\n   }]);\n\n/**\n * Factory function that requires special injections\n */\nfunction AnimateDomUtils($mdUtil, $q, $timeout, $mdConstant, $animateCss) {\n  var self;\n  return self = {\n    translate3d : function(target, from, to, options) {\n      return $animateCss(target, {\n        from: from,\n        to: to,\n        addClass: options.transitionInClass,\n        removeClass: options.transitionOutClass,\n        duration: options.duration\n      })\n      .start()\n      .then(function() {\n          // Resolve with reverser function...\n          return reverseTranslate;\n      });\n\n      /**\n       * Specific reversal of the request translate animation above...\n       */\n      function reverseTranslate (newFrom) {\n        return $animateCss(target, {\n           to: newFrom || from,\n           addClass: options.transitionOutClass,\n           removeClass: options.transitionInClass,\n           duration: options.duration\n        }).start();\n      }\n    },\n\n    /**\n     * Listen for transitionEnd event (with optional timeout)\n     * Announce completion or failure via promise handlers\n     */\n    waitTransitionEnd: function (element, opts) {\n      var TIMEOUT = 3000; // fallback is 3 secs\n\n      return $q(function(resolve, reject){\n        opts = opts || { };\n\n        // If there is no transition is found, resolve immediately\n        //\n        // NOTE: using $mdUtil.nextTick() causes delays/issues\n        if (noTransitionFound(opts.cachedTransitionStyles)) {\n          TIMEOUT = 0;\n        }\n\n        var timer = $timeout(finished, opts.timeout || TIMEOUT);\n        element.on($mdConstant.CSS.TRANSITIONEND, finished);\n\n        /**\n         * Upon timeout or transitionEnd, reject or resolve (respectively) this promise.\n         * NOTE: Make sure this transitionEnd didn't bubble up from a child\n         */\n        function finished(ev) {\n          if (ev && ev.target !== element[0]) return;\n\n          if (ev) $timeout.cancel(timer);\n          element.off($mdConstant.CSS.TRANSITIONEND, finished);\n\n          // Never reject since ngAnimate may cause timeouts due missed transitionEnd events\n          resolve();\n        }\n\n        /**\n         * Checks whether or not there is a transition.\n         *\n         * @param styles The cached styles to use for the calculation. If null, getComputedStyle()\n         * will be used.\n         *\n         * @returns {boolean} True if there is no transition/duration; false otherwise.\n         */\n        function noTransitionFound(styles) {\n          styles = styles || window.getComputedStyle(element[0]);\n\n          return styles.transitionDuration === '0s' ||\n            (!styles.transition && !styles.transitionProperty);\n        }\n      });\n    },\n\n    calculateTransformValues: function (element, originator) {\n      var origin = originator.element;\n      var bounds = originator.bounds;\n\n      if (origin || bounds) {\n        var originBnds = origin ? self.clientRect(origin) || currentBounds() : self.copyRect(bounds);\n        var dialogRect = self.copyRect(element[0].getBoundingClientRect());\n        var dialogCenterPt = self.centerPointFor(dialogRect);\n        var originCenterPt = self.centerPointFor(originBnds);\n\n        return {\n          centerX: originCenterPt.x - dialogCenterPt.x,\n          centerY: originCenterPt.y - dialogCenterPt.y,\n          scaleX: Math.round(100 * Math.min(0.5, originBnds.width / dialogRect.width)) / 100,\n          scaleY: Math.round(100 * Math.min(0.5, originBnds.height / dialogRect.height)) / 100\n        };\n      }\n      return {centerX: 0, centerY: 0, scaleX: 0.5, scaleY: 0.5};\n\n      /**\n       * This is a fallback if the origin information is no longer valid, then the\n       * origin bounds simply becomes the current bounds for the dialogContainer's parent.\n       * @returns {null|DOMRect}\n       */\n      function currentBounds() {\n        var container = element ? element.parent() : null;\n        var parent = container ? container.parent() : null;\n\n        return parent ? self.clientRect(parent) : null;\n      }\n    },\n\n    /**\n     * Calculate the zoom transform from dialog to origin.\n     *\n     * We use this to set the dialog position immediately;\n     * then the md-transition-in actually translates back to\n     * `translate3d(0,0,0) scale(1.0)`...\n     *\n     * NOTE: all values are rounded to the nearest integer\n     */\n    calculateZoomToOrigin: function (element, originator) {\n      var zoomTemplate = \"translate3d( {centerX}px, {centerY}px, 0 ) scale( {scaleX}, {scaleY} )\";\n      var buildZoom = angular.bind(null, $mdUtil.supplant, zoomTemplate);\n\n      return buildZoom(self.calculateTransformValues(element, originator));\n    },\n\n    /**\n     * Calculate the slide transform from panel to origin.\n     * NOTE: all values are rounded to the nearest integer\n     */\n    calculateSlideToOrigin: function (element, originator) {\n      var slideTemplate = \"translate3d( {centerX}px, {centerY}px, 0 )\";\n      var buildSlide = angular.bind(null, $mdUtil.supplant, slideTemplate);\n\n      return buildSlide(self.calculateTransformValues(element, originator));\n    },\n\n    /**\n     * Enhance raw values to represent valid css stylings...\n     */\n    toCss : function(raw) {\n      var css = { };\n      var lookups = 'left top right bottom width height x y min-width min-height max-width max-height';\n\n      angular.forEach(raw, function(value,key) {\n        if (angular.isUndefined(value)) return;\n\n        if (lookups.indexOf(key) >= 0) {\n          css[key] = value + 'px';\n        } else {\n          switch (key) {\n            case 'transition':\n              convertToVendor(key, $mdConstant.CSS.TRANSITION, value);\n              break;\n            case 'transform':\n              convertToVendor(key, $mdConstant.CSS.TRANSFORM, value);\n              break;\n            case 'transformOrigin':\n              convertToVendor(key, $mdConstant.CSS.TRANSFORM_ORIGIN, value);\n              break;\n            case 'font-size':\n              css['font-size'] = value; // font sizes aren't always in px\n              break;\n          }\n        }\n      });\n\n      return css;\n\n      function convertToVendor(key, vendor, value) {\n        angular.forEach(vendor.split(' '), function (key) {\n          css[key] = value;\n        });\n      }\n    },\n\n    /**\n     * Convert the translate CSS value to key/value pair(s).\n     * @param {string} transform\n     * @param {boolean=} addTransition\n     * @param {string=} transition\n     * @return {Object} object containing CSS translate key/value pair(s)\n     */\n    toTransformCss: function (transform, addTransition, transition) {\n      var css = {};\n      angular.forEach($mdConstant.CSS.TRANSFORM.split(' '), function (key) {\n        css[key] = transform;\n      });\n\n      if (addTransition) {\n        transition = transition || \"all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) !important\";\n        css.transition = transition;\n      }\n\n      return css;\n    },\n\n    /**\n     * Clone the Rect and calculate the height/width if needed.\n     * @param {DOMRect} source\n     * @param {DOMRect=} destination\n     * @returns {null|DOMRect}\n     */\n    copyRect: function (source, destination) {\n      if (!source) return null;\n\n      destination = destination || {};\n\n      angular.forEach('left top right bottom width height'.split(' '), function (key) {\n        destination[key] = Math.round(source[key]);\n      });\n\n      destination.width = destination.width || (destination.right - destination.left);\n      destination.height = destination.height || (destination.bottom - destination.top);\n\n      return destination;\n    },\n\n    /**\n     * Calculate ClientRect of element; return null if hidden or zero size.\n     * @param {Element|string} element\n     * @returns {null|DOMRect}\n     */\n    clientRect: function (element) {\n      var bounds = angular.element(element)[0].getBoundingClientRect();\n      var isPositiveSizeClientRect = function (rect) {\n        return rect && (rect.width > 0) && (rect.height > 0);\n      };\n\n      // If the event origin element has zero size, it has probably been hidden.\n      return isPositiveSizeClientRect(bounds) ? self.copyRect(bounds) : null;\n    },\n\n    /**\n     * Calculate 'rounded' center point of Rect\n     * @param {DOMRect} targetRect\n     * @returns {{x: number, y: number}}\n     */\n    centerPointFor: function (targetRect) {\n      return targetRect ? {\n        x: Math.round(targetRect.left + (targetRect.width / 2)),\n        y: Math.round(targetRect.top + (targetRect.height / 2))\n      } : { x : 0, y : 0 };\n    }\n  };\n}\n\n\n})();\n(function(){\n\"use strict\";\n\nif (angular.version.minor >= 4) {\n  angular.module('material.core.animate', []);\n} else {\n(function() {\n  \"use strict\";\n\n  var forEach = angular.forEach;\n\n  var WEBKIT = angular.isDefined(document.documentElement.style.WebkitAppearance);\n  var TRANSITION_PROP = WEBKIT ? 'WebkitTransition' : 'transition';\n  var ANIMATION_PROP = WEBKIT ? 'WebkitAnimation' : 'animation';\n  var PREFIX = WEBKIT ? '-webkit-' : '';\n\n  var TRANSITION_EVENTS = (WEBKIT ? 'webkitTransitionEnd ' : '') + 'transitionend';\n  var ANIMATION_EVENTS = (WEBKIT ? 'webkitAnimationEnd ' : '') + 'animationend';\n\n  var $$ForceReflowFactory = ['$document', function($document) {\n    return function() {\n      return $document[0].body.clientWidth + 1;\n    };\n  }];\n\n  var $$rAFMutexFactory = ['$$rAF', function($$rAF) {\n    return function() {\n      var passed = false;\n      $$rAF(function() {\n        passed = true;\n      });\n      return function(fn) {\n        passed ? fn() : $$rAF(fn);\n      };\n    };\n  }];\n\n  var $$AnimateRunnerFactory = ['$q', '$$rAFMutex', function($q, $$rAFMutex) {\n    var INITIAL_STATE = 0;\n    var DONE_PENDING_STATE = 1;\n    var DONE_COMPLETE_STATE = 2;\n\n    function AnimateRunner(host) {\n      this.setHost(host);\n\n      this._doneCallbacks = [];\n      this._runInAnimationFrame = $$rAFMutex();\n      this._state = 0;\n    }\n\n    AnimateRunner.prototype = {\n      setHost: function(host) {\n        this.host = host || {};\n      },\n\n      done: function(fn) {\n        if (this._state === DONE_COMPLETE_STATE) {\n          fn();\n        } else {\n          this._doneCallbacks.push(fn);\n        }\n      },\n\n      progress: angular.noop,\n\n      getPromise: function() {\n        if (!this.promise) {\n          var self = this;\n          this.promise = $q(function(resolve, reject) {\n            self.done(function(status) {\n              status === false ? reject() : resolve();\n            });\n          });\n        }\n        return this.promise;\n      },\n\n      then: function(resolveHandler, rejectHandler) {\n        return this.getPromise().then(resolveHandler, rejectHandler);\n      },\n\n      'catch': function(handler) {\n        return this.getPromise()['catch'](handler);\n      },\n\n      'finally': function(handler) {\n        return this.getPromise()['finally'](handler);\n      },\n\n      pause: function() {\n        if (this.host.pause) {\n          this.host.pause();\n        }\n      },\n\n      resume: function() {\n        if (this.host.resume) {\n          this.host.resume();\n        }\n      },\n\n      end: function() {\n        if (this.host.end) {\n          this.host.end();\n        }\n        this._resolve(true);\n      },\n\n      cancel: function() {\n        if (this.host.cancel) {\n          this.host.cancel();\n        }\n        this._resolve(false);\n      },\n\n      complete: function(response) {\n        var self = this;\n        if (self._state === INITIAL_STATE) {\n          self._state = DONE_PENDING_STATE;\n          self._runInAnimationFrame(function() {\n            self._resolve(response);\n          });\n        }\n      },\n\n      _resolve: function(response) {\n        if (this._state !== DONE_COMPLETE_STATE) {\n          forEach(this._doneCallbacks, function(fn) {\n            fn(response);\n          });\n          this._doneCallbacks.length = 0;\n          this._state = DONE_COMPLETE_STATE;\n        }\n      }\n    };\n\n    // Polyfill AnimateRunner.all which is used by input animations\n    AnimateRunner.all = function(runners, callback) {\n      var count = 0;\n      var status = true;\n      forEach(runners, function(runner) {\n        runner.done(onProgress);\n      });\n\n      function onProgress(response) {\n        status = status && response;\n        if (++count === runners.length) {\n          callback(status);\n        }\n      }\n    };\n\n    return AnimateRunner;\n  }];\n\n  angular\n    .module('material.core.animate', [])\n    .factory('$$forceReflow', $$ForceReflowFactory)\n    .factory('$$AnimateRunner', $$AnimateRunnerFactory)\n    .factory('$$rAFMutex', $$rAFMutexFactory)\n    .factory('$animateCss', ['$window', '$$rAF', '$$AnimateRunner', '$$forceReflow', '$$jqLite', '$timeout', '$animate',\n                     function($window,   $$rAF,   $$AnimateRunner,   $$forceReflow,   $$jqLite,   $timeout, $animate) {\n\n      function init(element, options) {\n\n        var temporaryStyles = [];\n        var node = getDomNode(element);\n        var areAnimationsAllowed = node && $animate.enabled();\n\n        var hasCompleteStyles = false;\n        var hasCompleteClasses = false;\n\n        if (areAnimationsAllowed) {\n          if (options.transitionStyle) {\n            temporaryStyles.push([PREFIX + 'transition', options.transitionStyle]);\n          }\n\n          if (options.keyframeStyle) {\n            temporaryStyles.push([PREFIX + 'animation', options.keyframeStyle]);\n          }\n\n          if (options.delay) {\n            temporaryStyles.push([PREFIX + 'transition-delay', options.delay + 's']);\n          }\n\n          if (options.duration) {\n            temporaryStyles.push([PREFIX + 'transition-duration', options.duration + 's']);\n          }\n\n          hasCompleteStyles = options.keyframeStyle ||\n              (options.to && (options.duration > 0 || options.transitionStyle));\n          hasCompleteClasses = !!options.addClass || !!options.removeClass;\n\n          blockTransition(element, true);\n        }\n\n        var hasCompleteAnimation = areAnimationsAllowed && (hasCompleteStyles || hasCompleteClasses);\n\n        applyAnimationFromStyles(element, options);\n\n        var animationClosed = false;\n        var events, eventFn;\n\n        return {\n          close: $window.close,\n          start: function() {\n            var runner = new $$AnimateRunner();\n            waitUntilQuiet(function() {\n              blockTransition(element, false);\n              if (!hasCompleteAnimation) {\n                return close();\n              }\n\n              forEach(temporaryStyles, function(entry) {\n                var key = entry[0];\n                var value = entry[1];\n                node.style[camelCase(key)] = value;\n              });\n\n              applyClasses(element, options);\n\n              var timings = computeTimings(element);\n              if (timings.duration === 0) {\n                return close();\n              }\n\n              var moreStyles = [];\n\n              if (options.easing) {\n                if (timings.transitionDuration) {\n                  moreStyles.push([PREFIX + 'transition-timing-function', options.easing]);\n                }\n                if (timings.animationDuration) {\n                  moreStyles.push([PREFIX + 'animation-timing-function', options.easing]);\n                }\n              }\n\n              if (options.delay && timings.animationDelay) {\n                moreStyles.push([PREFIX + 'animation-delay', options.delay + 's']);\n              }\n\n              if (options.duration && timings.animationDuration) {\n                moreStyles.push([PREFIX + 'animation-duration', options.duration + 's']);\n              }\n\n              forEach(moreStyles, function(entry) {\n                var key = entry[0];\n                var value = entry[1];\n                node.style[camelCase(key)] = value;\n                temporaryStyles.push(entry);\n              });\n\n              var maxDelay = timings.delay;\n              var maxDelayTime = maxDelay * 1000;\n              var maxDuration = timings.duration;\n              var maxDurationTime = maxDuration * 1000;\n              var startTime = Date.now();\n\n              events = [];\n              if (timings.transitionDuration) {\n                events.push(TRANSITION_EVENTS);\n              }\n              if (timings.animationDuration) {\n                events.push(ANIMATION_EVENTS);\n              }\n              events = events.join(' ');\n              eventFn = function(event) {\n                event.stopPropagation();\n                var ev = event.originalEvent || event;\n                var timeStamp = ev.timeStamp || Date.now();\n                var elapsedTime = parseFloat(ev.elapsedTime.toFixed(3));\n                if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {\n                  close();\n                }\n              };\n              element.on(events, eventFn);\n\n              applyAnimationToStyles(element, options);\n\n              $timeout(close, maxDelayTime + maxDurationTime * 1.5, false);\n            });\n\n            return runner;\n\n            function close() {\n              if (animationClosed) return;\n              animationClosed = true;\n\n              if (events && eventFn) {\n                element.off(events, eventFn);\n              }\n              applyClasses(element, options);\n              applyAnimationStyles(element, options);\n              forEach(temporaryStyles, function(entry) {\n                node.style[camelCase(entry[0])] = '';\n              });\n              runner.complete(true);\n              return runner;\n            }\n          }\n        };\n      }\n\n      function applyClasses(element, options) {\n        if (options.addClass) {\n          $$jqLite.addClass(element, options.addClass);\n          options.addClass = null;\n        }\n        if (options.removeClass) {\n          $$jqLite.removeClass(element, options.removeClass);\n          options.removeClass = null;\n        }\n      }\n\n      function computeTimings(element) {\n        var node = getDomNode(element);\n        var cs = $window.getComputedStyle(node);\n        var tdr = parseMaxTime(cs[prop('transitionDuration')]);\n        var adr = parseMaxTime(cs[prop('animationDuration')]);\n        var tdy = parseMaxTime(cs[prop('transitionDelay')]);\n        var ady = parseMaxTime(cs[prop('animationDelay')]);\n\n        adr *= (parseInt(cs[prop('animationIterationCount')], 10) || 1);\n        var duration = Math.max(adr, tdr);\n        var delay = Math.max(ady, tdy);\n\n        return {\n          duration: duration,\n          delay: delay,\n          animationDuration: adr,\n          transitionDuration: tdr,\n          animationDelay: ady,\n          transitionDelay: tdy\n        };\n\n        function prop(key) {\n          return WEBKIT ? 'Webkit' + key.charAt(0).toUpperCase() + key.substr(1)\n                        : key;\n        }\n      }\n\n      function parseMaxTime(str) {\n        var maxValue = 0;\n        var values = (str || \"\").split(/\\s*,\\s*/);\n        forEach(values, function(value) {\n          // it's always safe to consider only second values and omit `ms` values since\n          // getComputedStyle will always handle the conversion for us\n          if (value.charAt(value.length - 1) == 's') {\n            value = value.substring(0, value.length - 1);\n          }\n          value = parseFloat(value) || 0;\n          maxValue = maxValue ? Math.max(value, maxValue) : value;\n        });\n        return maxValue;\n      }\n\n      var cancelLastRAFRequest;\n      var rafWaitQueue = [];\n      function waitUntilQuiet(callback) {\n        if (cancelLastRAFRequest) {\n          cancelLastRAFRequest(); // cancels the request\n        }\n        rafWaitQueue.push(callback);\n        cancelLastRAFRequest = $$rAF(function() {\n          cancelLastRAFRequest = null;\n\n          // DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable.\n          // PLEASE EXAMINE THE `$$forceReflow` service to understand why.\n          var pageWidth = $$forceReflow();\n\n          // we use a for loop to ensure that if the queue is changed\n          // during this looping then it will consider new requests\n          for (var i = 0; i < rafWaitQueue.length; i++) {\n            rafWaitQueue[i](pageWidth);\n          }\n          rafWaitQueue.length = 0;\n        });\n      }\n\n      function applyAnimationStyles(element, options) {\n        applyAnimationFromStyles(element, options);\n        applyAnimationToStyles(element, options);\n      }\n\n      function applyAnimationFromStyles(element, options) {\n        if (options.from) {\n          element.css(options.from);\n          options.from = null;\n        }\n      }\n\n      function applyAnimationToStyles(element, options) {\n        if (options.to) {\n          element.css(options.to);\n          options.to = null;\n        }\n      }\n\n      function getDomNode(element) {\n        for (var i = 0; i < element.length; i++) {\n          if (element[i].nodeType === 1) return element[i];\n        }\n      }\n\n      function blockTransition(element, bool) {\n        var node = getDomNode(element);\n        var key = camelCase(PREFIX + 'transition-delay');\n        node.style[key] = bool ? '-9999s' : '';\n      }\n\n      return init;\n    }]);\n\n  /**\n   * Older browsers [FF31] expect camelCase\n   * property keys.\n   * e.g.\n   *  animation-duration --> animationDuration\n   */\n  function camelCase(str) {\n    return str.replace(/-[a-z]/g, function(str) {\n      return str.charAt(1).toUpperCase();\n    });\n  }\n\n})();\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.core.aria\n * @description\n * Aria Expectations for AngularJS Material components.\n */\nMdAriaService.$inject = [\"$$rAF\", \"$log\", \"$window\", \"$interpolate\"];\nangular\n  .module('material.core')\n  .provider('$mdAria', MdAriaProvider);\n\n/**\n * @ngdoc service\n * @name $mdAriaProvider\n * @module material.core.aria\n *\n * @description\n *\n * Modify options of the `$mdAria` service, which will be used by most of the AngularJS Material\n * components.\n *\n * You are able to disable `$mdAria` warnings, by using the following markup.\n *\n * <hljs lang=\"js\">\n *   app.config(function($mdAriaProvider) {\n *     // Globally disables all ARIA warnings.\n *     $mdAriaProvider.disableWarnings();\n *   });\n * </hljs>\n *\n */\nfunction MdAriaProvider() {\n\n  var config = {\n    /** Whether we should show ARIA warnings in the console if labels are missing on the element */\n    showWarnings: true\n  };\n\n  return {\n    disableWarnings: disableWarnings,\n    $get: [\"$$rAF\", \"$log\", \"$window\", \"$interpolate\", function($$rAF, $log, $window, $interpolate) {\n      return MdAriaService.apply(config, arguments);\n    }]\n  };\n\n  /**\n   * @ngdoc method\n   * @name $mdAriaProvider#disableWarnings\n   * @description Disables all ARIA warnings generated by AngularJS Material.\n   */\n  function disableWarnings() {\n    config.showWarnings = false;\n  }\n}\n\n/*\n * @ngInject\n */\nfunction MdAriaService($$rAF, $log, $window, $interpolate) {\n\n  // Load the showWarnings option from the current context and store it inside of a scope variable,\n  // because the context will be probably lost in some function calls.\n  var showWarnings = this.showWarnings;\n\n  return {\n    expect: expect,\n    expectAsync: expectAsync,\n    expectWithText: expectWithText,\n    expectWithoutText: expectWithoutText,\n    getText: getText,\n    hasAriaLabel: hasAriaLabel,\n    parentHasAriaLabel: parentHasAriaLabel\n  };\n\n  /**\n   * Check if expected attribute has been specified on the target element or child\n   * @param {string|JQLite} element\n   * @param {string} attrName\n   * @param {string=} defaultValue What to set the attr to if no value is found\n   */\n  function expect(element, attrName, defaultValue) {\n\n    var node = angular.element(element)[0] || element;\n\n    // if node exists and neither it nor its children have the attribute\n    if (node &&\n       ((!node.hasAttribute(attrName) ||\n        node.getAttribute(attrName).length === 0) &&\n        !childHasAttribute(node, attrName))) {\n\n      defaultValue = angular.isString(defaultValue) ? defaultValue.trim() : '';\n      if (defaultValue.length) {\n        element.attr(attrName, defaultValue);\n      } else if (showWarnings) {\n        $log.warn('ARIA: Attribute \"', attrName, '\", required for accessibility, is missing on node:', node);\n      }\n\n    }\n  }\n\n  function expectAsync(element, attrName, defaultValueGetter) {\n    // Problem: when retrieving the element's contents synchronously to find the label,\n    // the text may not be defined yet in the case of a binding.\n    // There is a higher chance that a binding will be defined if we wait one frame.\n    $$rAF(function() {\n        expect(element, attrName, defaultValueGetter());\n    });\n  }\n\n  function expectWithText(element, attrName) {\n    var content = getText(element) || \"\";\n    var hasBinding = content.indexOf($interpolate.startSymbol()) > -1;\n\n    if (hasBinding) {\n      expectAsync(element, attrName, function() {\n        return getText(element);\n      });\n    } else {\n      expect(element, attrName, content);\n    }\n  }\n\n  function expectWithoutText(element, attrName) {\n    var content = getText(element);\n    var hasBinding = content.indexOf($interpolate.startSymbol()) > -1;\n\n    if (!hasBinding && !content) {\n      expect(element, attrName, content);\n    }\n  }\n\n  /**\n   * @param {Element|JQLite} element\n   * @returns {string}\n   */\n  function getText(element) {\n    element = element[0] || element;\n    var walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);\n    var text = '';\n\n    var node;\n    while (node = walker.nextNode()) {\n      if (!isAriaHiddenNode(node)) {\n        text += node.textContent;\n      }\n    }\n\n    return text.trim() || '';\n\n    /**\n     * @param {Node} node\n     * @returns {boolean}\n     */\n    function isAriaHiddenNode(node) {\n      while (node.parentNode && (node = node.parentNode) !== element) {\n        if (node.getAttribute && node.getAttribute('aria-hidden') === 'true') {\n          return true;\n        }\n      }\n    }\n  }\n\n  function childHasAttribute(node, attrName) {\n    var hasChildren = node.hasChildNodes(),\n        hasAttr = false;\n\n    function isHidden(el) {\n      var style = el.currentStyle ? el.currentStyle : $window.getComputedStyle(el);\n      return (style.display === 'none');\n    }\n\n    if (hasChildren) {\n      var children = node.childNodes;\n      for (var i=0; i < children.length; i++) {\n        var child = children[i];\n        if (child.nodeType === 1 && child.hasAttribute(attrName)) {\n          if (!isHidden(child)) {\n            hasAttr = true;\n          }\n        }\n      }\n    }\n    return hasAttr;\n  }\n\n  /**\n   * Check if expected element has aria label attribute\n   * @param element\n   */\n  function hasAriaLabel(element) {\n    var node = angular.element(element)[0] || element;\n\n    /* Check if compatible node type (ie: not HTML Document node) */\n    if (!node.hasAttribute) {\n      return false;\n    }\n\n    /* Check label or description attributes */\n    return node.hasAttribute('aria-label') || node.hasAttribute('aria-labelledby') || node.hasAttribute('aria-describedby');\n  }\n\n  /**\n   * Check if expected element's parent has aria label attribute and has valid role and tagName\n   * @param {string|JQLite|Node & ParentNode} element\n   * @param {number=} level Number of levels deep search should be performed\n   */\n  function parentHasAriaLabel(element, level) {\n    level = level || 1;\n    var node = angular.element(element)[0] || element;\n    if (!node.parentNode) {\n      return false;\n    }\n    if (performCheck(node.parentNode)) {\n      return true;\n    }\n    level--;\n    if (level) {\n      return parentHasAriaLabel(node.parentNode, level);\n    }\n    return false;\n\n    function performCheck(parentNode) {\n      if (!hasAriaLabel(parentNode)) {\n        return false;\n      }\n      /* Perform role block-list check */\n      if (parentNode.hasAttribute('role')) {\n        switch (parentNode.getAttribute('role').toLowerCase()) {\n          case 'command':\n          case 'definition':\n          case 'directory':\n          case 'grid':\n          case 'list':\n          case 'listitem':\n          case 'log':\n          case 'marquee':\n          case 'menu':\n          case 'menubar':\n          case 'note':\n          case 'presentation':\n          case 'separator':\n          case 'scrollbar':\n          case 'status':\n          case 'tablist':\n            return false;\n        }\n      }\n      /* Perform tagName block-list check */\n      switch (parentNode.tagName.toLowerCase()) {\n        case 'abbr':\n        case 'acronym':\n        case 'address':\n        case 'applet':\n        case 'audio':\n        case 'b':\n        case 'bdi':\n        case 'bdo':\n        case 'big':\n        case 'blockquote':\n        case 'br':\n        case 'canvas':\n        case 'caption':\n        case 'center':\n        case 'cite':\n        case 'code':\n        case 'col':\n        case 'data':\n        case 'dd':\n        case 'del':\n        case 'dfn':\n        case 'dir':\n        case 'div':\n        case 'dl':\n        case 'em':\n        case 'embed':\n        case 'fieldset':\n        case 'figcaption':\n        case 'font':\n        case 'h1':\n        case 'h2':\n        case 'h3':\n        case 'h4':\n        case 'h5':\n        case 'h6':\n        case 'hgroup':\n        case 'html':\n        case 'i':\n        case 'ins':\n        case 'isindex':\n        case 'kbd':\n        case 'keygen':\n        case 'label':\n        case 'legend':\n        case 'li':\n        case 'map':\n        case 'mark':\n        case 'menu':\n        case 'object':\n        case 'ol':\n        case 'output':\n        case 'pre':\n        case 'presentation':\n        case 'q':\n        case 'rt':\n        case 'ruby':\n        case 'samp':\n        case 'small':\n        case 'source':\n        case 'span':\n        case 'status':\n        case 'strike':\n        case 'strong':\n        case 'sub':\n        case 'sup':\n        case 'svg':\n        case 'tbody':\n        case 'td':\n        case 'th':\n        case 'thead':\n        case 'time':\n        case 'tr':\n        case 'track':\n        case 'tt':\n        case 'ul':\n        case 'var':\n          return false;\n      }\n      return true;\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.core.compiler\n * @description\n * AngularJS Material template and element compiler.\n */\nangular\n  .module('material.core')\n  .provider('$mdCompiler', MdCompilerProvider);\n\nMdCompilerProvider.$inject = ['$compileProvider'];\nfunction MdCompilerProvider() {\n\n  this.$get = [\"$q\", \"$templateRequest\", \"$injector\", \"$compile\", \"$controller\",\n    function($q, $templateRequest, $injector, $compile, $controller) {\n      return new MdCompilerService($q, $templateRequest, $injector, $compile, $controller);\n    }];\n\n  /**\n   * @ngdoc service\n   * @name $mdCompiler\n   * @module material.core.compiler\n   * @description\n   * The $mdCompiler service is an abstraction of AngularJS's compiler, that allows developers\n   * to compile an element with options like in a Directive Definition Object.\n   *\n   * > The compiler powers a lot of components inside of AngularJS Material.\n   * > Like the `$mdPanel` or `$mdDialog` services.\n   *\n   * @usage\n   *\n   * Basic Usage with a template\n   *\n   * <hljs lang=\"js\">\n   *   $mdCompiler.compile({\n   *     templateUrl: 'modal.html',\n   *     controller: 'ModalCtrl',\n   *     locals: {\n   *       modal: myModalInstance;\n   *     }\n   *   }).then(function (compileData) {\n   *     compileData.element; // Compiled DOM element\n   *     compileData.link(myScope); // Instantiate controller and link element to scope.\n   *   });\n   * </hljs>\n   *\n   * Example with a content element\n   *\n   * <hljs lang=\"js\">\n   *\n   *   // Create a virtual element and link it manually.\n   *   // The compiler doesn't need to recompile the element each time.\n   *   var myElement = $compile('<span>Test</span>')(myScope);\n   *\n   *   $mdCompiler.compile({\n   *     contentElement: myElement\n   *   }).then(function (compileData) {\n   *     compileData.element // Content Element (same as above)\n   *     compileData.link // This does nothing when using a contentElement.\n   *   });\n   * </hljs>\n   *\n   * > Content Element is a significant performance improvement when the developer already knows\n   * > that the compiled element will be always the same and the scope will not change either.\n   *\n   * The `contentElement` option also supports DOM elements which will be temporary removed and\n   * restored at its old position.\n   *\n   * <hljs lang=\"js\">\n   *   var domElement = document.querySelector('#myElement');\n   *\n   *   $mdCompiler.compile({\n   *     contentElement: myElement\n   *   }).then(function (compileData) {\n   *     compileData.element // Content Element (same as above)\n   *     compileData.link // This does nothing when using a contentElement.\n   *   });\n   * </hljs>\n   *\n   * The `$mdCompiler` can also query for the element in the DOM itself.\n   *\n   * <hljs lang=\"js\">\n   *   $mdCompiler.compile({\n   *     contentElement: '#myElement'\n   *   }).then(function (compileData) {\n   *     compileData.element // Content Element (same as above)\n   *     compileData.link // This does nothing when using a contentElement.\n   *   });\n   * </hljs>\n   *\n   */\n  function MdCompilerService($q, $templateRequest, $injector, $compile, $controller) {\n\n    /**\n     * @private @const\n     * @type {!IQService}\n     */\n    this.$q = $q;\n\n    /**\n     * @private @const\n     * @type {!ITemplateRequestService}\n     */\n    this.$templateRequest = $templateRequest;\n\n    /**\n     * @private @const\n     * @type {!IInjectorService}\n     */\n    this.$injector = $injector;\n\n    /**\n     * @private @const\n     * @type{!ICompileService}\n     */\n    this.$compile = $compile;\n\n    /**\n     * @private @const\n     * @type {!IControllerService}\n     */\n    this.$controller = $controller;\n  }\n\n  /**\n   * @ngdoc method\n   * @name $mdCompiler#compile\n   * @description\n   *\n   * A method to compile a HTML template with the AngularJS compiler.\n   * The `$mdCompiler` is wrapper around the AngularJS compiler and provides extra functionality\n   * like controller instantiation or async resolves.\n   *\n   * @param {!Object} options An options object, with the following properties:\n   *\n   *    - `controller` - `{string|function}` Controller fn that should be associated with\n   *         newly created scope or the name of a registered controller if passed as a string.\n   *    - `controllerAs` - `{string=}` A controller alias name. If present the controller will be\n   *         published to scope under the `controllerAs` name.\n   *    - `contentElement` - `{string|Element}`: Instead of using a template, which will be\n   *         compiled each time, you can also use a DOM element.<br/>\n   *    - `template` - `{string=}` An html template as a string.\n   *    - `templateUrl` - `{string=}` A path to an html template.\n   *    - `transformTemplate` - `{function(template)=}` A function which transforms the template after\n   *        it is loaded. It will be given the template string as a parameter, and should\n   *        return a a new string representing the transformed template.\n   *    - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should\n   *        be injected into the controller. If any of these dependencies are promises, the compiler\n   *        will wait for them all to be resolved, or if one is rejected before the controller is\n   *        instantiated `compile()` will fail..\n   *      * `key` - `{string}`: a name of a dependency to be injected into the controller.\n   *      * `factory` - `{string|function}`: If `string` then it is an alias for a service.\n   *        Otherwise if function, then it is injected and the return value is treated as the\n   *        dependency. If the result is a promise, it is resolved before its value is\n   *        injected into the controller.\n   *\n   * @returns {Q.Promise<{element: JQLite, link: Function, locals: Object, cleanup: any,\n   *  controller: Object=}>} promise A promise, which will be resolved with a `compileData` object.\n   *  `compileData` has the following properties:\n   *\n   *   - `element` - `{JQLite}`: an uncompiled element matching the provided template.\n   *   - `link` - `{function(scope)}`: A link function, which, when called, will compile\n   *     the element and instantiate the provided controller (if given).\n   *   - `locals` - `{Object}`: The locals which will be passed into the controller once `link` is\n   *     called. If `bindToController` is true, they will be copied to the ctrl instead\n   */\n  MdCompilerService.prototype.compile = function(options) {\n    if (options.contentElement) {\n      return this._prepareContentElement(options);\n    } else {\n      return this._compileTemplate(options);\n    }\n  };\n\n  /**\n   * Instead of compiling any template, the compiler just fetches an existing HTML element from the\n   * DOM and provides a restore function to put the element back it old DOM position.\n   * @param {!Object} options Options to be used for the compiler.\n   * @returns {Q.Promise<{element: JQLite, link: Function, locals: Object, cleanup: any}>}\n   */\n  MdCompilerService.prototype._prepareContentElement = function(options) {\n\n    var contentElement = this._fetchContentElement(options);\n\n    return this.$q.resolve({\n      element: contentElement.element,\n      cleanup: contentElement.restore,\n      locals: {},\n      link: function() {\n        return contentElement.element;\n      }\n    });\n\n  };\n\n  /**\n   * Compiles a template by considering all options and waiting for all resolves to be ready.\n   * @param {!Object} options Compile options\n   * @returns {!Q.Promise<{element: JQLite, link: Function, locals: Object, cleanup: any}>} Compile\n   *  data with link function.\n   */\n  MdCompilerService.prototype._compileTemplate = function(options) {\n\n    var self = this;\n    var templateUrl = options.templateUrl;\n    var template = options.template || '';\n    var resolve = angular.extend({}, options.resolve);\n    var locals = angular.extend({}, options.locals);\n    var transformTemplate = options.transformTemplate || angular.identity;\n\n    // Take resolve values and invoke them.\n    // Resolves can either be a string (value: 'MyRegisteredAngularConst'),\n    // or an invokable 'factory' of sorts: (value: function ValueGetter($dependency) {})\n    angular.forEach(resolve, function(value, key) {\n      if (angular.isString(value)) {\n        resolve[key] = self.$injector.get(value);\n      } else {\n        resolve[key] = self.$injector.invoke(value);\n      }\n    });\n\n    // Add the locals, which are just straight values to inject\n    // eg locals: { three: 3 }, will inject three into the controller\n    angular.extend(resolve, locals);\n\n    if (templateUrl) {\n      resolve.$$ngTemplate = this.$templateRequest(templateUrl);\n    } else {\n      resolve.$$ngTemplate = this.$q.when(template);\n    }\n\n\n    // Wait for all the resolves to finish if they are promises\n    return this.$q.all(resolve).then(function(locals) {\n\n      var template = transformTemplate(locals.$$ngTemplate, options);\n      var element = options.element || angular.element('<div>').html(template.trim()).contents();\n\n      return self._compileElement(locals, element, options);\n    });\n\n  };\n\n  /**\n   * Method to compile an element with the given options.\n   * @param {!Object} locals Locals to be injected to the controller if present\n   * @param {!JQLite} element Element to be compiled and linked\n   * @param {!Object} options Options to be used for linking.\n   * @returns {!{element: JQLite, link: Function, locals: Object, cleanup: any, controller: Object}} Compile data with link function.\n   */\n  MdCompilerService.prototype._compileElement = function(locals, element, options) {\n    var self = this;\n    var ngLinkFn = this.$compile(element);\n\n    var compileData = {\n      element: element,\n      cleanup: element.remove.bind(element),\n      locals: locals,\n      link: linkFn\n    };\n\n    function linkFn(scope) {\n      locals.$scope = scope;\n\n      // Instantiate controller if the developer provided one.\n      if (options.controller) {\n\n        var injectLocals = angular.extend({}, locals, {\n          $element: element\n        });\n\n        // Create the specified controller instance.\n        var ctrl = self._createController(options, injectLocals, locals);\n\n        // Registering extra $destroy listeners should be avoided.\n        // Only register the listener if the controller implements a $onDestroy hook.\n        if (angular.isFunction(ctrl.$onDestroy)) {\n          scope.$on('$destroy', function() {\n            // Call the $onDestroy hook if it's present on the controller.\n            angular.isFunction(ctrl.$onDestroy) && ctrl.$onDestroy();\n          });\n        }\n\n        // Unique identifier for AngularJS Route ngView controllers.\n        element.data('$ngControllerController', ctrl);\n        element.children().data('$ngControllerController', ctrl);\n\n        // Expose the instantiated controller to the compile data\n        compileData.controller = ctrl;\n      }\n\n      // Invoke the AngularJS $compile link function.\n      return ngLinkFn(scope);\n    }\n\n    return compileData;\n\n  };\n\n  /**\n   * Creates and instantiates a new controller with the specified options.\n   * @param {!Object} options Options that include the controller function or string.\n   * @param {!Object} injectLocals Locals to to be provided in the controller DI.\n   * @param {!Object} locals Locals to be injected to the controller.\n   * @returns {!Object} Created controller instance.\n   */\n  MdCompilerService.prototype._createController = function(options, injectLocals, locals) {\n    var ctrl = this.$controller(options.controller, injectLocals);\n\n    if (options.bindToController) {\n      angular.extend(ctrl, locals);\n    }\n\n    if (options.controllerAs) {\n      injectLocals.$scope[options.controllerAs] = ctrl;\n    }\n\n    // Call the $onInit hook if it's present on the controller.\n    angular.isFunction(ctrl.$onInit) && ctrl.$onInit();\n\n    return ctrl;\n  };\n\n  /**\n   * Fetches an element removing it from the DOM and using it temporary for the compiler.\n   * Elements which were fetched will be restored after use.\n   * @param {!Object} options Options to be used for the compilation.\n   * @returns {{element: !JQLite, restore: !function}}\n   */\n  MdCompilerService.prototype._fetchContentElement = function(options) {\n    var contentEl = options.contentElement;\n    var restoreFn;\n\n    if (angular.isString(contentEl)) {\n      contentEl = document.querySelector(contentEl);\n      restoreFn = createRestoreFn(contentEl);\n    } else {\n      contentEl = contentEl[0] || contentEl;\n\n      // When the element is visible in the DOM, then we restore it at close of the dialog.\n      // Otherwise it will be removed from the DOM after close.\n      if (document.contains(contentEl)) {\n        restoreFn = createRestoreFn(contentEl);\n      } else {\n        restoreFn = function() {\n          if (contentEl.parentNode) {\n            contentEl.parentNode.removeChild(contentEl);\n          }\n        };\n      }\n    }\n\n    return {\n      element: angular.element(contentEl),\n      restore: restoreFn\n    };\n\n    function createRestoreFn(element) {\n      var parent = element.parentNode;\n      var nextSibling = element.nextElementSibling;\n\n      return function() {\n        if (!nextSibling) {\n          // When the element didn't had any sibling, then it can be simply appended to the\n          // parent, because it plays no role, which index it had before.\n          parent.appendChild(element);\n        } else {\n          // When the element had a sibling, which marks the previous position of the element\n          // in the DOM, we insert it correctly before the sibling, to have the same index as\n          // before.\n          parent.insertBefore(element, nextSibling);\n        }\n      };\n    }\n  };\n}\n\n\n})();\n(function(){\n\"use strict\";\n\n\nMdGesture.$inject = [\"$$MdGestureHandler\", \"$$rAF\", \"$timeout\", \"$mdUtil\"];\nattachToDocument.$inject = [\"$mdGesture\", \"$$MdGestureHandler\", \"$mdUtil\"];var HANDLERS = {};\n\n/**\n * The state of the current 'pointer'. The pointer represents the state of the current touch.\n * It contains normalized x and y coordinates from DOM events,\n * as well as other information abstracted from the DOM.\n */\nvar pointer, lastPointer, maxClickDistance = 6;\nvar forceSkipClickHijack = false, disableAllGestures = false;\n\n/**\n * The position of the most recent click if that click was on a label element.\n * @type {{x: number, y: number}|null}\n */\nvar lastLabelClickPos = null;\n\n/**\n * Used to attach event listeners once when multiple ng-apps are running.\n * @type {boolean}\n */\nvar isInitialized = false;\n\n/**\n * @ngdoc module\n * @name material.core.gestures\n * @description\n * AngularJS Material Gesture handling for touch devices.\n * This module replaced the usage of the HammerJS library.\n */\nangular\n  .module('material.core.gestures', [])\n  .provider('$mdGesture', MdGestureProvider)\n  .factory('$$MdGestureHandler', MdGestureHandler)\n  .run(attachToDocument);\n\n/**\n * @ngdoc service\n * @name $mdGestureProvider\n * @module material.core.gestures\n *\n * @description\n * In some scenarios on mobile devices (without jQuery), the click events should NOT be hijacked.\n * `$mdGestureProvider` is used to configure the Gesture module to ignore or skip click hijacking\n * on mobile devices.\n *\n * You can also change the max click distance, `6px` by default, if you have issues on some touch\n * screens.\n *\n * <hljs lang=\"js\">\n *   app.config(function($mdGestureProvider) {\n *\n *     // For mobile devices without jQuery loaded, do not\n *     // intercept click events during the capture phase.\n *     $mdGestureProvider.skipClickHijack();\n *\n *     // If hijacking clicks, you may want to change the default click distance\n *     $mdGestureProvider.setMaxClickDistance(12);\n *   });\n * </hljs>\n *\n */\nfunction MdGestureProvider() { }\n\nMdGestureProvider.prototype = {\n\n  /**\n   * @ngdoc method\n   * @name $mdGestureProvider#disableAll\n   *\n   * @description\n   * Disable all gesture detection. This can be beneficial to application performance\n   * and memory usage.\n   */\n  disableAll: function () {\n    disableAllGestures = true;\n  },\n\n  // Publish access to setter to configure a variable BEFORE the\n  // $mdGesture service is instantiated...\n  /**\n   * @ngdoc method\n   * @name $mdGestureProvider#skipClickHijack\n   *\n   * @description\n   * Tell the AngularJS Material Gesture module to skip (or ignore) click hijacking on mobile devices.\n   */\n  skipClickHijack: function() {\n    return forceSkipClickHijack = true;\n  },\n\n  /**\n   * @ngdoc method\n   * @name $mdGestureProvider#setMaxClickDistance\n   * @param clickDistance {string} Distance in pixels. I.e. `12px`.\n   * @description\n   * Set the max distance from the origin of the touch event to trigger touch handlers.\n   */\n  setMaxClickDistance: function(clickDistance) {\n    maxClickDistance = parseInt(clickDistance);\n  },\n\n  /**\n   * $get is used to build an instance of $mdGesture\n   * @ngInject\n   */\n  $get : [\"$$MdGestureHandler\", \"$$rAF\", \"$timeout\", \"$mdUtil\", function($$MdGestureHandler, $$rAF, $timeout, $mdUtil) {\n       return new MdGesture($$MdGestureHandler, $$rAF, $timeout, $mdUtil);\n  }]\n};\n\n\n\n/**\n * MdGesture factory construction function\n * @ngInject\n */\nfunction MdGesture($$MdGestureHandler, $$rAF, $timeout, $mdUtil) {\n  var touchActionProperty = $mdUtil.getTouchAction();\n  var hasJQuery = (typeof window.jQuery !== 'undefined') && (angular.element === window.jQuery);\n\n  var self = {\n    handler: addHandler,\n    register: register,\n    isAndroid: $mdUtil.isAndroid,\n    isIos: $mdUtil.isIos,\n    // On mobile w/out jQuery, we normally intercept clicks. Should we skip that?\n    isHijackingClicks: ($mdUtil.isIos || $mdUtil.isAndroid) && !hasJQuery && !forceSkipClickHijack\n  };\n\n  if (self.isHijackingClicks) {\n    self.handler('click', {\n      options: {\n        maxDistance: maxClickDistance\n      },\n      onEnd: checkDistanceAndEmit('click')\n    });\n\n    self.handler('focus', {\n      options: {\n        maxDistance: maxClickDistance\n      },\n      onEnd: function(ev, pointer) {\n        if (pointer.distance < this.state.options.maxDistance && canFocus(ev.target)) {\n          this.dispatchEvent(ev, 'focus', pointer);\n          ev.target.focus();\n        }\n      }\n    });\n\n    self.handler('mouseup', {\n      options: {\n        maxDistance: maxClickDistance\n      },\n      onEnd: checkDistanceAndEmit('mouseup')\n    });\n\n    self.handler('mousedown', {\n      onStart: function(ev) {\n        this.dispatchEvent(ev, 'mousedown');\n      }\n    });\n  }\n\n  function checkDistanceAndEmit(eventName) {\n    return function(ev, pointer) {\n      if (pointer.distance < this.state.options.maxDistance) {\n        this.dispatchEvent(ev, eventName, pointer);\n      }\n    };\n  }\n\n  /**\n   * Register an element to listen for a handler.\n   * This allows an element to override the default options for a handler.\n   * Additionally, some handlers like drag and hold only dispatch events if\n   * the domEvent happens inside an element that's registered to listen for these events.\n   *\n   * @see GestureHandler for how overriding of default options works.\n   * @example $mdGesture.register(myElement, 'drag', { minDistance: 20, horizontal: false })\n   */\n  function register(element, handlerName, options) {\n    var handler = HANDLERS[handlerName.replace(/^\\$md./, '')];\n    if (!handler) {\n      throw new Error('Failed to register element with handler ' + handlerName + '. ' +\n      'Available handlers: ' + Object.keys(HANDLERS).join(', '));\n    }\n    return handler.registerElement(element, options);\n  }\n\n  /*\n   * add a handler to $mdGesture. see below.\n   */\n  function addHandler(name, definition) {\n    var handler = new $$MdGestureHandler(name);\n    angular.extend(handler, definition);\n    HANDLERS[name] = handler;\n\n    return self;\n  }\n\n  /**\n   * Register handlers. These listen to touch/start/move events, interpret them,\n   * and dispatch gesture events depending on options & conditions. These are all\n   * instances of GestureHandler.\n   * @see GestureHandler\n   */\n  return self\n    /*\n     * The press handler dispatches an event on touchdown/touchend.\n     * It's a simple abstraction of touch/mouse/pointer start and end.\n     */\n    .handler('press', {\n      onStart: function (ev, pointer) {\n        this.dispatchEvent(ev, '$md.pressdown');\n      },\n      onEnd: function (ev, pointer) {\n        this.dispatchEvent(ev, '$md.pressup');\n      }\n    })\n\n    /*\n     * The hold handler dispatches an event if the user keeps their finger within\n     * the same <maxDistance> area for <delay> ms.\n     * The hold handler will only run if a parent of the touch target is registered\n     * to listen for hold events through $mdGesture.register()\n     */\n    .handler('hold', {\n      options: {\n        maxDistance: 6,\n        delay: 500\n      },\n      onCancel: function () {\n        $timeout.cancel(this.state.timeout);\n      },\n      onStart: function (ev, pointer) {\n        // For hold, require a parent to be registered with $mdGesture.register()\n        // Because we prevent scroll events, this is necessary.\n        if (!this.state.registeredParent) return this.cancel();\n\n        this.state.pos = {x: pointer.x, y: pointer.y};\n        this.state.timeout = $timeout(angular.bind(this, function holdDelayFn() {\n          this.dispatchEvent(ev, '$md.hold');\n          this.cancel(); // we're done!\n        }), this.state.options.delay, false);\n      },\n      onMove: function (ev, pointer) {\n        // Don't scroll while waiting for hold.\n        // If we don't preventDefault touchmove events here, Android will assume we don't\n        // want to listen to anymore touch events. It will start scrolling and stop sending\n        // touchmove events.\n        if (!touchActionProperty && ev.type === 'touchmove') ev.preventDefault();\n\n        // If the user moves greater than <maxDistance> pixels, stop the hold timer\n        // set in onStart\n        var dx = this.state.pos.x - pointer.x;\n        var dy = this.state.pos.y - pointer.y;\n        if (Math.sqrt(dx * dx + dy * dy) > this.options.maxDistance) {\n          this.cancel();\n        }\n      },\n      onEnd: function () {\n        this.onCancel();\n      }\n    })\n\n    /*\n     * The drag handler dispatches a drag event if the user holds and moves his finger greater than\n     * <minDistance> px in the x or y direction, depending on options.horizontal.\n     * The drag will be cancelled if the user moves his finger greater than <minDistance>*<cancelMultiplier> in\n     * the perpendicular direction. Eg if the drag is horizontal and the user moves his finger <minDistance>*<cancelMultiplier>\n     * pixels vertically, this handler won't consider the move part of a drag.\n     */\n    .handler('drag', {\n      options: {\n        minDistance: 6,\n        horizontal: true,\n        cancelMultiplier: 1.5\n      },\n      /**\n       * @param {angular.JQLite} element where touch action styles need to be adjusted\n       * @param {{horizontal: boolean}=} options object whose horizontal property can specify to\n       *  apply 'pan-y' or 'pan-x' touch actions.\n       */\n      onSetup: function(element, options) {\n        if (touchActionProperty) {\n          // We check for horizontal to be false, because otherwise we would overwrite the default opts.\n          this.oldTouchAction = element[0].style[touchActionProperty];\n          element[0].style[touchActionProperty] = options.horizontal ? 'pan-y' : 'pan-x';\n        }\n      },\n      /**\n       * @param {angular.JQLite} element where styles need to be cleaned up\n       */\n      onCleanup: function(element) {\n        if (this.oldTouchAction) {\n          element[0].style[touchActionProperty] = this.oldTouchAction;\n        } else {\n          element[0].style[touchActionProperty] = null;\n        }\n      },\n      onStart: function (ev) {\n        // For drag, require a parent to be registered with $mdGesture.register()\n        if (!this.state.registeredParent) this.cancel();\n      },\n      onMove: function (ev, pointer) {\n        var shouldStartDrag, shouldCancel;\n        // Don't scroll while deciding if this touchmove qualifies as a drag event.\n        // If we don't preventDefault touchmove events here, Android will assume we don't\n        // want to listen to anymore touch events. It will start scrolling and stop sending\n        // touchmove events.\n        if (!touchActionProperty && ev.type === 'touchmove') ev.preventDefault();\n\n        if (!this.state.dragPointer) {\n          if (this.state.options.horizontal) {\n            shouldStartDrag = Math.abs(pointer.distanceX) > this.state.options.minDistance;\n            shouldCancel = Math.abs(pointer.distanceY) > this.state.options.minDistance * this.state.options.cancelMultiplier;\n          } else {\n            shouldStartDrag = Math.abs(pointer.distanceY) > this.state.options.minDistance;\n            shouldCancel = Math.abs(pointer.distanceX) > this.state.options.minDistance * this.state.options.cancelMultiplier;\n          }\n\n          if (shouldStartDrag) {\n            // Create a new pointer representing this drag, starting at this point where the drag started.\n            this.state.dragPointer = makeStartPointer(ev);\n            updatePointerState(ev, this.state.dragPointer);\n            this.dispatchEvent(ev, '$md.dragstart', this.state.dragPointer);\n\n          } else if (shouldCancel) {\n            this.cancel();\n          }\n        } else {\n          this.dispatchDragMove(ev);\n        }\n      },\n      // Only dispatch dragmove events every frame; any more is unnecessary\n      dispatchDragMove: $$rAF.throttle(function (ev) {\n        // Make sure the drag didn't stop while waiting for the next frame\n        if (this.state.isRunning) {\n          updatePointerState(ev, this.state.dragPointer);\n          this.dispatchEvent(ev, '$md.drag', this.state.dragPointer);\n        }\n      }),\n      onEnd: function (ev, pointer) {\n        if (this.state.dragPointer) {\n          updatePointerState(ev, this.state.dragPointer);\n          this.dispatchEvent(ev, '$md.dragend', this.state.dragPointer);\n        }\n      }\n    })\n\n    /*\n     * The swipe handler will dispatch a swipe event if, on the end of a touch,\n     * the velocity and distance were high enough.\n     */\n    .handler('swipe', {\n      options: {\n        minVelocity: 0.65,\n        minDistance: 10\n      },\n      onEnd: function (ev, pointer) {\n        var eventType;\n\n        if (Math.abs(pointer.velocityX) > this.state.options.minVelocity &&\n          Math.abs(pointer.distanceX) > this.state.options.minDistance) {\n          eventType = pointer.directionX == 'left' ? '$md.swipeleft' : '$md.swiperight';\n          this.dispatchEvent(ev, eventType);\n        }\n        else if (Math.abs(pointer.velocityY) > this.state.options.minVelocity &&\n          Math.abs(pointer.distanceY) > this.state.options.minDistance) {\n          eventType = pointer.directionY == 'up' ? '$md.swipeup' : '$md.swipedown';\n          this.dispatchEvent(ev, eventType);\n        }\n      }\n    });\n}\n\n/**\n * MdGestureHandler\n * A GestureHandler is an object which is able to dispatch custom dom events\n * based on native dom {touch,pointer,mouse}{start,move,end} events.\n *\n * A gesture will manage its lifecycle through the start,move,end, and cancel\n * functions, which are called by native dom events.\n *\n * A gesture has the concept of 'options' (eg. a swipe's required velocity), which can be\n * overridden by elements registering through $mdGesture.register().\n */\nfunction GestureHandler (name) {\n  this.name = name;\n  this.state = {};\n}\n\nfunction MdGestureHandler() {\n  var hasJQuery =  (typeof window.jQuery !== 'undefined') && (angular.element === window.jQuery);\n\n  GestureHandler.prototype = {\n    options: {},\n    // jQuery listeners don't work with custom DOMEvents, so we have to dispatch events\n    // differently when jQuery is loaded\n    dispatchEvent: hasJQuery ?  jQueryDispatchEvent : nativeDispatchEvent,\n\n    // These are overridden by the registered handler\n    onSetup: angular.noop,\n    onCleanup: angular.noop,\n    onStart: angular.noop,\n    onMove: angular.noop,\n    onEnd: angular.noop,\n    onCancel: angular.noop,\n\n    // onStart sets up a new state for the handler, which includes options from the\n    // nearest registered parent element of ev.target.\n    start: function (ev, pointer) {\n      if (this.state.isRunning) return;\n      var parentTarget = this.getNearestParent(ev.target);\n      // Get the options from the nearest registered parent\n      var parentTargetOptions = parentTarget && parentTarget.$mdGesture[this.name] || {};\n\n      this.state = {\n        isRunning: true,\n        // Override the default options with the nearest registered parent's options\n        options: angular.extend({}, this.options, parentTargetOptions),\n        // Pass in the registered parent node to the state so the onStart listener can use\n        registeredParent: parentTarget\n      };\n      this.onStart(ev, pointer);\n    },\n    move: function (ev, pointer) {\n      if (!this.state.isRunning) return;\n      this.onMove(ev, pointer);\n    },\n    end: function (ev, pointer) {\n      if (!this.state.isRunning) return;\n      this.state.isRunning = false;\n      this.onEnd(ev, pointer);\n    },\n    cancel: function (ev, pointer) {\n      this.onCancel(ev, pointer);\n      this.state = {};\n    },\n\n    // Find and return the nearest parent element that has been registered to\n    // listen for this handler via $mdGesture.register(element, 'handlerName').\n    getNearestParent: function (node) {\n      var current = node;\n      while (current) {\n        if ((current.$mdGesture || {})[this.name]) {\n          return current;\n        }\n        current = current.parentNode;\n      }\n      return null;\n    },\n\n    // Called from $mdGesture.register when an element registers itself with a handler.\n    // Store the options the user gave on the DOMElement itself. These options will\n    // be retrieved with getNearestParent when the handler starts.\n    registerElement: function (element, options) {\n      var self = this;\n      element[0].$mdGesture = element[0].$mdGesture || {};\n      element[0].$mdGesture[this.name] = options || {};\n      element.on('$destroy', onDestroy);\n\n      self.onSetup(element, options || {});\n\n      return onDestroy;\n\n      function onDestroy() {\n        delete element[0].$mdGesture[self.name];\n        element.off('$destroy', onDestroy);\n\n        self.onCleanup(element, options || {});\n      }\n    }\n  };\n\n  return GestureHandler;\n\n  /**\n   * Dispatch an event with jQuery\n   * TODO: Make sure this sends bubbling events\n   *\n   * @param srcEvent the original DOM touch event that started this.\n   * @param eventType the name of the custom event to send (eg 'click' or '$md.drag')\n   * @param eventPointer the pointer object that matches this event.\n   */\n  function jQueryDispatchEvent(srcEvent, eventType, eventPointer) {\n    eventPointer = eventPointer || pointer;\n    var eventObj = new angular.element.Event(eventType);\n\n    eventObj.$material = true;\n    eventObj.pointer = eventPointer;\n    eventObj.srcEvent = srcEvent;\n\n    angular.extend(eventObj, {\n      clientX: eventPointer.x,\n      clientY: eventPointer.y,\n      screenX: eventPointer.x,\n      screenY: eventPointer.y,\n      pageX: eventPointer.x,\n      pageY: eventPointer.y,\n      ctrlKey: srcEvent.ctrlKey,\n      altKey: srcEvent.altKey,\n      shiftKey: srcEvent.shiftKey,\n      metaKey: srcEvent.metaKey\n    });\n    angular.element(eventPointer.target).trigger(eventObj);\n  }\n\n  /**\n   * NOTE: nativeDispatchEvent is very performance sensitive.\n   * @param srcEvent the original DOM touch event that started this.\n   * @param eventType the name of the custom event to send (eg 'click' or '$md.drag')\n   * @param eventPointer the pointer object that matches this event.\n   */\n  function nativeDispatchEvent(srcEvent, eventType, eventPointer) {\n    eventPointer = eventPointer || pointer;\n    var eventObj;\n\n    if (eventType === 'click' || eventType === 'mouseup' || eventType === 'mousedown') {\n      if (typeof window.MouseEvent === \"function\") {\n        eventObj = new MouseEvent(eventType, {\n          bubbles: true,\n          cancelable: true,\n          screenX: Number(srcEvent.screenX),\n          screenY: Number(srcEvent.screenY),\n          clientX: Number(eventPointer.x),\n          clientY: Number(eventPointer.y),\n          ctrlKey: srcEvent.ctrlKey,\n          altKey: srcEvent.altKey,\n          shiftKey: srcEvent.shiftKey,\n          metaKey: srcEvent.metaKey,\n          button: srcEvent.button,\n          buttons: srcEvent.buttons,\n          relatedTarget: srcEvent.relatedTarget || null\n        });\n      } else {\n        eventObj = document.createEvent('MouseEvents');\n        // This has been deprecated\n        // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent\n        eventObj.initMouseEvent(\n          eventType, true, true, window, srcEvent.detail,\n          eventPointer.x, eventPointer.y, eventPointer.x, eventPointer.y,\n          srcEvent.ctrlKey, srcEvent.altKey, srcEvent.shiftKey, srcEvent.metaKey,\n          srcEvent.button, srcEvent.relatedTarget || null\n        );\n      }\n    } else {\n      if (typeof window.CustomEvent === \"function\") {\n        eventObj = new CustomEvent(eventType, {\n          bubbles: true,\n          cancelable: true,\n          detail: {}\n        });\n      } else {\n        // This has been deprecated\n        // https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/initCustomEvent\n        eventObj = document.createEvent('CustomEvent');\n        eventObj.initCustomEvent(eventType, true, true, {});\n      }\n    }\n    eventObj.$material = true;\n    eventObj.pointer = eventPointer;\n    eventObj.srcEvent = srcEvent;\n    eventPointer.target.dispatchEvent(eventObj);\n  }\n}\n\n/**\n * Attach Gestures: hook document and check shouldHijack clicks\n * @ngInject\n */\nfunction attachToDocument($mdGesture, $$MdGestureHandler, $mdUtil) {\n  if (disableAllGestures) {\n    return;\n  }\n\n  if (!isInitialized && $mdGesture.isHijackingClicks) {\n    /*\n     * If hijack clicks is true, we preventDefault any click that wasn't\n     * sent by AngularJS Material. This is because on older Android & iOS, a false, or 'ghost',\n     * click event will be sent ~400ms after a touchend event happens.\n     * The only way to know if this click is real is to prevent any normal\n     * click events, and add a flag to events sent by material so we know not to prevent those.\n     *\n     * Two exceptions to click events that should be prevented are:\n     *  - click events sent by the keyboard (eg form submit)\n     *  - events that originate from an Ionic app\n     */\n    document.addEventListener('click'    , clickHijacker     , true);\n    document.addEventListener('mouseup'  , mouseInputHijacker, true);\n    document.addEventListener('mousedown', mouseInputHijacker, true);\n    document.addEventListener('focus'    , mouseInputHijacker, true);\n\n    isInitialized = true;\n  }\n\n  function mouseInputHijacker(ev) {\n    var isKeyClick = !ev.clientX && !ev.clientY;\n\n    if (\n      !isKeyClick &&\n      !ev.$material &&\n      !ev.isIonicTap &&\n      !isInputEventFromLabelClick(ev) &&\n      (ev.type !== 'mousedown' || (!canFocus(ev.target) && !canFocus(document.activeElement)))\n    ) {\n      ev.preventDefault();\n      ev.stopPropagation();\n    }\n  }\n\n  /**\n   * Ignore click events that don't come from AngularJS Material, Ionic, Input Label clicks,\n   * or key presses that generate click events. This helps to ignore the ghost tap events on\n   * older mobile browsers that get sent after a 300-400ms delay.\n   * @param ev MouseEvent or modified MouseEvent with $material, pointer, and other fields\n   */\n  function clickHijacker(ev) {\n    var isKeyClick;\n    if ($mdUtil.isIos) {\n      isKeyClick = angular.isDefined(ev.webkitForce) && ev.webkitForce === 0;\n    } else {\n      isKeyClick = ev.clientX === 0 && ev.clientY === 0;\n    }\n    if (!isKeyClick && !ev.$material && !ev.isIonicTap && !isInputEventFromLabelClick(ev)) {\n      ev.preventDefault();\n      ev.stopPropagation();\n      lastLabelClickPos = null;\n    } else {\n      lastLabelClickPos = null;\n      if (ev.target.tagName.toLowerCase() === 'label') {\n        lastLabelClickPos = {x: ev.x, y: ev.y};\n      }\n    }\n  }\n\n\n  // Listen to all events to cover all platforms.\n  var START_EVENTS = 'mousedown touchstart pointerdown';\n  var MOVE_EVENTS = 'mousemove touchmove pointermove';\n  var END_EVENTS = 'mouseup mouseleave touchend touchcancel pointerup pointercancel';\n\n  angular.element(document)\n    .on(START_EVENTS, gestureStart)\n    .on(MOVE_EVENTS, gestureMove)\n    .on(END_EVENTS, gestureEnd)\n    // For testing\n    .on('$$mdGestureReset', function gestureClearCache () {\n      lastPointer = pointer = null;\n    });\n\n  /**\n   * When a DOM event happens, run all registered gesture handlers' lifecycle\n   * methods which match the DOM event.\n   * Eg. when a 'touchstart' event happens, runHandlers('start') will call and\n   * run `handler.cancel()` and `handler.start()` on all registered handlers.\n   */\n  function runHandlers(handlerEvent, event) {\n    var handler;\n    for (var name in HANDLERS) {\n      handler = HANDLERS[name];\n      if (handler instanceof $$MdGestureHandler) {\n\n        if (handlerEvent === 'start') {\n          // Run cancel to reset any handlers' state\n          handler.cancel();\n        }\n        handler[handlerEvent](event, pointer);\n      }\n    }\n  }\n\n  /*\n   * gestureStart vets if a start event is legitimate (and not part of a 'ghost click' from iOS/Android)\n   * If it is legitimate, we initiate the pointer state and mark the current pointer's type\n   * For example, for a touchstart event, mark the current pointer as a 'touch' pointer, so mouse events\n   * won't effect it.\n   */\n  function gestureStart(ev) {\n    // If we're already touched down, abort\n    if (pointer) return;\n\n    var now = +Date.now();\n\n    // iOS & old android bug: after a touch event, a click event is sent 350 ms later.\n    // If <400ms have passed, don't allow an event of a different type than the previous event\n    if (lastPointer && !typesMatch(ev, lastPointer) && (now - lastPointer.endTime < 1500)) {\n      return;\n    }\n\n    pointer = makeStartPointer(ev);\n\n    runHandlers('start', ev);\n  }\n\n  /**\n   * If a move event happens of the right type, update the pointer and run all the move handlers.\n   * \"of the right type\": if a mousemove happens but our pointer started with a touch event, do\n   * nothing.\n   */\n  function gestureMove(ev) {\n    if (!pointer || !typesMatch(ev, pointer)) return;\n\n    updatePointerState(ev, pointer);\n    runHandlers('move', ev);\n  }\n\n  /**\n   * If an end event happens of the right type, update the pointer, run endHandlers, and save the\n   * pointer as 'lastPointer'.\n   */\n  function gestureEnd(ev) {\n    if (!pointer || !typesMatch(ev, pointer)) return;\n\n    updatePointerState(ev, pointer);\n    pointer.endTime = +Date.now();\n\n    if (ev.type !== 'pointercancel') {\n      runHandlers('end', ev);\n    }\n\n    lastPointer = pointer;\n    pointer = null;\n  }\n\n}\n\n// ********************\n// Module Functions\n// ********************\n\n/*\n * Initiate the pointer. x, y, and the pointer's type.\n */\nfunction makeStartPointer(ev) {\n  var point = getEventPoint(ev);\n  var startPointer = {\n    startTime: +Date.now(),\n    target: ev.target,\n    // 'p' for pointer events, 'm' for mouse, 't' for touch\n    type: ev.type.charAt(0)\n  };\n  startPointer.startX = startPointer.x = point.pageX;\n  startPointer.startY = startPointer.y = point.pageY;\n  return startPointer;\n}\n\n/*\n * return whether the pointer's type matches the event's type.\n * Eg if a touch event happens but the pointer has a mouse type, return false.\n */\nfunction typesMatch(ev, pointer) {\n  return ev && pointer && ev.type.charAt(0) === pointer.type;\n}\n\n/**\n * Gets whether the given event is an input event that was caused by clicking on an\n * associated label element.\n *\n * This is necessary because the browser will, upon clicking on a label element, fire an\n * *extra* click event on its associated input (if any). mdGesture is able to flag the label\n * click as with `$material` correctly, but not the second input click.\n *\n * In order to determine whether an input event is from a label click, we compare the (x, y) for\n * the event to the (x, y) for the most recent label click (which is cleared whenever a non-label\n * click occurs). Unfortunately, there are no event properties that tie the input and the label\n * together (such as relatedTarget).\n *\n * @param {MouseEvent} event\n * @returns {boolean}\n */\nfunction isInputEventFromLabelClick(event) {\n  return lastLabelClickPos\n      && lastLabelClickPos.x === event.x\n      && lastLabelClickPos.y === event.y;\n}\n\n/*\n * Update the given pointer based upon the given DOMEvent.\n * Distance, velocity, direction, duration, etc\n */\nfunction updatePointerState(ev, pointer) {\n  var point = getEventPoint(ev);\n  var x = pointer.x = point.pageX;\n  var y = pointer.y = point.pageY;\n\n  pointer.distanceX = x - pointer.startX;\n  pointer.distanceY = y - pointer.startY;\n  pointer.distance = Math.sqrt(\n    pointer.distanceX * pointer.distanceX + pointer.distanceY * pointer.distanceY\n  );\n\n  pointer.directionX = pointer.distanceX > 0 ? 'right' : pointer.distanceX < 0 ? 'left' : '';\n  pointer.directionY = pointer.distanceY > 0 ? 'down' : pointer.distanceY < 0 ? 'up' : '';\n\n  pointer.duration = +Date.now() - pointer.startTime;\n  pointer.velocityX = pointer.distanceX / pointer.duration;\n  pointer.velocityY = pointer.distanceY / pointer.duration;\n}\n\n/**\n * Normalize the point where the DOM event happened whether it's touch or mouse.\n * @returns point event obj with pageX and pageY on it.\n */\nfunction getEventPoint(ev) {\n  ev = ev.originalEvent || ev; // support jQuery events\n  return (ev.touches && ev.touches[0]) ||\n    (ev.changedTouches && ev.changedTouches[0]) ||\n    ev;\n}\n\n/** Checks whether an element can be focused. */\nfunction canFocus(element) {\n  return (\n    !!element &&\n    element.getAttribute('tabindex') !== '-1' &&\n    !element.hasAttribute('disabled') &&\n    (\n      element.hasAttribute('tabindex') ||\n      element.hasAttribute('href') ||\n      element.isContentEditable ||\n      ['INPUT', 'SELECT', 'BUTTON', 'TEXTAREA', 'VIDEO', 'AUDIO'].indexOf(element.nodeName) !== -1\n    )\n  );\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.core.interaction\n * @description\n * User interaction detection to provide proper accessibility.\n */\nMdInteractionService.$inject = [\"$timeout\", \"$mdUtil\", \"$rootScope\"];\nangular\n  .module('material.core.interaction', [])\n  .service('$mdInteraction', MdInteractionService);\n\n\n/**\n * @ngdoc service\n * @name $mdInteraction\n * @module material.core.interaction\n *\n * @description\n *\n * Service which keeps track of the last interaction type and validates them for several browsers.\n * The service hooks into the document's body and listens for touch, mouse and keyboard events.\n *\n * The most recent interaction type can be retrieved by calling the `getLastInteractionType` method.\n *\n * Here is an example markup for using the interaction service.\n *\n * <hljs lang=\"js\">\n *   var lastType = $mdInteraction.getLastInteractionType();\n *\n *   if (lastType === 'keyboard') {\n *     // We only restore the focus for keyboard users.\n *     restoreFocus();\n *   }\n * </hljs>\n *\n */\nfunction MdInteractionService($timeout, $mdUtil, $rootScope) {\n  this.$timeout = $timeout;\n  this.$mdUtil = $mdUtil;\n  this.$rootScope = $rootScope;\n\n  // IE browsers can also trigger pointer events, which also leads to an interaction.\n  this.pointerEvent = 'MSPointerEvent' in window ? 'MSPointerDown' : 'PointerEvent' in window ? 'pointerdown' : null;\n  this.bodyElement = angular.element(document.body);\n  this.isBuffering = false;\n  this.bufferTimeout = null;\n  this.lastInteractionType = null;\n  this.lastInteractionTime = null;\n  this.inputHandler = this.onInputEvent.bind(this);\n  this.bufferedInputHandler = this.onBufferInputEvent.bind(this);\n\n  // Type Mappings for the different events\n  // There will be three three interaction types\n  // `keyboard`, `mouse` and `touch`\n  // type `pointer` will be evaluated in `pointerMap` for IE Browser events\n  this.inputEventMap = {\n    'keydown': 'keyboard',\n    'mousedown': 'mouse',\n    'mouseenter': 'mouse',\n    'touchstart': 'touch',\n    'pointerdown': 'pointer',\n    'MSPointerDown': 'pointer'\n  };\n\n  // IE PointerDown events will be validated in `touch` or `mouse`\n  // Index numbers referenced here: https://msdn.microsoft.com/library/windows/apps/hh466130.aspx\n  this.iePointerMap = {\n    2: 'touch',\n    3: 'touch',\n    4: 'mouse'\n  };\n\n  this.initializeEvents();\n  this.$rootScope.$on('$destroy', this.deregister.bind(this));\n}\n\n/**\n * Removes all event listeners created by $mdInteration on the\n * body element.\n */\nMdInteractionService.prototype.deregister = function() {\n\n    this.bodyElement.off('keydown mousedown', this.inputHandler);\n\n    if ('ontouchstart' in document.documentElement) {\n      this.bodyElement.off('touchstart', this.bufferedInputHandler);\n    }\n\n    if (this.pointerEvent) {\n      this.bodyElement.off(this.pointerEvent, this.inputHandler);\n    }\n\n};\n\n/**\n * Initializes the interaction service, by registering all interaction events to the\n * body element.\n */\nMdInteractionService.prototype.initializeEvents = function() {\n\n  this.bodyElement.on('keydown mousedown', this.inputHandler);\n\n  if ('ontouchstart' in document.documentElement) {\n    this.bodyElement.on('touchstart', this.bufferedInputHandler);\n  }\n\n  if (this.pointerEvent) {\n    this.bodyElement.on(this.pointerEvent, this.inputHandler);\n  }\n\n};\n\n/**\n * Event listener for normal interaction events, which should be tracked.\n * @param event {MouseEvent|KeyboardEvent|PointerEvent|TouchEvent}\n */\nMdInteractionService.prototype.onInputEvent = function(event) {\n  if (this.isBuffering) {\n    return;\n  }\n\n  var type = this.inputEventMap[event.type];\n\n  if (type === 'pointer') {\n    type = this.iePointerMap[event.pointerType] || event.pointerType;\n  }\n\n  this.lastInteractionType = type;\n  this.lastInteractionTime = this.$mdUtil.now();\n};\n\n/**\n * Event listener for interaction events which should be buffered (touch events).\n * @param event {TouchEvent}\n */\nMdInteractionService.prototype.onBufferInputEvent = function(event) {\n  this.$timeout.cancel(this.bufferTimeout);\n\n  this.onInputEvent(event);\n  this.isBuffering = true;\n\n  // The timeout of 650ms is needed to delay the touchstart, because otherwise the touch will call\n  // the `onInput` function multiple times.\n  this.bufferTimeout = this.$timeout(function() {\n    this.isBuffering = false;\n  }.bind(this), 650, false);\n\n};\n\n/**\n * @ngdoc method\n * @name $mdInteraction#getLastInteractionType\n * @description Retrieves the last interaction type triggered in body.\n * @returns {string|null} Last interaction type.\n */\nMdInteractionService.prototype.getLastInteractionType = function() {\n  return this.lastInteractionType;\n};\n\n/**\n * @ngdoc method\n * @name $mdInteraction#isUserInvoked\n * @description Method to detect whether any interaction happened recently or not.\n * @param {number=} checkDelay Time to check for any interaction to have been triggered.\n * @returns {boolean} Whether there was any interaction or not.\n */\nMdInteractionService.prototype.isUserInvoked = function(checkDelay) {\n  var delay = angular.isNumber(checkDelay) ? checkDelay : 15;\n\n  // Check for any interaction to be within the specified check time.\n  return this.lastInteractionTime >= this.$mdUtil.now() - delay;\n};\n\n})();\n(function(){\n\"use strict\";\n\nangular.module('material.core')\n  .provider('$$interimElement', InterimElementProvider);\n\n/**\n * @ngdoc service\n * @name $$interimElementProvider\n * @module material.core.interimElement\n *\n * @description\n *\n * Factory that constructs `$$interimElement.$service` services.\n * Used internally in material design for elements that appear on screen temporarily.\n * The service provides a promise-like API for interacting with the temporary\n * elements.\n *\n * <hljs lang=\"js\">\n *   app.service('$mdToast', function($$interimElement) {\n *     var $mdToast = $$interimElement(toastDefaultOptions);\n *     return $mdToast;\n *   });\n * </hljs>\n *\n * @param {object=} defaultOptions Options used by default for the `show` method on the service.\n *\n * @returns {$$interimElement.$service}\n */\n\nfunction InterimElementProvider() {\n  InterimElementFactory.$inject = [\"$document\", \"$q\", \"$rootScope\", \"$timeout\", \"$rootElement\", \"$animate\", \"$mdUtil\", \"$mdCompiler\", \"$mdTheming\", \"$injector\", \"$exceptionHandler\"];\n  createInterimElementProvider.$get = InterimElementFactory;\n  return createInterimElementProvider;\n\n  /**\n   * Returns a new provider which allows configuration of a new interimElement\n   * service. Allows configuration of default options & methods for options,\n   * as well as configuration of 'preset' methods (eg dialog.basic(): basic is a preset method)\n   */\n  function createInterimElementProvider(interimFactoryName) {\n    factory.$inject = [\"$$interimElement\", \"$injector\"];\n    var EXPOSED_METHODS = ['onHide', 'onShow', 'onRemove'];\n\n    var customMethods = {};\n    var providerConfig = {\n      presets: {}\n    };\n\n    var provider = {\n      setDefaults: setDefaults,\n      addPreset: addPreset,\n      addMethod: addMethod,\n      $get: factory\n    };\n\n    /**\n     * all interim elements will come with the 'build' preset\n     */\n    provider.addPreset('build', {\n      methods: ['controller', 'controllerAs', 'resolve', 'multiple',\n        'template', 'templateUrl', 'themable', 'transformTemplate', 'parent', 'contentElement']\n    });\n\n    return provider;\n\n    /**\n     * Save the configured defaults to be used when the factory is instantiated\n     */\n    function setDefaults(definition) {\n      providerConfig.optionsFactory = definition.options;\n      providerConfig.methods = (definition.methods || []).concat(EXPOSED_METHODS);\n      return provider;\n    }\n\n    /**\n     * Add a method to the factory that isn't specific to any interim element operations\n     */\n    function addMethod(name, fn) {\n      customMethods[name] = fn;\n      return provider;\n    }\n\n    /**\n     * Save the configured preset to be used when the factory is instantiated\n     */\n    function addPreset(name, definition) {\n      definition = definition || {};\n      definition.methods = definition.methods || [];\n      definition.options = definition.options || function() { return {}; };\n\n      if (/^cancel|hide|show$/.test(name)) {\n        throw new Error(\"Preset '\" + name + \"' in \" + interimFactoryName + \" is reserved!\");\n      }\n      if (definition.methods.indexOf('_options') > -1) {\n        throw new Error(\"Method '_options' in \" + interimFactoryName + \" is reserved!\");\n      }\n      providerConfig.presets[name] = {\n        methods: definition.methods.concat(EXPOSED_METHODS),\n        optionsFactory: definition.options,\n        argOption: definition.argOption\n      };\n      return provider;\n    }\n\n    function addPresetMethod(presetName, methodName, method) {\n      providerConfig.presets[presetName][methodName] = method;\n    }\n\n    /**\n     * Create a factory that has the given methods & defaults implementing interimElement\n     */\n    /* @ngInject */\n    function factory($$interimElement, $injector) {\n      var defaultMethods;\n      var defaultOptions;\n      var interimElementService = $$interimElement();\n\n      /*\n       * publicService is what the developer will be using.\n       * It has methods hide(), cancel(), show(), build(), and any other\n       * presets which were set during the config phase.\n       */\n      var publicService = {\n        hide: interimElementService.hide,\n        cancel: interimElementService.cancel,\n        show: showInterimElement,\n\n        // Special internal method to destroy an interim element without animations\n        // used when navigation changes causes a $scope.$destroy() action\n        destroy : destroyInterimElement\n      };\n\n\n      defaultMethods = providerConfig.methods || [];\n      // This must be invoked after the publicService is initialized\n      defaultOptions = invokeFactory(providerConfig.optionsFactory, {});\n\n      // Copy over the simple custom methods\n      angular.forEach(customMethods, function(fn, name) {\n        publicService[name] = fn;\n      });\n\n      angular.forEach(providerConfig.presets, function(definition, name) {\n        var presetDefaults = invokeFactory(definition.optionsFactory, {});\n        var presetMethods = (definition.methods || []).concat(defaultMethods);\n\n        // Every interimElement built with a preset has a field called `$type`,\n        // which matches the name of the preset.\n        // Eg in preset 'confirm', options.$type === 'confirm'\n        angular.extend(presetDefaults, { $type: name });\n\n        // This creates a preset class which has setter methods for every\n        // method given in the `.addPreset()` function, as well as every\n        // method given in the `.setDefaults()` function.\n        //\n        // @example\n        // .setDefaults({\n        //   methods: ['hasBackdrop', 'clickOutsideToClose', 'escapeToClose', 'targetEvent'],\n        //   options: dialogDefaultOptions\n        // })\n        // .addPreset('alert', {\n        //   methods: ['title', 'ok'],\n        //   options: alertDialogOptions\n        // })\n        //\n        // Set values will be passed to the options when interimElement.show() is called.\n        function Preset(opts) {\n          this._options = angular.extend({}, presetDefaults, opts);\n        }\n        angular.forEach(presetMethods, function(name) {\n          Preset.prototype[name] = function(value) {\n            this._options[name] = value;\n            return this;\n          };\n        });\n\n        // Create shortcut method for one-linear methods\n        if (definition.argOption) {\n          var methodName = 'show' + name.charAt(0).toUpperCase() + name.slice(1);\n          publicService[methodName] = function(arg) {\n            var config = publicService[name](arg);\n            return publicService.show(config);\n          };\n        }\n\n        // eg $mdDialog.alert() will return a new alert preset\n        publicService[name] = function(arg) {\n          // If argOption is supplied, eg `argOption: 'content'`, then we assume\n          // if the argument is not an options object then it is the `argOption` option.\n          //\n          // @example `$mdToast.simple('hello')` // sets options.content to hello\n          //                                     // because argOption === 'content'\n          if (arguments.length && definition.argOption &&\n              !angular.isObject(arg) && !angular.isArray(arg))  {\n\n            return (new Preset())[definition.argOption](arg);\n\n          } else {\n            return new Preset(arg);\n          }\n\n        };\n      });\n\n      return publicService;\n\n      /**\n       *\n       */\n      function showInterimElement(opts) {\n        // opts is either a preset which stores its options on an _options field,\n        // or just an object made up of options\n        opts = opts || { };\n        if (opts._options) opts = opts._options;\n\n        return interimElementService.show(\n          angular.extend({}, defaultOptions, opts)\n        );\n      }\n\n      /**\n       *  Special method to hide and destroy an interimElement WITHOUT\n       *  any 'leave` or hide animations ( an immediate force hide/remove )\n       *\n       *  NOTE: This calls the onRemove() subclass method for each component...\n       *  which must have code to respond to `options.$destroy == true`\n       */\n      function destroyInterimElement(opts) {\n          return interimElementService.destroy(opts);\n      }\n\n      /**\n       * Helper to call $injector.invoke with a local of the factory name for\n       * this provider.\n       * If an $mdDialog is providing options for a dialog and tries to inject\n       * $mdDialog, a circular dependency error will happen.\n       * We get around that by manually injecting $mdDialog as a local.\n       */\n      function invokeFactory(factory, defaultVal) {\n        var locals = {};\n        locals[interimFactoryName] = publicService;\n        return $injector.invoke(factory || function() { return defaultVal; }, {}, locals);\n      }\n    }\n  }\n\n  /* @ngInject */\n  function InterimElementFactory($document, $q, $rootScope, $timeout, $rootElement, $animate,\n                                 $mdUtil, $mdCompiler, $mdTheming, $injector, $exceptionHandler) {\n    return function createInterimElementService() {\n      var SHOW_CANCELLED = false;\n\n      /**\n       * @ngdoc service\n       * @name $$interimElementProvider.$service\n       *\n       * @description\n       * A service used to control inserting and removing of an element from the DOM.\n       * It is used by $mdBottomSheet, $mdDialog, $mdToast, $mdMenu, $mdPanel, and $mdSelect.\n       */\n      var service;\n\n      var showPromises = []; // Promises for the interim's which are currently opening.\n      var hidePromises = []; // Promises for the interim's which are currently hiding.\n      var showingInterims = []; // Interim elements which are currently showing up.\n\n      // Publish instance $$interimElement service;\n      return service = {\n        show: show,\n        hide: waitForInterim(hide),\n        cancel: waitForInterim(cancel),\n        destroy : destroy,\n        $injector_: $injector\n      };\n\n      /**\n       * @ngdoc method\n       * @name $$interimElementProvider.$service#show\n       * @kind function\n       *\n       * @description\n       * Adds the `$interimElement` to the DOM and returns a special promise that will be resolved\n       * or rejected with hide or cancel, respectively.\n       *\n       * @param {Object} options map of options and values\n       * @returns {Promise} a Promise that will be resolved when hide() is called or rejected when\n       *  cancel() is called.\n       */\n      function show(options) {\n        options = options || {};\n        var interimElement = new InterimElement(options || {});\n\n        // When an interim element is currently showing, we have to cancel it.\n        // Just hiding it, will resolve the InterimElement's promise, the promise should be\n        // rejected instead.\n        var hideAction = options.multiple ? $q.resolve() : $q.all(showPromises);\n\n        if (!options.multiple) {\n          // Wait for all opening interim's to finish their transition.\n          hideAction = hideAction.then(function() {\n            // Wait for all closing and showing interim's to be completely closed.\n            var promiseArray = hidePromises.concat(showingInterims.map(service.cancel));\n            return $q.all(promiseArray);\n          });\n        }\n\n        var showAction = hideAction.then(function() {\n\n          return interimElement\n            .show()\n            .then(function () {\n              showingInterims.push(interimElement);\n            })\n            .catch(function (reason) {\n              return reason;\n            })\n            .finally(function() {\n              showPromises.splice(showPromises.indexOf(showAction), 1);\n            });\n\n        });\n\n        showPromises.push(showAction);\n\n        // In AngularJS 1.6+, exceptions inside promises will cause a rejection. We need to handle\n        // the rejection and only log it if it's an error.\n        interimElement.deferred.promise.catch(function(fault) {\n          if (fault instanceof Error) {\n            $exceptionHandler(fault);\n          }\n\n          return fault;\n        });\n\n        // Return a promise that will be resolved when the interim\n        // element is hidden or cancelled...\n        return interimElement.deferred.promise;\n      }\n\n      /**\n       * @ngdoc method\n       * @name $$interimElementProvider.$service#hide\n       * @kind function\n       *\n       * @description\n       * Removes the `$interimElement` from the DOM and resolves the Promise returned from `show()`.\n       *\n       * @param {*} reason Data used to resolve the Promise\n       * @param {object} options map of options and values\n       * @returns {Promise} a Promise that will be resolved after the element has been removed\n       *  from the DOM.\n       */\n      function hide(reason, options) {\n        options = options || {};\n\n        if (options.closeAll) {\n          // We have to make a shallow copy of the array, because otherwise the map will break.\n          return $q.all(showingInterims.slice().reverse().map(closeElement));\n        } else if (options.closeTo !== undefined) {\n          return $q.all(showingInterims.slice(options.closeTo).map(closeElement));\n        }\n\n        // Hide the latest showing interim element.\n        return closeElement(showingInterims[showingInterims.length - 1]);\n\n        /**\n         * @param {InterimElement} interim element to close\n         * @returns {Promise<InterimElement>}\n         */\n        function closeElement(interim) {\n          if (!interim) {\n            return $q.when(reason);\n          }\n\n          var hideAction = interim\n            .remove(reason, false, options || { })\n            .catch(function(reason) { return reason; })\n            .finally(function() {\n              hidePromises.splice(hidePromises.indexOf(hideAction), 1);\n            });\n\n          showingInterims.splice(showingInterims.indexOf(interim), 1);\n          hidePromises.push(hideAction);\n\n          return interim.deferred.promise;\n        }\n      }\n\n      /**\n       * @ngdoc method\n       * @name $$interimElementProvider.$service#cancel\n       * @kind function\n       *\n       * @description\n       * Removes the `$interimElement` from the DOM and rejects the Promise returned from `show()`.\n       *\n       * @param {*} reason Data used to resolve the Promise\n       * @param {object} options map of options and values\n       * @returns {Promise} Promise that will be resolved after the element has been removed\n       *  from the DOM.\n       */\n      function cancel(reason, options) {\n        var interim = showingInterims.pop();\n        if (!interim) {\n          return $q.when(reason);\n        }\n\n        var cancelAction = interim\n          .remove(reason, true, options || {})\n          .catch(function(reason) { return reason; })\n          .finally(function() {\n            hidePromises.splice(hidePromises.indexOf(cancelAction), 1);\n          });\n\n        hidePromises.push(cancelAction);\n\n        // Since AngularJS 1.6.7, promises will be logged to $exceptionHandler when the promise\n        // is not handling the rejection. We create a pseudo catch handler, which will prevent the\n        // promise from being logged to the $exceptionHandler.\n        return interim.deferred.promise.catch(angular.noop);\n      }\n\n      /**\n       * Creates a function to wait for at least one interim element to be available.\n       * @param callbackFn Function to be used as callback\n       * @returns {Function}\n       */\n      function waitForInterim(callbackFn) {\n        return function() {\n          var fnArguments = arguments;\n\n          if (!showingInterims.length) {\n            // When there are still interim's opening, then wait for the first interim element to\n            // finish its open animation.\n            if (showPromises.length) {\n              return showPromises[0].finally(function () {\n                return callbackFn.apply(service, fnArguments);\n              });\n            }\n\n            return $q.when(\"No interim elements currently showing up.\");\n          }\n\n          return callbackFn.apply(service, fnArguments);\n        };\n      }\n\n      /**\n       * @ngdoc method\n       * @name $$interimElementProvider.$service#destroy\n       * @kind function\n       *\n       * Special method to quick-remove the interim element without running animations. This is\n       * useful when the parent component has been or is being destroyed.\n       *\n       * Note: interim elements are in \"interim containers\".\n       */\n      function destroy(targetEl) {\n        var interim = !targetEl ? showingInterims.shift() : null;\n\n        var parentEl = angular.element(targetEl).length && angular.element(targetEl)[0].parentNode;\n\n        if (parentEl) {\n          // Try to find the interim in the stack which corresponds to the supplied DOM element.\n          var filtered = showingInterims.filter(function(entry) {\n            return entry.options.element[0] === parentEl;\n          });\n\n          // Note: This function might be called when the element already has been removed,\n          // in which case we won't find any matches.\n          if (filtered.length) {\n            interim = filtered[0];\n            showingInterims.splice(showingInterims.indexOf(interim), 1);\n          }\n        }\n\n        return interim ? interim.remove(SHOW_CANCELLED, false, { '$destroy': true }) :\n                         $q.when(SHOW_CANCELLED);\n      }\n\n      /*\n       * Internal Interim Element Object\n       * Used internally to manage the DOM element and related data\n       */\n      function InterimElement(options) {\n        var self, element, showAction = $q.when(true);\n\n        options = configureScopeAndTransitions(options);\n\n        return self = {\n          options : options,\n          deferred: $q.defer(),\n          show    : createAndTransitionIn,\n          remove  : transitionOutAndRemove\n        };\n\n        /**\n         * Compile, link, and show this interim element. Use optional autoHide and transition-in\n         * effects.\n         * @return {Q.Promise}\n         */\n        function createAndTransitionIn() {\n          return $q(function(resolve, reject) {\n\n            // Trigger onCompiling callback before the compilation starts.\n            // This is useful, when modifying options, which can be influenced by developers.\n            options.onCompiling && options.onCompiling(options);\n\n            compileElement(options)\n              .then(function(compiledData) {\n                element = linkElement(compiledData, options);\n\n                // Expose the cleanup function from the compiler.\n                options.cleanupElement = compiledData.cleanup;\n\n                showAction = showElement(element, options, compiledData.controller)\n                  .then(resolve, rejectAll);\n              }).catch(rejectAll);\n\n            function rejectAll(fault) {\n              // Force the '$md<xxx>.show()' promise to reject\n              self.deferred.reject(fault);\n\n              // Continue rejection propagation\n              reject(fault);\n            }\n          });\n        }\n\n        /**\n         * After the show process has finished/rejected:\n         * - announce 'removing',\n         * - perform the transition-out, and\n         * - perform optional clean up scope.\n         */\n        function transitionOutAndRemove(response, isCancelled, opts) {\n\n          // abort if the show() and compile failed\n          if (!element) return $q.when(false);\n\n          options = angular.extend(options || {}, opts || {});\n          options.cancelAutoHide && options.cancelAutoHide();\n          options.element.triggerHandler('$mdInterimElementRemove');\n\n          if (options.$destroy === true) {\n\n            return hideElement(options.element, options).then(function(){\n              (isCancelled && rejectAll(response)) || resolveAll(response);\n            });\n\n          } else {\n            $q.when(showAction).finally(function() {\n              hideElement(options.element, options).then(function() {\n                isCancelled ? rejectAll(response) : resolveAll(response);\n              }, rejectAll);\n            });\n\n            return self.deferred.promise;\n          }\n\n\n          /**\n           * The `show()` returns a promise that will be resolved when the interim\n           * element is hidden or cancelled...\n           */\n          function resolveAll(response) {\n            self.deferred.resolve(response);\n          }\n\n          /**\n           * Force the '$md<xxx>.show()' promise to reject\n           */\n          function rejectAll(fault) {\n            self.deferred.reject(fault);\n          }\n        }\n\n        /**\n         * Prepare optional isolated scope and prepare $animate with default enter and leave\n         * transitions for the new element instance.\n         */\n        function configureScopeAndTransitions(options) {\n          options = options || { };\n          if (options.template) {\n            options.template = $mdUtil.processTemplate(options.template);\n          }\n\n          return angular.extend({\n            preserveScope: false,\n            cancelAutoHide : angular.noop,\n            scope: options.scope || $rootScope.$new(options.isolateScope),\n\n            /**\n             * Default usage to enable $animate to transition-in; can be easily overridden via 'options'\n             */\n            onShow: function transitionIn(scope, element, options) {\n              return $animate.enter(element, options.parent);\n            },\n\n            /**\n             * Default usage to enable $animate to transition-out; can be easily overridden via 'options'\n             */\n            onRemove: function transitionOut(scope, element) {\n              // Element could be undefined if a new element is shown before\n              // the old one finishes compiling.\n              return element && $animate.leave(element) || $q.when();\n            }\n          }, options);\n\n        }\n\n        /**\n         * Compile an element with a templateUrl, controller, and locals\n         * @param {Object} options\n         * @return {Q.Promise<{element: JQLite=, link: Function, locals: Object, cleanup: any=,\n         *  controller: Object=}>}\n         */\n        function compileElement(options) {\n\n          var compiled = !options.skipCompile ? $mdCompiler.compile(options) : null;\n\n          return compiled || $q(function (resolve) {\n              resolve({\n                locals: {},\n                link: function () {\n                  return options.element;\n                }\n              });\n            });\n        }\n\n        /**\n         * Link an element with compiled configuration\n         * @param {{element: JQLite=, link: Function, locals: Object, controller: Object=}} compileData\n         * @param {Object} options\n         * @return {JQLite}\n         */\n        function linkElement(compileData, options) {\n          angular.extend(compileData.locals, options);\n\n          var element = compileData.link(options.scope);\n\n          // Search for parent at insertion time, if not specified\n          options.element = element;\n          options.parent = findParent(element, options);\n          if (options.themable) $mdTheming(element);\n\n          return element;\n        }\n\n        /**\n         * Search for parent at insertion time, if not specified.\n         * @param {JQLite} element\n         * @param {Object} options\n         * @return {JQLite}\n         */\n        function findParent(element, options) {\n          var parent = options.parent;\n\n          // Search for parent at insertion time, if not specified\n          if (angular.isFunction(parent)) {\n            parent = parent(options.scope, element, options);\n          } else if (angular.isString(parent)) {\n            parent = angular.element($document[0].querySelector(parent));\n          } else {\n            parent = angular.element(parent);\n          }\n\n          // If parent querySelector/getter function fails, or it's just null,\n          // find a default.\n          if (!(parent || {}).length) {\n            var el;\n            if ($rootElement[0] && $rootElement[0].querySelector) {\n              el = $rootElement[0].querySelector(':not(svg) > body');\n            }\n            if (!el) el = $rootElement[0];\n            if (el.nodeName === '#comment') {\n              el = $document[0].body;\n            }\n            return angular.element(el);\n          }\n\n          return parent;\n        }\n\n        /**\n         * If auto-hide is enabled, start timer and prepare cancel function\n         */\n        function startAutoHide() {\n          var autoHideTimer, cancelAutoHide = angular.noop;\n\n          if (options.hideDelay) {\n            autoHideTimer = $timeout(service.hide, options.hideDelay) ;\n            cancelAutoHide = function() {\n              $timeout.cancel(autoHideTimer);\n            };\n          }\n\n          // Cache for subsequent use\n          options.cancelAutoHide = function() {\n            cancelAutoHide();\n            options.cancelAutoHide = undefined;\n          };\n        }\n\n        /**\n         * Show the element (with transitions), notify complete and start optional auto hiding\n         * timer.\n         * @param {JQLite} element\n         * @param {Object} options\n         * @param {Object} controller\n         * @return {Q.Promise<JQLite>}\n         */\n        function showElement(element, options, controller) {\n          // Trigger onShowing callback before the `show()` starts\n          var notifyShowing = options.onShowing || angular.noop;\n          // Trigger onComplete callback when the `show()` finishes\n          var notifyComplete = options.onComplete || angular.noop;\n\n          // Necessary for consistency between AngularJS 1.5 and 1.6.\n          try {\n            // This fourth controller parameter is used by $mdDialog in beforeShow().\n            notifyShowing(options.scope, element, options, controller);\n          } catch (e) {\n            return $q.reject(e);\n          }\n\n          return $q(function (resolve, reject) {\n            try {\n              // Start transitionIn\n              $q.when(options.onShow(options.scope, element, options))\n                .then(function () {\n                  notifyComplete(options.scope, element, options);\n                  startAutoHide();\n\n                  resolve(element);\n                }, reject);\n\n            } catch (e) {\n              reject(e.message);\n            }\n          });\n        }\n\n        function hideElement(element, options) {\n          var announceRemoving = options.onRemoving || angular.noop;\n\n          return $q(function (resolve, reject) {\n            try {\n              // Start transitionIn\n              var action = $q.when(options.onRemove(options.scope, element, options) || true);\n\n              // Trigger callback *before* the remove operation starts\n              announceRemoving(element, action);\n\n              if (options.$destroy) {\n                // For $destroy, onRemove should be synchronous\n                resolve(element);\n\n                if (!options.preserveScope && options.scope) {\n                  // scope destroy should still be be done after the current digest is done\n                  action.then(function() { options.scope.$destroy(); });\n                }\n              } else {\n                // Wait until transition-out is done\n                action.then(function () {\n                  if (!options.preserveScope && options.scope) {\n                    options.scope.$destroy();\n                  }\n\n                  resolve(element);\n                }, reject);\n              }\n            } catch (e) {\n              reject(e.message);\n            }\n          });\n        }\n\n      }\n    };\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  var $mdUtil, $interpolate, $log;\n\n  var SUFFIXES = /(-gt)?-(sm|md|lg|print)/g;\n  var WHITESPACE = /\\s+/g;\n\n  var FLEX_OPTIONS = ['grow', 'initial', 'auto', 'none', 'noshrink', 'nogrow'];\n  var LAYOUT_OPTIONS = ['row', 'column'];\n  var ALIGNMENT_MAIN_AXIS= [\"\", \"start\", \"center\", \"end\", \"stretch\", \"space-around\", \"space-between\"];\n  var ALIGNMENT_CROSS_AXIS= [\"\", \"start\", \"center\", \"end\", \"stretch\"];\n\n  var config = {\n    /**\n     * Enable directive attribute-to-class conversions\n     * Developers can use `<body md-layout-css />` to quickly\n     * disable the Layout directives and prohibit the injection of Layout classNames\n     */\n    enabled: true,\n\n    /**\n     * List of mediaQuery breakpoints and associated suffixes\n     *   [\n     *    { suffix: \"sm\", mediaQuery: \"screen and (max-width: 599px)\" },\n     *    { suffix: \"md\", mediaQuery: \"screen and (min-width: 600px) and (max-width: 959px)\" }\n     *   ]\n     */\n    breakpoints: []\n  };\n\n  registerLayoutAPI(angular.module('material.core.layout', ['ng']));\n\n  /**\n   *   registerLayoutAPI()\n   *\n   *   The original AngularJS Material Layout solution used attribute selectors and CSS.\n   *\n   *  ```html\n   *  <div layout=\"column\"> My Content </div>\n   *  ```\n   *\n   *  ```css\n   *  [layout] {\n   *    box-sizing: border-box;\n   *    display:flex;\n   *  }\n   *  [layout=column] {\n   *    flex-direction : column\n   *  }\n   *  ```\n   *\n   *  Use of attribute selectors creates significant performance impacts in some\n   *  browsers... mainly IE.\n   *\n   *  This module registers directives that allow the same layout attributes to be\n   *  interpreted and converted to class selectors. The directive will add equivalent classes to\n   *  each element that contains a Layout directive.\n   *\n   * ```html\n   *   <div layout=\"column\" class=\"layout layout-column\"> My Content </div>\n   * ```\n   *\n   *  ```css\n   *  .layout {\n   *    box-sizing: border-box;\n   *    display:flex;\n   *  }\n   *  .layout-column {\n   *    flex-direction : column\n   *  }\n   *  ```\n   */\n  function registerLayoutAPI(module){\n    var PREFIX_REGEXP = /^((?:x|data)[:\\-_])/i;\n    var SPECIAL_CHARS_REGEXP = /([:\\-_]+(.))/g;\n\n    // NOTE: these are also defined in constants::MEDIA_PRIORITY and constants::MEDIA\n    var BREAKPOINTS     = [\"\", \"xs\", \"gt-xs\", \"sm\", \"gt-sm\", \"md\", \"gt-md\", \"lg\", \"gt-lg\", \"xl\", \"print\"];\n    var API_WITH_VALUES = [\"layout\", \"flex\", \"flex-order\", \"flex-offset\", \"layout-align\"];\n    var API_NO_VALUES   = [\"show\", \"hide\", \"layout-padding\", \"layout-margin\"];\n\n\n    // Build directive registration functions for the standard Layout API... for all breakpoints.\n    angular.forEach(BREAKPOINTS, function(mqb) {\n\n      // Attribute directives with expected, observable value(s)\n      angular.forEach(API_WITH_VALUES, function(name){\n        var fullName = mqb ? name + \"-\" + mqb : name;\n        module.directive(directiveNormalize(fullName), attributeWithObserve(fullName));\n      });\n\n      // Attribute directives with no expected value(s)\n      angular.forEach(API_NO_VALUES, function(name){\n        var fullName = mqb ? name + \"-\" + mqb : name;\n        module.directive(directiveNormalize(fullName), attributeWithoutValue(fullName));\n      });\n\n    });\n\n    // Register other, special directive functions for the Layout features:\n    module\n      .provider('$$mdLayout', function() {\n        // Publish internal service for Layouts\n        return {\n          $get : angular.noop,\n          validateAttributeValue : validateAttributeValue,\n          validateAttributeUsage : validateAttributeUsage,\n          /**\n           * Easy way to disable/enable the Layout API.\n           * When disabled, this stops all attribute-to-classname generations\n           */\n          disableLayouts  : function(isDisabled) {\n            config.enabled =  (isDisabled !== true);\n          }\n        };\n      })\n\n      .directive('mdLayoutCss'        , disableLayoutDirective)\n      .directive('ngCloak'            , buildCloakInterceptor('ng-cloak'))\n\n      .directive('layoutWrap'   , attributeWithoutValue('layout-wrap'))\n      .directive('layoutNowrap' , attributeWithoutValue('layout-nowrap'))\n      .directive('layoutNoWrap' , attributeWithoutValue('layout-no-wrap'))\n      .directive('layoutFill'   , attributeWithoutValue('layout-fill'))\n\n      // Determine if\n      .config(detectDisabledLayouts);\n\n    /**\n     * Converts snake_case to camelCase.\n     * Also there is special case for Moz prefix starting with upper case letter.\n     * @param name Name to normalize\n     */\n    function directiveNormalize(name) {\n      return name\n        .replace(PREFIX_REGEXP, '')\n        .replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {\n          return offset ? letter.toUpperCase() : letter;\n        });\n    }\n  }\n\n\n  /**\n    * Detect if any of the HTML tags has a [md-layouts-disabled] attribute;\n    * If yes, then immediately disable all layout API features\n    *\n    * Note: this attribute should be specified on either the HTML or BODY tags\n    * @ngInject\n    */\n   function detectDisabledLayouts() {\n     var isDisabled = !!document.querySelector('[md-layouts-disabled]');\n     config.enabled = !isDisabled;\n   }\n\n  /**\n   * Special directive that will disable ALL Layout conversions of layout\n   * attribute(s) to classname(s).\n   *\n   * <link rel=\"stylesheet\" href=\"angular-material.min.css\">\n   * <link rel=\"stylesheet\" href=\"angular-material.layout.css\">\n   *\n   * <body md-layout-css>\n   *  ...\n   * </body>\n   *\n   * Note: Using md-layout-css directive requires the developer to load the Material\n   * Layout Attribute stylesheet (which only uses attribute selectors):\n   *\n   *       `angular-material.layout.css`\n   *\n   * Another option is to use the LayoutProvider to configure and disable the attribute\n   * conversions; this would obviate the use of the `md-layout-css` directive\n   */\n  function disableLayoutDirective() {\n    // Return a 1x-only, first-match attribute directive\n    config.enabled = false;\n\n    return {\n      restrict : 'A',\n      priority : '900'\n    };\n  }\n\n  /**\n   * Tail-hook ngCloak to delay the uncloaking while Layout transformers\n   * finish processing. Eliminates flicker with Material.Layouts\n   */\n  function buildCloakInterceptor(className) {\n    return ['$timeout', function($timeout){\n      return {\n        restrict : 'A',\n        priority : -10,   // run after normal ng-cloak\n        compile  : function(element) {\n          if (!config.enabled) return angular.noop;\n\n          // Re-add the cloak\n          element.addClass(className);\n\n          return function(scope, element) {\n            // Wait while layout injectors configure, then uncloak\n            // NOTE: $rAF does not delay enough... and this is a 1x-only event,\n            //       $timeout is acceptable.\n            $timeout(function(){\n              element.removeClass(className);\n            }, 10, false);\n          };\n        }\n      };\n    }];\n  }\n\n\n  // *********************************************************************************\n  //\n  // These functions create registration functions for AngularJS Material Layout attribute\n  // directives. This provides easy translation to switch AngularJS Material attribute selectors to\n  // CLASS selectors and directives; which has huge performance implications for IE Browsers.\n  //\n  // *********************************************************************************\n\n  /**\n   * Creates a directive registration function where a possible dynamic attribute\n   * value will be observed/watched.\n   * @param {string} className attribute name; eg `layout-gt-md` with value =\"row\"\n   */\n  function attributeWithObserve(className) {\n\n    return ['$mdUtil', '$interpolate', \"$log\", function(_$mdUtil_, _$interpolate_, _$log_) {\n      $mdUtil = _$mdUtil_;\n      $interpolate = _$interpolate_;\n      $log = _$log_;\n\n      return {\n        restrict: 'A',\n        compile: function(element, attr) {\n          var linkFn;\n          if (config.enabled) {\n            // immediately replace static (non-interpolated) invalid values...\n\n            validateAttributeUsage(className, attr, element, $log);\n\n            validateAttributeValue(className,\n              getNormalizedAttrValue(className, attr, \"\"),\n              buildUpdateFn(element, className, attr)\n            );\n\n            linkFn = translateWithValueToCssClass;\n          }\n\n          // Use for postLink to account for transforms after ng-transclude.\n          return linkFn || angular.noop;\n        }\n      };\n    }];\n\n    /**\n     * Observe deprecated layout attributes and update the element's layout classes to match.\n     */\n    function translateWithValueToCssClass(scope, element, attrs) {\n      var updateFn = updateClassWithValue(element, className, attrs);\n      var unwatch = attrs.$observe(attrs.$normalize(className), updateFn);\n\n      updateFn(getNormalizedAttrValue(className, attrs, \"\"));\n      scope.$on(\"$destroy\", function() { unwatch(); });\n    }\n  }\n\n  /**\n   * Creates a registration function for AngularJS Material Layout attribute directive.\n   * This is a `simple` transpose of attribute usage to class usage; where we ignore\n   * any attribute value.\n   */\n  function attributeWithoutValue(className) {\n    return ['$mdUtil', '$interpolate', \"$log\", function(_$mdUtil_, _$interpolate_, _$log_) {\n      $mdUtil = _$mdUtil_;\n      $interpolate = _$interpolate_;\n      $log = _$log_;\n\n      return {\n        restrict: 'A',\n        compile: function(element, attr) {\n          var linkFn;\n          if (config.enabled) {\n            // immediately replace static (non-interpolated) invalid values...\n\n            validateAttributeValue(className,\n              getNormalizedAttrValue(className, attr, \"\"),\n              buildUpdateFn(element, className, attr)\n            );\n\n            translateToCssClass(null, element);\n\n            // Use for postLink to account for transforms after ng-transclude.\n            linkFn = translateToCssClass;\n          }\n\n          return linkFn || angular.noop;\n        }\n      };\n    }];\n\n    /**\n     * Add transformed class selector.\n     */\n    function translateToCssClass(scope, element) {\n      element.addClass(className);\n    }\n  }\n\n  /**\n   * After link-phase, do NOT remove deprecated layout attribute selector.\n   * Instead watch the attribute so interpolated data-bindings to layout\n   * selectors will continue to be supported.\n   *\n   * $observe() the className and update with new class (after removing the last one)\n   *\n   * e.g. `layout=\"{{layoutDemo.direction}}\"` will update...\n   *\n   * NOTE: The value must match one of the specified styles in the CSS.\n   * For example `flex-gt-md=\"{{size}}`  where `scope.size == 47` will NOT work since\n   * only breakpoints for 0, 5, 10, 15... 100, 33, 34, 66, 67 are defined.\n   */\n  function updateClassWithValue(element, className) {\n    var lastClass;\n\n    return function updateClassFn(newValue) {\n      var value = validateAttributeValue(className, newValue || \"\");\n      if (angular.isDefined(value)) {\n        if (lastClass) element.removeClass(lastClass);\n        lastClass = !value ? className : className + \"-\" + value.trim().replace(WHITESPACE, \"-\");\n        element.addClass(lastClass);\n      }\n    };\n  }\n\n  /**\n   * Centralize warnings for known flexbox issues (especially IE-related issues)\n   */\n  function validateAttributeUsage(className, attr, element, $log){\n    var message, usage, url;\n    var nodeName = element[0].nodeName.toLowerCase();\n\n    switch (className.replace(SUFFIXES,\"\")) {\n      case \"flex\":\n        if ((nodeName === \"md-button\") || (nodeName === \"fieldset\")){\n          // @see https://github.com/philipwalton/flexbugs#9-some-html-elements-cant-be-flex-containers\n          // Use <div flex> wrapper inside (preferred) or outside\n\n          usage = \"<\" + nodeName + \" \" + className + \"></\" + nodeName + \">\";\n          url = \"https://github.com/philipwalton/flexbugs#9-some-html-elements-cant-be-flex-containers\";\n          message = \"Markup '{0}' may not work as expected in IE Browsers. Consult '{1}' for details.\";\n\n          $log.warn($mdUtil.supplant(message, [usage, url]));\n        }\n    }\n  }\n\n\n  /**\n   * For the Layout attribute value, validate or replace with default fallback value.\n   */\n  function validateAttributeValue(className, value, updateFn) {\n    var origValue = value;\n\n    if (!needsInterpolation(value)) {\n      switch (className.replace(SUFFIXES,\"\")) {\n        case 'layout'        :\n          if (!findIn(value, LAYOUT_OPTIONS)) {\n            value = LAYOUT_OPTIONS[0];    // 'row';\n          }\n          break;\n\n        case 'flex'          :\n          if (!findIn(value, FLEX_OPTIONS)) {\n            if (isNaN(value)) {\n              value = '';\n            }\n          }\n          break;\n\n        case 'flex-offset' :\n        case 'flex-order'    :\n          if (!value || isNaN(+value)) {\n            value = '0';\n          }\n          break;\n\n        case 'layout-align'  :\n          var axis = extractAlignAxis(value);\n          value = $mdUtil.supplant(\"{main}-{cross}\",axis);\n          break;\n\n        case 'layout-padding' :\n        case 'layout-margin'  :\n        case 'layout-fill'    :\n        case 'layout-wrap'    :\n        case 'layout-nowrap' :\n          value = '';\n          break;\n      }\n\n      if (value !== origValue) {\n        (updateFn || angular.noop)(value);\n      }\n    }\n\n    return value ? value.trim() : \"\";\n  }\n\n  /**\n   * Replace current attribute value with fallback value\n   */\n  function buildUpdateFn(element, className, attrs) {\n    return function updateAttrValue(fallback) {\n      if (!needsInterpolation(fallback)) {\n        // Do not modify the element's attribute value; so\n        // uses '<ui-layout layout=\"/api/sidebar.html\" />' will not\n        // be affected. Just update the attrs value.\n        attrs[attrs.$normalize(className)] = fallback;\n      }\n    };\n  }\n\n  /**\n   * See if the original value has interpolation symbols:\n   * e.g.  flex-gt-md=\"{{triggerPoint}}\"\n   */\n  function needsInterpolation(value) {\n    return (value || \"\").indexOf($interpolate.startSymbol()) > -1;\n  }\n\n  function getNormalizedAttrValue(className, attrs, defaultVal) {\n    var normalizedAttr = attrs.$normalize(className);\n    return attrs[normalizedAttr] ? attrs[normalizedAttr].trim().replace(WHITESPACE, \"-\") :\n      defaultVal || null;\n  }\n\n  function findIn(item, list, replaceWith) {\n    item = replaceWith && item ? item.replace(WHITESPACE, replaceWith) : item;\n\n    var found = false;\n    if (item) {\n      list.forEach(function(it) {\n        it = replaceWith ? it.replace(WHITESPACE, replaceWith) : it;\n        found = found || (it === item);\n      });\n    }\n    return found;\n  }\n\n  function extractAlignAxis(attrValue) {\n    var axis = {\n      main : \"start\",\n      cross: \"stretch\"\n    }, values;\n\n    attrValue = (attrValue || \"\");\n\n    if (attrValue.indexOf(\"-\") === 0 || attrValue.indexOf(\" \") === 0) {\n      // For missing main-axis values\n      attrValue = \"none\" + attrValue;\n    }\n\n    values = attrValue.toLowerCase().trim().replace(WHITESPACE, \"-\").split(\"-\");\n    if (values.length && (values[0] === \"space\")) {\n      // for main-axis values of \"space-around\" or \"space-between\"\n      values = [values[0]+\"-\"+values[1],values[2]];\n    }\n\n    if (values.length > 0) axis.main  = values[0] || axis.main;\n    if (values.length > 1) axis.cross = values[1] || axis.cross;\n\n    if (ALIGNMENT_MAIN_AXIS.indexOf(axis.main) < 0)   axis.main = \"start\";\n    if (ALIGNMENT_CROSS_AXIS.indexOf(axis.cross) < 0) axis.cross = \"stretch\";\n\n    return axis;\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\n/**\r\n * @ngdoc module\r\n * @name material.core.liveannouncer\r\n * @description\r\n * AngularJS Material Live Announcer to provide accessibility for Voice Readers.\r\n */\r\nMdLiveAnnouncer.$inject = [\"$timeout\"];\r\nangular\r\n  .module('material.core')\r\n  .service('$mdLiveAnnouncer', MdLiveAnnouncer);\r\n\r\n/**\r\n * @ngdoc service\r\n * @name $mdLiveAnnouncer\r\n * @module material.core.liveannouncer\r\n *\r\n * @description\r\n *\r\n * Service to announce messages to supported screenreaders.\r\n *\r\n * > The `$mdLiveAnnouncer` service is internally used for components to provide proper accessibility.\r\n *\r\n * <hljs lang=\"js\">\r\n *   module.controller('AppCtrl', function($mdLiveAnnouncer) {\r\n *     // Basic announcement (Polite Mode)\r\n *     $mdLiveAnnouncer.announce('Hey Google');\r\n *\r\n *     // Custom announcement (Assertive Mode)\r\n *     $mdLiveAnnouncer.announce('Hey Google', 'assertive');\r\n *   });\r\n * </hljs>\r\n *\r\n */\r\nfunction MdLiveAnnouncer($timeout) {\r\n  /** @private @const @type {!angular.$timeout} */\r\n  this._$timeout = $timeout;\r\n\r\n  /** @private @const @type {!HTMLElement} */\r\n  this._liveElement = this._createLiveElement();\r\n\r\n  /** @private @const @type {!number} */\r\n  this._announceTimeout = 100;\r\n}\r\n\r\n/**\r\n * @ngdoc method\r\n * @name $mdLiveAnnouncer#announce\r\n * @description Announces messages to supported screenreaders.\r\n * @param {string} message Message to be announced to the screenreader\r\n * @param {'off'|'polite'|'assertive'} politeness The politeness of the announcer element.\r\n */\r\nMdLiveAnnouncer.prototype.announce = function(message, politeness) {\r\n  if (!politeness) {\r\n    politeness = 'polite';\r\n  }\r\n\r\n  var self = this;\r\n\r\n  self._liveElement.textContent = '';\r\n  self._liveElement.setAttribute('aria-live', politeness);\r\n\r\n  // This 100ms timeout is necessary for some browser + screen-reader combinations:\r\n  // - Both JAWS and NVDA over IE11 will not announce anything without a non-zero timeout.\r\n  // - With Chrome and IE11 with NVDA or JAWS, a repeated (identical) message won't be read a\r\n  //   second time without clearing and then using a non-zero delay.\r\n  // (using JAWS 17 at time of this writing).\r\n  self._$timeout(function() {\r\n    self._liveElement.textContent = message;\r\n  }, self._announceTimeout, false);\r\n};\r\n\r\n/**\r\n * Creates a live announcer element, which listens for DOM changes and announces them\r\n * to the screenreaders.\r\n * @returns {!HTMLElement}\r\n * @private\r\n */\r\nMdLiveAnnouncer.prototype._createLiveElement = function() {\r\n  var liveEl = document.createElement('div');\r\n\r\n  liveEl.classList.add('md-visually-hidden');\r\n  liveEl.setAttribute('role', 'status');\r\n  liveEl.setAttribute('aria-atomic', 'true');\r\n  liveEl.setAttribute('aria-live', 'polite');\r\n\r\n  document.body.appendChild(liveEl);\r\n\r\n  return liveEl;\r\n};\r\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc service\n * @name $$mdMeta\n * @module material.core.meta\n *\n * @description\n *\n * A provider and a service that simplifies meta tags access\n *\n * Note: This is intended only for use with dynamic meta tags such as browser color and title.\n * Tags that are only processed when the page is rendered (such as `charset`, and `http-equiv`)\n * will not work since `$$mdMeta` adds the tags after the page has already been loaded.\n *\n * ```js\n * app.config(function($$mdMetaProvider) {\n *   var removeMeta = $$mdMetaProvider.setMeta('meta-name', 'content');\n *   var metaValue  = $$mdMetaProvider.getMeta('meta-name'); // -> 'content'\n *\n *   removeMeta();\n * });\n *\n * app.controller('myController', function($$mdMeta) {\n *   var removeMeta = $$mdMeta.setMeta('meta-name', 'content');\n *   var metaValue  = $$mdMeta.getMeta('meta-name'); // -> 'content'\n *\n *   removeMeta();\n * });\n * ```\n *\n * @returns {$$mdMeta.$service}\n *\n */\nangular.module('material.core.meta', [])\n  .provider('$$mdMeta', function () {\n    var head = angular.element(document.head);\n    var metaElements = {};\n\n    /**\n     * Checks if the requested element was written manually and maps it\n     *\n     * @param {string} name meta tag 'name' attribute value\n     * @returns {boolean} returns true if there is an element with the requested name\n     */\n    function mapExistingElement(name) {\n      if (metaElements[name]) {\n        return true;\n      }\n\n      var element = document.getElementsByName(name)[0];\n\n      if (!element) {\n        return false;\n      }\n\n      metaElements[name] = angular.element(element);\n\n      return true;\n    }\n\n    /**\n     * @ngdoc method\n     * @name $$mdMeta#setMeta\n     *\n     * @description\n     * Creates meta element with the 'name' and 'content' attributes,\n     * if the meta tag is already created than we replace the 'content' value\n     *\n     * @param {string} name meta tag 'name' attribute value\n     * @param {string} content meta tag 'content' attribute value\n     * @returns {function} remove function\n     *\n     */\n    function setMeta(name, content) {\n      mapExistingElement(name);\n\n      if (!metaElements[name]) {\n        var newMeta = angular.element('<meta name=\"' + name + '\" content=\"' + content + '\"/>');\n        head.append(newMeta);\n        metaElements[name] = newMeta;\n      }\n      else {\n        metaElements[name].attr('content', content);\n      }\n\n      return function () {\n        metaElements[name].attr('content', '');\n        metaElements[name].remove();\n        delete metaElements[name];\n      };\n    }\n\n    /**\n     * @ngdoc method\n     * @name $$mdMeta#getMeta\n     *\n     * @description\n     * Gets the 'content' attribute value of the wanted meta element\n     *\n     * @param {string} name meta tag 'name' attribute value\n     * @returns {string} content attribute value\n     */\n    function getMeta(name) {\n      if (!mapExistingElement(name)) {\n        throw Error('$$mdMeta: could not find a meta tag with the name \\'' + name + '\\'');\n      }\n\n      return metaElements[name].attr('content');\n    }\n\n    var module = {\n      setMeta: setMeta,\n      getMeta: getMeta\n    };\n\n    return angular.extend({}, module, {\n      $get: function () {\n        return module;\n      }\n    });\n  });\n})();\n(function(){\n\"use strict\";\n\n  /**\n   * @ngdoc module\n   * @name material.core.componentRegistry\n   *\n   * @description\n   * A component instance registration service.\n   * Note: currently this as a private service in the SideNav component.\n   */\n  ComponentRegistry.$inject = [\"$log\", \"$q\"];\n  angular.module('material.core')\n    .factory('$mdComponentRegistry', ComponentRegistry);\n\n  /*\n   * @private\n   * @ngdoc factory\n   * @name ComponentRegistry\n   * @module material.core.componentRegistry\n   *\n   */\n  function ComponentRegistry($log, $q) {\n\n    var self;\n    var instances = [];\n    var pendings = { };\n\n    return self = {\n      /**\n       * Used to print an error when an instance for a handle isn't found.\n       */\n      notFoundError: function(handle, msgContext) {\n        $log.error((msgContext || \"\") + 'No instance found for handle', handle);\n      },\n      /**\n       * Return all registered instances as an array.\n       */\n      getInstances: function() {\n        return instances;\n      },\n\n      /**\n       * Get a registered instance.\n       * @param handle the String handle to look up for a registered instance.\n       */\n      get: function(handle) {\n        if (!isValidID(handle)) return null;\n\n        var i, j, instance;\n        for (i = 0, j = instances.length; i < j; i++) {\n          instance = instances[i];\n          if (instance.$$mdHandle === handle) {\n            return instance;\n          }\n        }\n        return null;\n      },\n\n      /**\n       * Register an instance.\n       * @param instance the instance to register\n       * @param handle the handle to identify the instance under.\n       */\n      register: function(instance, handle) {\n        if (!handle) return angular.noop;\n\n        instance.$$mdHandle = handle;\n        instances.push(instance);\n        resolveWhen();\n\n        return deregister;\n\n        /**\n         * Remove registration for an instance\n         */\n        function deregister() {\n          var index = instances.indexOf(instance);\n          if (index !== -1) {\n            instances.splice(index, 1);\n          }\n        }\n\n        /**\n         * Resolve any pending promises for this instance\n         */\n        function resolveWhen() {\n          var dfd = pendings[handle];\n          if (dfd) {\n            dfd.forEach(function (promise) {\n              promise.resolve(instance);\n            });\n            delete pendings[handle];\n          }\n        }\n      },\n\n      /**\n       * Async accessor to registered component instance\n       * If not available then a promise is created to notify\n       * all listeners when the instance is registered.\n       */\n      when : function(handle) {\n        if (isValidID(handle)) {\n          var deferred = $q.defer();\n          var instance = self.get(handle);\n\n          if (instance)  {\n            deferred.resolve(instance);\n          } else {\n            if (pendings[handle] === undefined) {\n              pendings[handle] = [];\n            }\n            pendings[handle].push(deferred);\n          }\n\n          return deferred.promise;\n        }\n        return $q.reject(\"Invalid `md-component-id` value.\");\n      }\n\n    };\n\n    function isValidID(handle){\n      return handle && (handle !== \"\");\n    }\n\n  }\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  /**\n   * @ngdoc service\n   * @name $mdButtonInkRipple\n   * @module material.core\n   *\n   * @description\n   * Provides ripple effects for md-button.  See $mdInkRipple service for all possible configuration options.\n   *\n   * @param {object=} scope Scope within the current context\n   * @param {object=} element The element the ripple effect should be applied to\n   * @param {object=} options (Optional) Configuration options to override the default ripple configuration\n   */\n\n  MdButtonInkRipple.$inject = [\"$mdInkRipple\"];\n  angular.module('material.core')\n    .factory('$mdButtonInkRipple', MdButtonInkRipple);\n\n  function MdButtonInkRipple($mdInkRipple) {\n    return {\n      attach: function attachRipple(scope, element, options) {\n        options = angular.extend(optionsForElement(element), options);\n\n        return $mdInkRipple.attach(scope, element, options);\n      }\n    };\n\n    function optionsForElement(element) {\n      if (element.hasClass('md-icon-button')) {\n        return {\n          isMenuItem: element.hasClass('md-menu-item'),\n          fitRipple: true,\n          center: true\n        };\n      } else {\n        return {\n          isMenuItem: element.hasClass('md-menu-item'),\n          dimBackground: true\n        };\n      }\n    }\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n    /**\n   * @ngdoc service\n   * @name $mdCheckboxInkRipple\n   * @module material.core\n   *\n   * @description\n   * Provides ripple effects for md-checkbox.  See $mdInkRipple service for all possible configuration options.\n   *\n   * @param {object=} scope Scope within the current context\n   * @param {object=} element The element the ripple effect should be applied to\n   * @param {object=} options (Optional) Configuration options to override the defaultripple configuration\n   */\n\n  MdCheckboxInkRipple.$inject = [\"$mdInkRipple\"];\n  angular.module('material.core')\n    .factory('$mdCheckboxInkRipple', MdCheckboxInkRipple);\n\n  function MdCheckboxInkRipple($mdInkRipple) {\n    return {\n      attach: attach\n    };\n\n    function attach(scope, element, options) {\n      return $mdInkRipple.attach(scope, element, angular.extend({\n        center: true,\n        dimBackground: false,\n        fitRipple: true\n      }, options));\n    }\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  /**\n   * @ngdoc service\n   * @name $mdListInkRipple\n   * @module material.core\n   *\n   * @description\n   * Provides ripple effects for md-list.  See $mdInkRipple service for all possible configuration options.\n   *\n   * @param {object=} scope Scope within the current context\n   * @param {object=} element The element the ripple effect should be applied to\n   * @param {object=} options (Optional) Configuration options to override the defaultripple configuration\n   */\n\n  MdListInkRipple.$inject = [\"$mdInkRipple\"];\n  angular.module('material.core')\n    .factory('$mdListInkRipple', MdListInkRipple);\n\n  function MdListInkRipple($mdInkRipple) {\n    return {\n      attach: attach\n    };\n\n    function attach(scope, element, options) {\n      return $mdInkRipple.attach(scope, element, angular.extend({\n        center: false,\n        dimBackground: true,\n        outline: false,\n        rippleSize: 'full'\n      }, options));\n    }\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.core.ripple\n * @description\n * Ripple\n */\nInkRippleCtrl.$inject = [\"$scope\", \"$element\", \"rippleOptions\", \"$window\", \"$timeout\", \"$mdUtil\", \"$mdColorUtil\"];\nInkRippleDirective.$inject = [\"$mdButtonInkRipple\", \"$mdCheckboxInkRipple\"];\nangular.module('material.core')\n    .provider('$mdInkRipple', InkRippleProvider)\n    .directive('mdInkRipple', InkRippleDirective)\n    .directive('mdNoInk', attrNoDirective)\n    .directive('mdNoBar', attrNoDirective)\n    .directive('mdNoStretch', attrNoDirective);\n\nvar DURATION = 450;\n\n/**\n * @ngdoc directive\n * @name mdInkRipple\n * @module material.core.ripple\n *\n * @description\n * The `md-ink-ripple` directive allows you to specify the ripple color or if a ripple is allowed.\n *\n * @param {string|boolean} md-ink-ripple A color string `#FF0000` or boolean (`false` or `0`) for\n *  preventing ripple\n *\n * @usage\n * ### String values\n * <hljs lang=\"html\">\n *   <ANY md-ink-ripple=\"#FF0000\">\n *     Ripples in red\n *   </ANY>\n *\n *   <ANY md-ink-ripple=\"false\">\n *     Not rippling\n *   </ANY>\n * </hljs>\n *\n * ### Interpolated values\n * <hljs lang=\"html\">\n *   <ANY md-ink-ripple=\"{{ randomColor() }}\">\n *     Ripples with the return value of 'randomColor' function\n *   </ANY>\n *\n *   <ANY md-ink-ripple=\"{{ canRipple() }}\">\n *     Ripples if 'canRipple' function return value is not 'false' or '0'\n *   </ANY>\n * </hljs>\n */\nfunction InkRippleDirective ($mdButtonInkRipple, $mdCheckboxInkRipple) {\n  return {\n    controller: angular.noop,\n    link:       function (scope, element, attr) {\n      attr.hasOwnProperty('mdInkRippleCheckbox')\n          ? $mdCheckboxInkRipple.attach(scope, element)\n          : $mdButtonInkRipple.attach(scope, element);\n    }\n  };\n}\n\n/**\n * @ngdoc service\n * @name $mdInkRipple\n * @module material.core.ripple\n *\n * @description\n * `$mdInkRipple` is a service for adding ripples to any element.\n *\n * @usage\n * <hljs lang=\"js\">\n * app.factory('$myElementInkRipple', function($mdInkRipple) {\n *   return {\n *     attach: function (scope, element, options) {\n *       return $mdInkRipple.attach(scope, element, angular.extend({\n *         center: false,\n *         dimBackground: true\n *       }, options));\n *     }\n *   };\n * });\n *\n * app.controller('myController', function ($scope, $element, $myElementInkRipple) {\n *   $scope.onClick = function (ev) {\n *     $myElementInkRipple.attach($scope, angular.element(ev.target), { center: true });\n *   }\n * });\n * </hljs>\n */\n\n/**\n * @ngdoc service\n * @name $mdInkRippleProvider\n * @module material.core.ripple\n *\n * @description\n  * If you want to disable ink ripples globally, for all components, you can call the\n * `disableInkRipple` method in your app's config.\n *\n *\n * @usage\n * <hljs lang=\"js\">\n * app.config(function ($mdInkRippleProvider) {\n *   $mdInkRippleProvider.disableInkRipple();\n * });\n * </hljs>\n */\n\nfunction InkRippleProvider () {\n  var isDisabledGlobally = false;\n\n  return {\n    disableInkRipple: disableInkRipple,\n    $get: [\"$injector\", function($injector) {\n      return { attach: attach };\n\n      /**\n       * @ngdoc method\n       * @name $mdInkRipple#attach\n       *\n       * @description\n       * Attaching given scope, element and options to inkRipple controller\n       *\n       * @param {object=} scope Scope within the current context\n       * @param {object=} element The element the ripple effect should be applied to\n       * @param {object=} options (Optional) Configuration options to override the defaultRipple configuration\n       * * `center` -  Whether the ripple should start from the center of the container element\n       * * `dimBackground` - Whether the background should be dimmed with the ripple color\n       * * `colorElement` - The element the ripple should take its color from, defined by css property `color`\n       * * `fitRipple` - Whether the ripple should fill the element\n       */\n      function attach (scope, element, options) {\n        if (isDisabledGlobally || element.controller('mdNoInk')) return angular.noop;\n        return $injector.instantiate(InkRippleCtrl, {\n          $scope:        scope,\n          $element:      element,\n          rippleOptions: options\n        });\n      }\n    }]\n  };\n\n  /**\n   * @ngdoc method\n   * @name $mdInkRippleProvider#disableInkRipple\n   *\n   * @description\n   * A config-time method that, when called, disables ripples globally.\n   */\n  function disableInkRipple () {\n    isDisabledGlobally = true;\n  }\n}\n\n/**\n * Controller used by the ripple service in order to apply ripples\n * @ngInject\n */\nfunction InkRippleCtrl ($scope, $element, rippleOptions, $window, $timeout, $mdUtil, $mdColorUtil) {\n  this.$window    = $window;\n  this.$timeout   = $timeout;\n  this.$mdUtil    = $mdUtil;\n  this.$mdColorUtil    = $mdColorUtil;\n  this.$scope     = $scope;\n  this.$element   = $element;\n  this.options    = rippleOptions;\n  this.mousedown  = false;\n  this.ripples    = [];\n  this.timeout    = null; // Stores a reference to the most-recent ripple timeout\n  this.lastRipple = null;\n\n  $mdUtil.valueOnUse(this, 'container', this.createContainer);\n\n  this.$element.addClass('md-ink-ripple');\n\n  // attach method for unit tests\n  ($element.controller('mdInkRipple') || {}).createRipple = angular.bind(this, this.createRipple);\n  ($element.controller('mdInkRipple') || {}).setColor = angular.bind(this, this.color);\n\n  this.bindEvents();\n}\n\n\n/**\n * Either remove or unlock any remaining ripples when the user mouses off of the element (either by\n * mouseup or mouseleave event)\n */\nfunction autoCleanup (self, cleanupFn) {\n  if (self.mousedown || self.lastRipple) {\n    self.mousedown = false;\n    self.$mdUtil.nextTick(angular.bind(self, cleanupFn), false);\n  }\n}\n\n\n/**\n * Returns the color that the ripple should be (either based on CSS or hard-coded)\n * @returns {string}\n */\nInkRippleCtrl.prototype.color = function (value) {\n  var self = this;\n\n  // If assigning a color value, apply it to background and the ripple color\n  if (angular.isDefined(value)) {\n    self._color = self._parseColor(value);\n  }\n\n  // If color lookup, use assigned, defined, or inherited\n  return self._color || self._parseColor(self.inkRipple()) || self._parseColor(getElementColor());\n\n  /**\n   * Finds the color element and returns its text color for use as default ripple color\n   * @returns {string}\n   */\n  function getElementColor () {\n    var items = self.options && self.options.colorElement ? self.options.colorElement : [];\n    var elem =  items.length ? items[ 0 ] : self.$element[ 0 ];\n\n    return elem ? self.$window.getComputedStyle(elem).color : 'rgb(0,0,0)';\n  }\n};\n\n/**\n * Updating the ripple colors based on the current inkRipple value\n * or the element's computed style color\n */\nInkRippleCtrl.prototype.calculateColor = function () {\n  return this.color();\n};\n\n\n/**\n * Takes a string color and converts it to RGBA format\n * @param {string} color\n * @param {number} multiplier\n * @returns {string}\n */\nInkRippleCtrl.prototype._parseColor = function parseColor (color, multiplier) {\n  multiplier = multiplier || 1;\n  var colorUtil = this.$mdColorUtil;\n\n  if (!color) return;\n  if (color.indexOf('rgba') === 0) return color.replace(/\\d?\\.?\\d*\\s*\\)\\s*$/, (0.1 * multiplier).toString() + ')');\n  if (color.indexOf('rgb') === 0) return colorUtil.rgbToRgba(color);\n  if (color.indexOf('#') === 0) return colorUtil.hexToRgba(color);\n\n};\n\n/**\n * Binds events to the root element for\n */\nInkRippleCtrl.prototype.bindEvents = function () {\n  this.$element.on('mousedown', angular.bind(this, this.handleMousedown));\n  this.$element.on('mouseup touchend', angular.bind(this, this.handleMouseup));\n  this.$element.on('mouseleave', angular.bind(this, this.handleMouseup));\n  this.$element.on('touchmove', angular.bind(this, this.handleTouchmove));\n};\n\n/**\n * Create a new ripple on every mousedown event from the root element\n * @param event {MouseEvent}\n */\nInkRippleCtrl.prototype.handleMousedown = function (event) {\n  if (this.mousedown) return;\n\n  // When jQuery is loaded, we have to get the original event\n  if (event.hasOwnProperty('originalEvent')) event = event.originalEvent;\n  this.mousedown = true;\n  if (this.options.center) {\n    this.createRipple(this.container.prop('clientWidth') / 2, this.container.prop('clientWidth') / 2);\n  } else {\n\n    // We need to calculate the relative coordinates if the target is a sublayer of the ripple element\n    if (event.srcElement !== this.$element[0]) {\n      var layerRect = this.$element[0].getBoundingClientRect();\n      var layerX = event.clientX - layerRect.left;\n      var layerY = event.clientY - layerRect.top;\n\n      this.createRipple(layerX, layerY);\n    } else {\n      this.createRipple(event.offsetX, event.offsetY);\n    }\n  }\n};\n\n/**\n * Either remove or unlock any remaining ripples when the user mouses off of the element (either by\n * mouseup, touchend or mouseleave event)\n */\nInkRippleCtrl.prototype.handleMouseup = function () {\n  this.$timeout(function () {\n    autoCleanup(this, this.clearRipples);\n  }.bind(this));\n};\n\n/**\n * Either remove or unlock any remaining ripples when the user mouses off of the element (by\n * touchmove)\n */\nInkRippleCtrl.prototype.handleTouchmove = function () {\n  autoCleanup(this, this.deleteRipples);\n};\n\n/**\n * Cycles through all ripples and attempts to remove them.\n */\nInkRippleCtrl.prototype.deleteRipples = function () {\n  for (var i = 0; i < this.ripples.length; i++) {\n    this.ripples[ i ].remove();\n  }\n};\n\n/**\n * Cycles through all ripples and attempts to remove them with fade.\n * Depending on logic within `fadeInComplete`, some removals will be postponed.\n */\nInkRippleCtrl.prototype.clearRipples = function () {\n  for (var i = 0; i < this.ripples.length; i++) {\n    this.fadeInComplete(this.ripples[ i ]);\n  }\n};\n\n/**\n * Creates the ripple container element\n * @returns {*}\n */\nInkRippleCtrl.prototype.createContainer = function () {\n  var container = angular.element('<div class=\"md-ripple-container\"></div>');\n  this.$element.append(container);\n  return container;\n};\n\nInkRippleCtrl.prototype.clearTimeout = function () {\n  if (this.timeout) {\n    this.$timeout.cancel(this.timeout);\n    this.timeout = null;\n  }\n};\n\nInkRippleCtrl.prototype.isRippleAllowed = function () {\n  var element = this.$element[0];\n  do {\n    if (!element.tagName || element.tagName === 'BODY') break;\n\n    if (element && angular.isFunction(element.hasAttribute)) {\n      if (element.hasAttribute('disabled')) return false;\n      if (this.inkRipple() === 'false' || this.inkRipple() === '0') return false;\n    }\n\n  } while (element = element.parentNode);\n  return true;\n};\n\n/**\n * The attribute `md-ink-ripple` may be a static or interpolated\n * color value OR a boolean indicator (used to disable ripples)\n */\nInkRippleCtrl.prototype.inkRipple = function () {\n  return this.$element.attr('md-ink-ripple');\n};\n\n/**\n * Creates a new ripple and adds it to the container.  Also tracks ripple in `this.ripples`.\n * @param left\n * @param top\n */\nInkRippleCtrl.prototype.createRipple = function (left, top) {\n  if (!this.isRippleAllowed()) return;\n\n  var ctrl        = this;\n  var colorUtil   = ctrl.$mdColorUtil;\n  var ripple      = angular.element('<div class=\"md-ripple\"></div>');\n  var width       = this.$element.prop('clientWidth');\n  var height      = this.$element.prop('clientHeight');\n  var x           = Math.max(Math.abs(width - left), left) * 2;\n  var y           = Math.max(Math.abs(height - top), top) * 2;\n  var size        = getSize(this.options.fitRipple, x, y);\n  var color       = this.calculateColor();\n\n  ripple.css({\n    left:            left + 'px',\n    top:             top + 'px',\n    background:      'black',\n    width:           size + 'px',\n    height:          size + 'px',\n    backgroundColor: colorUtil.rgbaToRgb(color),\n    borderColor:     colorUtil.rgbaToRgb(color)\n  });\n  this.lastRipple = ripple;\n\n  // we only want one timeout to be running at a time\n  this.clearTimeout();\n  this.timeout    = this.$timeout(function () {\n    ctrl.clearTimeout();\n    if (!ctrl.mousedown) ctrl.fadeInComplete(ripple);\n  }, DURATION * 0.35, false);\n\n  if (this.options.dimBackground) this.container.css({ backgroundColor: color });\n  this.container.append(ripple);\n  this.ripples.push(ripple);\n  ripple.addClass('md-ripple-placed');\n\n  this.$mdUtil.nextTick(function () {\n\n    ripple.addClass('md-ripple-scaled md-ripple-active');\n    ctrl.$timeout(function () {\n      ctrl.clearRipples();\n    }, DURATION, false);\n\n  }, false);\n\n  function getSize (fit, x, y) {\n    return fit\n        ? Math.max(x, y)\n        : Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));\n  }\n};\n\n\n\n/**\n * After fadeIn finishes, either kicks off the fade-out animation or queues the element for removal on mouseup\n * @param ripple\n */\nInkRippleCtrl.prototype.fadeInComplete = function (ripple) {\n  if (this.lastRipple === ripple) {\n    if (!this.timeout && !this.mousedown) {\n      this.removeRipple(ripple);\n    }\n  } else {\n    this.removeRipple(ripple);\n  }\n};\n\n/**\n * Kicks off the animation for removing a ripple\n * @param ripple {Element}\n */\nInkRippleCtrl.prototype.removeRipple = function (ripple) {\n  var ctrl  = this;\n  var index = this.ripples.indexOf(ripple);\n  if (index < 0) return;\n  this.ripples.splice(this.ripples.indexOf(ripple), 1);\n  ripple.removeClass('md-ripple-active');\n  ripple.addClass('md-ripple-remove');\n  if (this.ripples.length === 0) this.container.css({ backgroundColor: '' });\n  // use a 2-second timeout in order to allow for the animation to finish\n  // we don't actually care how long the animation takes\n  this.$timeout(function () {\n    ctrl.fadeOutComplete(ripple);\n  }, DURATION, false);\n};\n\n/**\n * Removes the provided ripple from the DOM\n * @param ripple\n */\nInkRippleCtrl.prototype.fadeOutComplete = function (ripple) {\n  ripple.remove();\n  this.lastRipple = null;\n};\n\n/**\n * Used to create an empty directive.  This is used to track flag-directives whose children may have\n * functionality based on them.\n *\n * Example: `md-no-ink` will potentially be used by all child directives.\n */\nfunction attrNoDirective () {\n  return { controller: angular.noop };\n}\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n    /**\n   * @ngdoc service\n   * @name $mdTabInkRipple\n   * @module material.core\n   *\n   * @description\n   * Provides ripple effects for md-tabs.  See $mdInkRipple service for all possible configuration options.\n   *\n   * @param {object=} scope Scope within the current context\n   * @param {object=} element The element the ripple effect should be applied to\n   * @param {object=} options (Optional) Configuration options to override the defaultripple configuration\n   */\n\n  MdTabInkRipple.$inject = [\"$mdInkRipple\"];\n  angular.module('material.core')\n    .factory('$mdTabInkRipple', MdTabInkRipple);\n\n  function MdTabInkRipple($mdInkRipple) {\n    return {\n      attach: attach\n    };\n\n    function attach(scope, element, options) {\n      return $mdInkRipple.attach(scope, element, angular.extend({\n        center: false,\n        dimBackground: true,\n        outline: false,\n        rippleSize: 'full'\n      }, options));\n    }\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\nangular.module('material.core.theming.palette', [])\n.constant('$mdColorPalette', {\n  'red': {\n    '50': '#ffebee',\n    '100': '#ffcdd2',\n    '200': '#ef9a9a',\n    '300': '#e57373',\n    '400': '#ef5350',\n    '500': '#f44336',\n    '600': '#e53935',\n    '700': '#d32f2f',\n    '800': '#c62828',\n    '900': '#b71c1c',\n    'A100': '#ff8a80',\n    'A200': '#ff5252',\n    'A400': '#ff1744',\n    'A700': '#d50000',\n    'contrastDefaultColor': 'light',\n    'contrastDarkColors': '50 100 200 300 400 500 600 A100 A200 A400',\n    'contrastStrongLightColors': '700 800 900 A700'\n  },\n  'pink': {\n    '50': '#fce4ec',\n    '100': '#f8bbd0',\n    '200': '#f48fb1',\n    '300': '#f06292',\n    '400': '#ec407a',\n    '500': '#e91e63',\n    '600': '#d81b60',\n    '700': '#c2185b',\n    '800': '#ad1457',\n    '900': '#880e4f',\n    'A100': '#ff80ab',\n    'A200': '#ff4081',\n    'A400': '#f50057',\n    'A700': '#c51162',\n    'contrastDefaultColor': 'light',\n    'contrastDarkColors': '50 100 200 300 400 A100 A200 A400',\n    // White on 500 does not meet the minimum 4.5 contrast ratio (at 4.34),\n    // but it's worse with a dark foreground (3.61).\n    'contrastStrongLightColors': '500 600 700 800 900 A700'\n  },\n  'purple': {\n    '50': '#f3e5f5',\n    '100': '#e1bee7',\n    '200': '#ce93d8',\n    '300': '#ba68c8',\n    '400': '#ab47bc',\n    '500': '#9c27b0',\n    '600': '#8e24aa',\n    '700': '#7b1fa2',\n    '800': '#6a1b9a',\n    '900': '#4a148c',\n    'A100': '#ea80fc',\n    'A200': '#e040fb',\n    'A400': '#d500f9',\n    'A700': '#aa00ff',\n    'contrastDefaultColor': 'light',\n    'contrastDarkColors': '50 100 200 300 A100 A200 A400',\n    'contrastStrongLightColors': '400 500 600 700 800 900 A700'\n  },\n  'deep-purple': {\n    '50': '#ede7f6',\n    '100': '#d1c4e9',\n    '200': '#b39ddb',\n    '300': '#9575cd',\n    '400': '#7e57c2',\n    '500': '#673ab7',\n    '600': '#5e35b1',\n    '700': '#512da8',\n    '800': '#4527a0',\n    '900': '#311b92',\n    'A100': '#b388ff',\n    'A200': '#7c4dff',\n    'A400': '#651fff',\n    'A700': '#6200ea',\n    'contrastDefaultColor': 'light',\n    'contrastDarkColors': '50 100 200 300 A100',\n    'contrastStrongLightColors': '400 500 600 700 800 900 A200 A400 A700'\n  },\n  'indigo': {\n    '50': '#e8eaf6',\n    '100': '#c5cae9',\n    '200': '#9fa8da',\n    '300': '#7986cb',\n    '400': '#5c6bc0',\n    '500': '#3f51b5',\n    '600': '#3949ab',\n    '700': '#303f9f',\n    '800': '#283593',\n    '900': '#1a237e',\n    'A100': '#8c9eff',\n    'A200': '#536dfe',\n    'A400': '#3d5afe',\n    'A700': '#304ffe',\n    'contrastDefaultColor': 'light',\n    'contrastDarkColors': '50 100 200 300 A100 A200',\n    'contrastStrongLightColors': '400 500 600 700 800 900 A400 A700'\n  },\n  'blue': {\n    '50': '#e3f2fd',\n    '100': '#bbdefb',\n    '200': '#90caf9',\n    '300': '#64b5f6',\n    '400': '#42a5f5',\n    '500': '#2196f3',\n    '600': '#1e88e5',\n    '700': '#1976d2',\n    '800': '#1565c0',\n    '900': '#0d47a1',\n    'A100': '#82b1ff',\n    'A200': '#448aff',\n    'A400': '#2979ff',\n    'A700': '#2962ff',\n    'contrastDefaultColor': 'light',\n    // White on A400 does not meet the minimum 4.5 contrast ratio (at 3.98),\n    // but it's worse with a dark foreground (3.94).\n    'contrastDarkColors': '50 100 200 300 400 500 600 A100 A200',\n    'contrastStrongLightColors': '700 800 900 A400 A700'\n  },\n  'light-blue': {\n    '50': '#e1f5fe',\n    '100': '#b3e5fc',\n    '200': '#81d4fa',\n    '300': '#4fc3f7',\n    '400': '#29b6f6',\n    '500': '#03a9f4',\n    '600': '#039be5',\n    '700': '#0288d1',\n    '800': '#0277bd',\n    '900': '#01579b',\n    'A100': '#80d8ff',\n    'A200': '#40c4ff',\n    'A400': '#00b0ff',\n    'A700': '#0091ea',\n    'contrastDefaultColor': 'dark',\n    // Dark on 700 does not meet the minimum 4.5 contrast ratio (at 4.07),\n    // but it's worse with a white foreground (3.85).\n    'contrastStrongLightColors': '800 900 A700'\n  },\n  'cyan': {\n    '50': '#e0f7fa',\n    '100': '#b2ebf2',\n    '200': '#80deea',\n    '300': '#4dd0e1',\n    '400': '#26c6da',\n    '500': '#00bcd4',\n    '600': '#00acc1',\n    '700': '#0097a7',\n    '800': '#00838f',\n    '900': '#006064',\n    'A100': '#84ffff',\n    'A200': '#18ffff',\n    'A400': '#00e5ff',\n    'A700': '#00b8d4',\n    'contrastDefaultColor': 'dark',\n    // Dark on 700 does not meet the minimum 4.5 contrast ratio (at 4.47),\n    // but it's worse with a white foreground (3.5).\n    'contrastStrongLightColors': '800 900'\n  },\n  'teal': {\n    '50': '#e0f2f1',\n    '100': '#b2dfdb',\n    '200': '#80cbc4',\n    '300': '#4db6ac',\n    '400': '#26a69a',\n    '500': '#009688',\n    '600': '#00897b',\n    '700': '#00796b',\n    '800': '#00695c',\n    '900': '#004d40',\n    'A100': '#a7ffeb',\n    'A200': '#64ffda',\n    'A400': '#1de9b6',\n    'A700': '#00bfa5',\n    'contrastDefaultColor': 'dark',\n    // Dark on 500 does not meet the minimum 4.5 contrast ratio (at 4.27),\n    // but it's worse with a white foreground (3.67).\n    // White on 600 does not meet the minimum 4.5 contrast ratio (at 4.31),\n    // but it's worse with a dark foreground (3.64).\n    'contrastStrongLightColors': '600 700 800 900'\n  },\n  'green': {\n    '50': '#e8f5e9',\n    '100': '#c8e6c9',\n    '200': '#a5d6a7',\n    '300': '#81c784',\n    '400': '#66bb6a',\n    '500': '#4caf50',\n    '600': '#43a047',\n    '700': '#388e3c',\n    '800': '#2e7d32',\n    '900': '#1b5e20',\n    'A100': '#b9f6ca',\n    'A200': '#69f0ae',\n    'A400': '#00e676',\n    'A700': '#00c853',\n    'contrastDefaultColor': 'dark',\n    // White on 700 does not meet the minimum 4.5 contrast ratio (at 4.11),\n    // but it's worse with a dark foreground (3.81).\n    'contrastStrongLightColors': '700 800 900'\n  },\n  'light-green': {\n    '50': '#f1f8e9',\n    '100': '#dcedc8',\n    '200': '#c5e1a5',\n    '300': '#aed581',\n    '400': '#9ccc65',\n    '500': '#8bc34a',\n    '600': '#7cb342',\n    '700': '#689f38',\n    '800': '#558b2f',\n    '900': '#33691e',\n    'A100': '#ccff90',\n    'A200': '#b2ff59',\n    'A400': '#76ff03',\n    'A700': '#64dd17',\n    'contrastDefaultColor': 'dark',\n    'contrastStrongLightColors': '800 900'\n  },\n  'lime': {\n    '50': '#f9fbe7',\n    '100': '#f0f4c3',\n    '200': '#e6ee9c',\n    '300': '#dce775',\n    '400': '#d4e157',\n    '500': '#cddc39',\n    '600': '#c0ca33',\n    '700': '#afb42b',\n    '800': '#9e9d24',\n    '900': '#827717',\n    'A100': '#f4ff81',\n    'A200': '#eeff41',\n    'A400': '#c6ff00',\n    'A700': '#aeea00',\n    'contrastDefaultColor': 'dark',\n    'contrastStrongLightColors': '900'\n  },\n  'yellow': {\n    '50': '#fffde7',\n    '100': '#fff9c4',\n    '200': '#fff59d',\n    '300': '#fff176',\n    '400': '#ffee58',\n    '500': '#ffeb3b',\n    '600': '#fdd835',\n    '700': '#fbc02d',\n    '800': '#f9a825',\n    '900': '#f57f17',\n    'A100': '#ffff8d',\n    'A200': '#ffff00',\n    'A400': '#ffea00',\n    'A700': '#ffd600',\n    'contrastDefaultColor': 'dark'\n  },\n  'amber': {\n    '50': '#fff8e1',\n    '100': '#ffecb3',\n    '200': '#ffe082',\n    '300': '#ffd54f',\n    '400': '#ffca28',\n    '500': '#ffc107',\n    '600': '#ffb300',\n    '700': '#ffa000',\n    '800': '#ff8f00',\n    '900': '#ff6f00',\n    'A100': '#ffe57f',\n    'A200': '#ffd740',\n    'A400': '#ffc400',\n    'A700': '#ffab00',\n    'contrastDefaultColor': 'dark'\n  },\n  'orange': {\n    '50': '#fff3e0',\n    '100': '#ffe0b2',\n    '200': '#ffcc80',\n    '300': '#ffb74d',\n    '400': '#ffa726',\n    '500': '#ff9800',\n    '600': '#fb8c00',\n    '700': '#f57c00',\n    '800': '#ef6c00',\n    '900': '#e65100',\n    'A100': '#ffd180',\n    'A200': '#ffab40',\n    'A400': '#ff9100',\n    'A700': '#ff6d00',\n    'contrastDefaultColor': 'dark',\n    'contrastStrongLightColors': '900'\n  },\n  'deep-orange': {\n    '50': '#fbe9e7',\n    '100': '#ffccbc',\n    '200': '#ffab91',\n    '300': '#ff8a65',\n    '400': '#ff7043',\n    '500': '#ff5722',\n    '600': '#f4511e',\n    '700': '#e64a19',\n    '800': '#d84315',\n    '900': '#bf360c',\n    'A100': '#ff9e80',\n    'A200': '#ff6e40',\n    'A400': '#ff3d00',\n    'A700': '#dd2c00',\n    'contrastDefaultColor': 'dark',\n    // Dark on 700 does not meet the minimum 4.5 contrast ratio (at 4.01),\n    // but it's worse with a white foreground (3.91).\n    // White on 800 does not meet the minimum 4.5 contrast ratio (at 4.43),\n    // but it's worse with a dark foreground (3.54).\n    'contrastStrongLightColors': '800 900 A400 A700',\n  },\n  'brown': {\n    '50': '#efebe9',\n    '100': '#d7ccc8',\n    '200': '#bcaaa4',\n    '300': '#a1887f',\n    '400': '#8d6e63',\n    '500': '#795548',\n    '600': '#6d4c41',\n    '700': '#5d4037',\n    '800': '#4e342e',\n    '900': '#3e2723',\n    'A100': '#d7ccc8',\n    'A200': '#bcaaa4',\n    'A400': '#8d6e63',\n    'A700': '#5d4037',\n    'contrastDefaultColor': 'light',\n    'contrastDarkColors': '50 100 200 300 A100 A200',\n    'contrastStrongLightColors': '400 500 600 700 800 900 A400 A700'\n  },\n  'grey': {\n    '50': '#fafafa',\n    '100': '#f5f5f5',\n    '200': '#eeeeee',\n    '300': '#e0e0e0',\n    '400': '#bdbdbd',\n    '500': '#9e9e9e',\n    '600': '#757575',\n    '700': '#616161',\n    '800': '#424242',\n    '900': '#212121',\n    'A100': '#ffffff',\n    'A200': '#000000',\n    'A400': '#303030',\n    'A700': '#616161',\n    'contrastDefaultColor': 'dark',\n    'contrastLightColors': '700 800 900 A200 A400 A700',\n    'contrastStrongLightColors': '600'\n  },\n  'blue-grey': {\n    '50': '#eceff1',\n    '100': '#cfd8dc',\n    '200': '#b0bec5',\n    '300': '#90a4ae',\n    '400': '#78909c',\n    '500': '#607d8b',\n    '600': '#546e7a',\n    '700': '#455a64',\n    '800': '#37474f',\n    '900': '#263238',\n    'A100': '#cfd8dc',\n    'A200': '#b0bec5',\n    'A400': '#78909c',\n    'A700': '#455a64',\n    'contrastDefaultColor': 'light',\n    'contrastDarkColors': '50 100 200 300 400 A100 A200 A400',\n    // White on 500 does not meet the minimum 4.5 contrast ratio (at 4.37),\n    // but it's worse with a dark foreground.\n    'contrastStrongLightColors': '500 600 700 800 900 A700'\n  }\n});\n\n})();\n(function(){\n\"use strict\";\n\n(function(angular) {\n  'use strict';\n/**\n * @ngdoc module\n * @name material.core.theming\n * @description\n * Theming\n */\ndetectDisabledThemes.$inject = [\"$mdThemingProvider\"];\nThemingDirective.$inject = [\"$mdTheming\", \"$interpolate\", \"$parse\", \"$mdUtil\", \"$q\", \"$log\"];\nThemableDirective.$inject = [\"$mdTheming\"];\nThemingProvider.$inject = [\"$mdColorPalette\", \"$$mdMetaProvider\"];\ngenerateAllThemes.$inject = [\"$injector\", \"$mdTheming\"];\nangular.module('material.core.theming', ['material.core.theming.palette', 'material.core.meta'])\n  .directive('mdTheme', ThemingDirective)\n  .directive('mdThemable', ThemableDirective)\n  .directive('mdThemesDisabled', disableThemesDirective)\n  .provider('$mdTheming', ThemingProvider)\n  .config(detectDisabledThemes)\n  .run(generateAllThemes);\n\n/**\n * Detect if the HTML or the BODY tags has a [md-themes-disabled] attribute\n * If yes, then immediately disable all theme stylesheet generation and DOM injection\n */\n/**\n * @ngInject\n */\nfunction detectDisabledThemes($mdThemingProvider) {\n  var isDisabled = !!document.querySelector('[md-themes-disabled]');\n  $mdThemingProvider.disableTheming(isDisabled);\n}\n\n/**\n * @ngdoc service\n * @name $mdThemingProvider\n * @module material.core.theming\n *\n * @description Provider to configure the `$mdTheming` service.\n *\n * ### Default Theme\n * The `$mdThemingProvider` uses by default the following theme configuration:\n *\n * - Primary Palette: `Blue`\n * - Accent Palette: `Pink`\n * - Warn Palette: `Deep-Orange`\n * - Background Palette: `Grey`\n *\n * If you don't want to use the `md-theme` directive on the elements itself, you may want to overwrite\n * the default theme.<br/>\n * This can be done by using the following markup.\n *\n * <hljs lang=\"js\">\n *   myAppModule.config(function($mdThemingProvider) {\n *     $mdThemingProvider\n *       .theme('default')\n *       .primaryPalette('blue')\n *       .accentPalette('teal')\n *       .warnPalette('red')\n *       .backgroundPalette('grey');\n *   });\n * </hljs>\n *\n\n * ### Dynamic Themes\n *\n * By default, if you change a theme at runtime, the `$mdTheming` service will not detect those changes.<br/>\n * If you have an application, which changes its theme on runtime, you have to enable theme watching.\n *\n * <hljs lang=\"js\">\n *   myAppModule.config(function($mdThemingProvider) {\n *     // Enable theme watching.\n *     $mdThemingProvider.alwaysWatchTheme(true);\n *   });\n * </hljs>\n *\n * ### Custom Theme Styles\n *\n * Sometimes you may want to use your own theme styles for some custom components.<br/>\n * You are able to register your own styles by using the following markup.\n *\n * <hljs lang=\"js\">\n *   myAppModule.config(function($mdThemingProvider) {\n *     // Register our custom stylesheet into the theming provider.\n *     $mdThemingProvider.registerStyles(STYLESHEET);\n *   });\n * </hljs>\n *\n * The `registerStyles` method only accepts strings as value, so you're actually not able to load an external\n * stylesheet file into the `$mdThemingProvider`.\n *\n * If it's necessary to load an external stylesheet, we suggest using a bundler, which supports including raw content,\n * like [raw-loader](https://github.com/webpack/raw-loader) for `webpack`.\n *\n * <hljs lang=\"js\">\n *   myAppModule.config(function($mdThemingProvider) {\n *     // Register your custom stylesheet into the theming provider.\n *     $mdThemingProvider.registerStyles(require('../styles/my-component.theme.css'));\n *   });\n * </hljs>\n *\n * ### Browser color\n *\n * Enables browser header coloring\n * for more info please visit:\n * https://developers.google.com/web/fundamentals/design-and-ui/browser-customization/theme-color\n *\n * Options parameter: <br/>\n * `theme`   - A defined theme via `$mdThemeProvider` to use the palettes from. Default is `default` theme. <br/>\n * `palette` - Can be any one of the basic material design palettes, extended defined palettes and 'primary',\n *             'accent', 'background' and 'warn'. Default is `primary`. <br/>\n * `hue`     - The hue from the selected palette. Default is `800`<br/>\n *\n * <hljs lang=\"js\">\n *   myAppModule.config(function($mdThemingProvider) {\n *     // Enable browser color\n *     $mdThemingProvider.enableBrowserColor({\n *       theme: 'myTheme', // Default is 'default'\n *       palette: 'accent', // Default is 'primary', any basic material palette and extended palettes are available\n *       hue: '200' // Default is '800'\n *     });\n *   });\n * </hljs>\n */\n\n/**\n * Some Example Valid Theming Expressions\n * =======================================\n *\n * Intention group expansion: (valid for primary, accent, warn, background)\n *\n * {{primary-100}} - grab shade 100 from the primary palette\n * {{primary-100-0.7}} - grab shade 100, apply opacity of 0.7\n * {{primary-100-contrast}} - grab shade 100's contrast color\n * {{primary-hue-1}} - grab the shade assigned to hue-1 from the primary palette\n * {{primary-hue-1-0.7}} - apply 0.7 opacity to primary-hue-1\n * {{primary-color}} - Generates .md-hue-1, .md-hue-2, .md-hue-3 with configured shades set for each hue\n * {{primary-color-0.7}} - Apply 0.7 opacity to each of the above rules\n * {{primary-contrast}} - Generates .md-hue-1, .md-hue-2, .md-hue-3 with configured contrast (ie. text) color shades set for each hue\n * {{primary-contrast-0.7}} - Apply 0.7 opacity to each of the above rules\n * {{primary-contrast-divider}} - Apply divider opacity to contrast color\n *\n * Foreground expansion: Applies rgba to black/white foreground text\n *\n * Old Foreground Expressions:\n * {{foreground-1}} - used for primary text\n * {{foreground-2}} - used for secondary text/divider\n * {{foreground-3}} - used for disabled text\n * {{foreground-4}} - used for dividers\n *\n * New Foreground Expressions:\n *\n * Apply primary text color for contrasting with default background\n *  {{background-default-contrast}} - default opacity\n *  {{background-default-contrast-secondary}} - opacity for secondary text\n *  {{background-default-contrast-hint}} - opacity for hints and placeholders\n *  {{background-default-contrast-disabled}} - opacity for disabled text\n *  {{background-default-contrast-divider}} - opacity for dividers\n *\n * Apply contrast color for specific shades\n *  {{background-50-contrast-icon}} - Apply contrast color for icon on background's shade 50 hue\n */\n\n// In memory generated CSS rules; registered by theme.name\nvar GENERATED = { };\n\n// In memory storage of defined themes and color palettes (both loaded by CSS, and user specified)\nvar PALETTES;\n\n// Text colors are automatically generated based on background color when not specified\n// Custom palettes can provide override colors\n// @see https://material.io/archive/guidelines/style/color.html#color-usability\nvar DARK_FOREGROUND = {\n  name: 'dark',\n};\nvar LIGHT_FOREGROUND = {\n  name: 'light',\n};\n\nvar DARK_SHADOW = '1px 1px 0px rgba(0,0,0,0.4), -1px -1px 0px rgba(0,0,0,0.4)';\nvar LIGHT_SHADOW = '';\n\nvar DARK_CONTRAST_COLOR = colorToRgbaArray('rgba(0,0,0,0.87)');\nvar LIGHT_CONTRAST_COLOR = colorToRgbaArray('rgba(255,255,255,0.87)');\nvar STRONG_LIGHT_CONTRAST_COLOR = colorToRgbaArray('rgb(255,255,255)');\n\nvar THEME_COLOR_TYPES = ['primary', 'accent', 'warn', 'background'];\nvar DEFAULT_COLOR_TYPE = 'primary';\n\n// A color in a theme will use these hues by default, if not specified by user.\nvar LIGHT_DEFAULT_HUES = {\n  'accent': {\n    'default': 'A200',\n    'hue-1': 'A100',\n    'hue-2': 'A400',\n    'hue-3': 'A700'\n  },\n  'background': {\n    'default': '50',\n    'hue-1': 'A100',\n    'hue-2': '100',\n    'hue-3': '300'\n  }\n};\n\nvar DARK_DEFAULT_HUES = {\n  'background': {\n    'default': 'A400',\n    'hue-1': '800',\n    'hue-2': '900',\n    'hue-3': 'A200'\n  }\n};\n\n// Icon opacity values (active/inactive) from\n// https://material.io/archive/guidelines/style/color.html#color-usability\nvar DARK_CONTRAST_OPACITY = {\n  'icon': 0.54,\n  'secondary': 0.54,\n  'disabled': 0.38,\n  'hint': 0.38,\n  'divider': 0.12,\n};\n\nvar LIGHT_CONTRAST_OPACITY = {\n  'icon': 0.87,\n  'secondary': 0.7,\n  'disabled': 0.5,\n  'hint': 0.5,\n  'divider': 0.12\n};\n\n// Icon opacity values (active/inactive) from\n// https://material.io/archive/guidelines/style/color.html#color-usability\nvar STRONG_LIGHT_CONTRAST_OPACITY = {\n  'icon': 1.0,\n  'secondary': 0.7,\n  'disabled': 0.5,\n  'hint': 0.5,\n  'divider': 0.12\n};\n\nTHEME_COLOR_TYPES.forEach(function(colorType) {\n  // Color types with unspecified default hues will use these default hue values\n  var defaultDefaultHues = {\n    'default': '500',\n    'hue-1': '300',\n    'hue-2': '800',\n    'hue-3': 'A100'\n  };\n  if (!LIGHT_DEFAULT_HUES[colorType]) LIGHT_DEFAULT_HUES[colorType] = defaultDefaultHues;\n  if (!DARK_DEFAULT_HUES[colorType]) DARK_DEFAULT_HUES[colorType] = defaultDefaultHues;\n});\n\nvar VALID_HUE_VALUES = [\n  '50', '100', '200', '300', '400', '500', '600',\n  '700', '800', '900', 'A100', 'A200', 'A400', 'A700'\n];\n\nvar themeConfig = {\n  disableTheming : false,   // Generate our themes at run time; also disable stylesheet DOM injection\n  generateOnDemand : false, // Whether or not themes are to be generated on-demand (vs. eagerly).\n  registeredStyles : [],    // Custom styles registered to be used in the theming of custom components.\n  nonce : null              // Nonce to be added as an attribute to the generated themes style tags.\n};\n\n/**\n *\n */\nfunction ThemingProvider($mdColorPalette, $$mdMetaProvider) {\n  ThemingService.$inject = [\"$rootScope\", \"$mdUtil\", \"$q\", \"$log\"];\n  PALETTES = { };\n  var THEMES = { };\n\n  var themingProvider;\n\n  var alwaysWatchTheme = false;\n  var defaultTheme = 'default';\n\n  // Load JS Defined Palettes\n  angular.extend(PALETTES, $mdColorPalette);\n\n  // Default theme defined in core.js\n\n  /**\n   * Adds `theme-color` and `msapplication-navbutton-color` meta tags with the color parameter\n   * @param {string} color Hex value of the wanted browser color\n   * @returns {function} Remove function of the meta tags\n   */\n  var setBrowserColor = function (color) {\n    // Chrome, Firefox OS and Opera\n    var removeChrome = $$mdMetaProvider.setMeta('theme-color', color);\n    // Windows Phone\n    var removeWindows = $$mdMetaProvider.setMeta('msapplication-navbutton-color', color);\n\n    return function () {\n      removeChrome();\n      removeWindows();\n    };\n  };\n\n  /**\n   * @ngdoc method\n   * @name $mdThemingProvider#enableBrowserColor\n   * @description\n   * Enables browser header coloring. For more info please visit\n   * <a href=\"https://developers.google.com/web/fundamentals/design-and-ui/browser-customization/theme-color\">\n   *   Web Fundamentals</a>.\n   * @param {object=} options Options for the browser color, which include:<br/>\n   * - `theme` - `{string}`: A defined theme via `$mdThemeProvider` to use the palettes from. Default is `default` theme. <br/>\n   * - `palette` - `{string}`:  Can be any one of the basic material design palettes, extended defined palettes, or `primary`,\n   *  `accent`, `background`, and `warn`. Default is `primary`.<br/>\n   * - `hue` -  `{string}`: The hue from the selected palette. Default is `800`.<br/>\n   * @returns {function} Function that removes the browser coloring when called.\n   */\n  var enableBrowserColor = function (options) {\n    options = angular.isObject(options) ? options : {};\n\n    var theme = options.theme || 'default';\n    var hue = options.hue || '800';\n\n    var palette = PALETTES[options.palette] ||\n      PALETTES[THEMES[theme].colors[options.palette || 'primary'].name];\n\n    var color = angular.isObject(palette[hue]) ? palette[hue].hex : palette[hue];\n    if (color.substr(0, 1) !== '#') color = '#' + color;\n\n    return setBrowserColor(color);\n  };\n\n  return themingProvider = {\n    definePalette: definePalette,\n    extendPalette: extendPalette,\n    theme: registerTheme,\n\n    /**\n     * return a read-only clone of the current theme configuration\n     */\n    configuration : function() {\n      return angular.extend({ }, themeConfig, {\n        defaultTheme : defaultTheme,\n        alwaysWatchTheme : alwaysWatchTheme,\n        registeredStyles : [].concat(themeConfig.registeredStyles)\n      });\n    },\n\n    /**\n     * @ngdoc method\n     * @name $mdThemingProvider#disableTheming\n     * @description\n     * An easier way to disable theming without having to use `.constant(\"$MD_THEME_CSS\",\"\");`.\n     * This disables all dynamic theme style sheet generations and injections.\n     * @param {boolean=} isDisabled Disable all dynamic theme style sheet generations and injections\n     *  if `true` or `undefined`.\n     */\n    disableTheming: function(isDisabled) {\n      themeConfig.disableTheming = angular.isUndefined(isDisabled) || !!isDisabled;\n    },\n\n    /**\n     * @ngdoc method\n     * @name $mdThemingProvider#registerStyles\n     * @param {string} styles The styles to be appended to AngularJS Material's built in theme CSS.\n     */\n    registerStyles: function(styles) {\n      themeConfig.registeredStyles.push(styles);\n    },\n\n    /**\n     * @ngdoc method\n     * @name $mdThemingProvider#setNonce\n     * @param {string} nonceValue The nonce to be added as an attribute to the theme style tags.\n     * Setting a value allows the use of CSP policy without using the `'unsafe-inline'` directive.\n     * The string must already be base64 encoded. You can use `btoa(string)` to do this encoding.\n     * In your CSP's `style-src`, you would then add an entry for `'nonce-nonceValue'`.\n     */\n    setNonce: function(nonceValue) {\n      themeConfig.nonce = nonceValue;\n    },\n\n    generateThemesOnDemand: function(onDemand) {\n      themeConfig.generateOnDemand = onDemand;\n    },\n\n    /**\n     * @ngdoc method\n     * @name $mdThemingProvider#setDefaultTheme\n     * @param {string} theme Default theme name to be applied to elements.\n     *  Default value is `default`.\n     */\n    setDefaultTheme: function(theme) {\n      defaultTheme = theme;\n    },\n\n    /**\n     * @ngdoc method\n     * @name $mdThemingProvider#alwaysWatchTheme\n     * @param {boolean} alwaysWatch Whether or not to always watch themes for changes and re-apply\n     * classes when they change. Default is `false`. Enabling can reduce performance.\n     */\n    alwaysWatchTheme: function(alwaysWatch) {\n      alwaysWatchTheme = alwaysWatch;\n    },\n\n    enableBrowserColor: enableBrowserColor,\n\n    $get: ThemingService,\n    _LIGHT_DEFAULT_HUES: LIGHT_DEFAULT_HUES,\n    _DARK_DEFAULT_HUES: DARK_DEFAULT_HUES,\n    _PALETTES: PALETTES,\n    _THEMES: THEMES,\n    _parseRules: parseRules,\n    _rgba: rgba\n  };\n\n  /**\n   * @ngdoc method\n   * @name $mdThemingProvider#definePalette\n   * @description\n   * In the event that you need to define a custom color palette, you can use this function to\n   * make it available to your theme for use in its intention groups.<br>\n   * Note that you must specify all hues in the definition map.\n   * @param {string} name Name of palette being defined\n   * @param {object} map Palette definition that includes hue definitions and contrast colors:\n   * - `'50'` - `{string}`: HEX color\n   * - `'100'` - `{string}`: HEX color\n   * - `'200'` - `{string}`: HEX color\n   * - `'300'` - `{string}`: HEX color\n   * - `'400'` - `{string}`: HEX color\n   * - `'500'` - `{string}`: HEX color\n   * - `'600'` - `{string}`: HEX color\n   * - `'700'` - `{string}`: HEX color\n   * - `'800'` - `{string}`: HEX color\n   * - `'900'` - `{string}`: HEX color\n   * - `'A100'` - `{string}`: HEX color\n   * - `'A200'` - `{string}`: HEX color\n   * - `'A400'` - `{string}`: HEX color\n   * - `'A700'` - `{string}`: HEX color\n   * - `'contrastDefaultColor'` - `{string}`: `light` or `dark`\n   * - `'contrastDarkColors'` - `{string[]}`: Hues which should use dark contrast colors (i.e. raised button text).\n   *  For example: `['50', '100', '200', '300', '400', 'A100']`.\n   * - `'contrastLightColors'` - `{string[]}`: Hues which should use light contrast colors (i.e. raised button text).\n   *  For example: `['500', '600', '700', '800', '900', 'A200', 'A400', 'A700']`.\n   */\n  function definePalette(name, map) {\n    map = map || {};\n    PALETTES[name] = checkPaletteValid(name, map);\n    return themingProvider;\n  }\n\n  /**\n   * @ngdoc method\n   * @name $mdThemingProvider#extendPalette\n   * @description\n   * Sometimes it is easier to extend an existing color palette and then change a few properties,\n   * rather than defining a whole new palette.\n   * @param {string} name Name of palette being extended\n   * @param {object} map Palette definition that includes optional hue definitions and contrast colors:\n   * - `'50'` - `{string}`: HEX color\n   * - `'100'` - `{string}`: HEX color\n   * - `'200'` - `{string}`: HEX color\n   * - `'300'` - `{string}`: HEX color\n   * - `'400'` - `{string}`: HEX color\n   * - `'500'` - `{string}`: HEX color\n   * - `'600'` - `{string}`: HEX color\n   * - `'700'` - `{string}`: HEX color\n   * - `'800'` - `{string}`: HEX color\n   * - `'900'` - `{string}`: HEX color\n   * - `'A100'` - `{string}`: HEX color\n   * - `'A200'` - `{string}`: HEX color\n   * - `'A400'` - `{string}`: HEX color\n   * - `'A700'` - `{string}`: HEX color\n   * - `'contrastDefaultColor'` - `{string}`: `light` or `dark`\n   * - `'contrastDarkColors'` - `{string[]}`: Hues which should use dark contrast colors (i.e. raised button text).\n   *  For example: `['50', '100', '200', '300', '400', 'A100']`.\n   * - `'contrastLightColors'` - `{string[]}`: Hues which should use light contrast colors (i.e. raised button text).\n   *  For example: `['500', '600', '700', '800', '900', 'A200', 'A400', 'A700']`.\n   *  @returns {object} A new object which is a copy of the given palette, `name`,\n   *    with variables from `map` overwritten.\n   */\n  function extendPalette(name, map) {\n    return checkPaletteValid(name,  angular.extend({}, PALETTES[name] || {}, map));\n  }\n\n  // Make sure that palette has all required hues\n  function checkPaletteValid(name, map) {\n    var missingColors = VALID_HUE_VALUES.filter(function(field) {\n      return !map[field];\n    });\n    if (missingColors.length) {\n      throw new Error(\"Missing colors %1 in palette %2!\"\n                      .replace('%1', missingColors.join(', '))\n                      .replace('%2', name));\n    }\n\n    return map;\n  }\n\n  /**\n   * @ngdoc method\n   * @name $mdThemingProvider#theme\n   * @description\n   * Register a theme (which is a collection of color palettes); i.e. `warn`, `accent`,\n   * `background`, and `primary`.<br>\n   * Optionally inherit from an existing theme.\n   * @param {string} name Name of theme being registered\n   * @param {string=} inheritFrom Existing theme name to inherit from\n   */\n  function registerTheme(name, inheritFrom) {\n    if (THEMES[name]) return THEMES[name];\n\n    inheritFrom = inheritFrom || 'default';\n\n    var parentTheme = typeof inheritFrom === 'string' ? THEMES[inheritFrom] : inheritFrom;\n    var theme = new Theme(name);\n\n    if (parentTheme) {\n      angular.forEach(parentTheme.colors, function(color, colorType) {\n        theme.colors[colorType] = {\n          name: color.name,\n          // Make sure a COPY of the hues is given to the child color,\n          // not the same reference.\n          hues: angular.extend({}, color.hues)\n        };\n      });\n    }\n    THEMES[name] = theme;\n\n    return theme;\n  }\n\n  function Theme(name) {\n    var self = this;\n    self.name = name;\n    self.colors = {};\n\n    self.dark = setDark;\n    setDark(false);\n\n    function setDark(isDark) {\n      isDark = arguments.length === 0 ? true : !!isDark;\n\n      // If no change, abort\n      if (isDark === self.isDark) return;\n\n      self.isDark = isDark;\n\n      self.foregroundPalette = self.isDark ? LIGHT_FOREGROUND : DARK_FOREGROUND;\n      self.foregroundShadow = self.isDark ? DARK_SHADOW : LIGHT_SHADOW;\n\n      // Light and dark themes have different default hues.\n      // Go through each existing color type for this theme, and for every\n      // hue value that is still the default hue value from the previous light/dark setting,\n      // set it to the default hue value from the new light/dark setting.\n      var newDefaultHues = self.isDark ? DARK_DEFAULT_HUES : LIGHT_DEFAULT_HUES;\n      var oldDefaultHues = self.isDark ? LIGHT_DEFAULT_HUES : DARK_DEFAULT_HUES;\n      angular.forEach(newDefaultHues, function(newDefaults, colorType) {\n        var color = self.colors[colorType];\n        var oldDefaults = oldDefaultHues[colorType];\n        if (color) {\n          for (var hueName in color.hues) {\n            if (color.hues[hueName] === oldDefaults[hueName]) {\n              color.hues[hueName] = newDefaults[hueName];\n            }\n          }\n        }\n      });\n\n      return self;\n    }\n\n    THEME_COLOR_TYPES.forEach(function(colorType) {\n      var defaultHues = (self.isDark ? DARK_DEFAULT_HUES : LIGHT_DEFAULT_HUES)[colorType];\n      self[colorType + 'Palette'] = function setPaletteType(paletteName, hues) {\n        var color = self.colors[colorType] = {\n          name: paletteName,\n          hues: angular.extend({}, defaultHues, hues)\n        };\n\n        Object.keys(color.hues).forEach(function(name) {\n          if (!defaultHues[name]) {\n            throw new Error(\"Invalid hue name '%1' in theme %2's %3 color %4. Available hue names: %4\"\n              .replace('%1', name)\n              .replace('%2', self.name)\n              .replace('%3', paletteName)\n              .replace('%4', Object.keys(defaultHues).join(', '))\n            );\n          }\n        });\n        Object.keys(color.hues).map(function(key) {\n          return color.hues[key];\n        }).forEach(function(hueValue) {\n          if (VALID_HUE_VALUES.indexOf(hueValue) === -1) {\n            throw new Error(\"Invalid hue value '%1' in theme %2's %3 color %4. Available hue values: %5\"\n              .replace('%1', hueValue)\n              .replace('%2', self.name)\n              .replace('%3', colorType)\n              .replace('%4', paletteName)\n              .replace('%5', VALID_HUE_VALUES.join(', '))\n            );\n          }\n        });\n        return self;\n      };\n    });\n  }\n\n  /**\n   * @ngdoc service\n   * @name $mdTheming\n   * @module material.core.theming\n   * @description\n   * Service that makes an element apply theming related <b>classes</b> to itself.\n   *\n   * For more information on the hue objects, their default values, as well as valid hue values, please visit <a ng-href=\"Theming/03_configuring_a_theme#specifying-custom-hues-for-color-intentions\">the custom hues section of Configuring a Theme</a>.\n   *\n   * <hljs lang=\"js\">\n   * // Example component directive that we want to apply theming classes to.\n   * app.directive('myFancyDirective', function($mdTheming) {\n   *   return {\n   *     restrict: 'AE',\n   *     link: function(scope, element, attrs) {\n   *       // Initialize the service using our directive's element\n   *       $mdTheming(element);\n   *\n   *       $mdTheming.defineTheme('myTheme', {\n   *         primary: 'blue',\n   *         primaryHues: {\n   *           default: '500',\n   *           hue-1: '300',\n   *           hue-2: '900',\n   *           hue-3: 'A100'\n   *         },\n   *         accent: 'pink',\n   *         accentHues: {\n   *           default: '600',\n   *           hue-1: '300',\n   *           hue-2: '200',\n   *           hue-3: 'A500'\n   *         },\n   *         warn: 'red',\n   *         // It's not necessary to specify all hues in the object.\n   *         warnHues: {\n   *           default: '200',\n   *           hue-3: 'A100'\n   *         },\n   *         // It's not necessary to specify custom hues at all.\n   *         background: 'grey',\n   *         dark: true\n   *       });\n   *       // Your directive's custom code here.\n   *     }\n   *   };\n   * });\n   * </hljs>\n   * @param {element=} element Element that will have theming classes applied to it.\n   */\n\n  /**\n   * @ngdoc property\n   * @name $mdTheming#THEMES\n   * @description\n   * Property to get all the themes defined\n   * @returns {object} All the themes defined with their properties.\n   */\n\n  /**\n   * @ngdoc property\n   * @name $mdTheming#PALETTES\n   * @description\n   * Property to get all the palettes defined\n   * @returns {object} All the palettes defined with their colors.\n   */\n\n  /**\n   * @ngdoc method\n   * @name $mdTheming#registered\n   * @description\n   * Determine is specified theme name is a valid, registered theme\n   * @param {string} themeName the theme to check if registered\n   * @returns {boolean} whether the theme is registered or not\n   */\n\n  /**\n   * @ngdoc method\n   * @name $mdTheming#defaultTheme\n   * @description\n   * Returns the default theme\n   * @returns {string} The default theme\n   */\n\n  /**\n   * @ngdoc method\n   * @name $mdTheming#generateTheme\n   * @description\n   * Lazy generate themes - by default, every theme is generated when defined.\n   * You can disable this in the configuration section using the\n   * `$mdThemingProvider.generateThemesOnDemand(true);`\n   *\n   * The theme name that is passed in must match the name of the theme that was defined as part of\n   * the configuration block.\n   *\n   * @param {string} name theme name to generate\n   */\n\n  /**\n   * @ngdoc method\n   * @name $mdTheming#setBrowserColor\n   * @description\n   * Enables browser header coloring. For more info please visit\n   * <a href=\"https://developers.google.com/web/fundamentals/design-and-ui/browser-customization/theme-color\">\n   *   Web Fundamentals</a>.\n   * @param {object=} options Options for the browser color, which include:<br/>\n   * - `theme` - `{string}`: A defined theme via `$mdThemeProvider` to use the palettes from.\n   *    Default is `default` theme. <br/>\n   * - `palette` - `{string}`:  Can be any one of the basic material design palettes, extended\n   *    defined palettes, or `primary`, `accent`, `background`, and `warn`. Default is `primary`.\n   * <br/>\n   * - `hue` -  `{string}`: The hue from the selected palette. Default is `800`.<br/>\n   * @returns {function} Function that removes the browser coloring when called.\n   */\n\n  /**\n   * @ngdoc method\n   * @name $mdTheming#defineTheme\n   * @description\n   * Dynamically define a theme by using an options object that contains palette names.\n   *\n   * @param {string} name Theme name to define\n   * @param {object} options Theme definition options\n   *\n   * Options are:<br/>\n   * - `primary` - `{string}`: The name of the primary palette to use in the theme.<br/>\n   * - `primaryHues` - `{object=}`: Override hues for primary palette.<br/>\n   * - `accent` - `{string}`: The name of the accent palette to use in the theme.<br/>\n   * - `accentHues` - `{object=}`: Override hues for accent palette.<br/>\n   * - `warn` - `{string}`: The name of the warn palette to use in the theme.<br/>\n   * - `warnHues` - `{object=}`: Override hues for warn palette.<br/>\n   * - `background` - `{string}`: The name of the background palette to use in the theme.<br/>\n   * - `backgroundHues` - `{object=}`: Override hues for background palette.<br/>\n   * - `dark` - `{boolean}`: Indicates if it's a dark theme.<br/>\n   * @returns {Promise<string>} A resolved promise with the new theme name.\n   */\n\n  /* @ngInject */\n  function ThemingService($rootScope, $mdUtil, $q, $log) {\n    // Allow us to be invoked via a linking function signature.\n    var applyTheme = function (scope, el) {\n      if (el === undefined) { el = scope; scope = undefined; }\n      if (scope === undefined) { scope = $rootScope; }\n      applyTheme.inherit(el, el);\n    };\n\n    Object.defineProperty(applyTheme, 'THEMES', {\n      get: function () {\n        return angular.extend({}, THEMES);\n      }\n    });\n    Object.defineProperty(applyTheme, 'PALETTES', {\n      get: function () {\n        return angular.extend({}, PALETTES);\n      }\n    });\n    Object.defineProperty(applyTheme, 'ALWAYS_WATCH', {\n      get: function () {\n        return alwaysWatchTheme;\n      }\n    });\n    applyTheme.inherit = inheritTheme;\n    applyTheme.registered = registered;\n    applyTheme.defaultTheme = function() { return defaultTheme; };\n    applyTheme.generateTheme = function(name) { generateTheme(THEMES[name], name, themeConfig.nonce); };\n    applyTheme.defineTheme = function(name, options) {\n      options = options || {};\n\n      var theme = registerTheme(name);\n\n      if (options.primary) {\n        theme.primaryPalette(options.primary, options.primaryHues);\n      }\n      if (options.accent) {\n        theme.accentPalette(options.accent, options.accentHues);\n      }\n      if (options.warn) {\n        theme.warnPalette(options.warn, options.warnHues);\n      }\n      if (options.background) {\n        theme.backgroundPalette(options.background, options.backgroundHues);\n      }\n      if (options.dark){\n        theme.dark();\n      }\n\n      this.generateTheme(name);\n\n      return $q.resolve(name);\n    };\n    applyTheme.setBrowserColor = enableBrowserColor;\n\n    return applyTheme;\n\n    /**\n     * Determine is specified theme name is a valid, registered theme\n     */\n    function registered(themeName) {\n      if (themeName === undefined || themeName === '') return true;\n      return applyTheme.THEMES[themeName] !== undefined;\n    }\n\n    /**\n     * Get theme name for the element, then update with Theme CSS class\n     */\n    function inheritTheme (el, parent) {\n      var ctrl = parent.controller('mdTheme') || el.data('$mdThemeController');\n      var scope = el.scope();\n\n      updateThemeClass(lookupThemeName());\n\n      if (ctrl) {\n        var watchTheme = alwaysWatchTheme ||\n                         ctrl.$shouldWatch ||\n                         $mdUtil.parseAttributeBoolean(el.attr('md-theme-watch'));\n\n        if (watchTheme || ctrl.isAsyncTheme) {\n          var clearNameWatcher = function () {\n            if (unwatch) {\n              unwatch();\n              unwatch = undefined;\n            }\n          };\n\n          var unwatch = ctrl.registerChanges(function(name) {\n            updateThemeClass(name);\n\n            if (!watchTheme) {\n              clearNameWatcher();\n            }\n          });\n\n          if (scope) {\n            scope.$on('$destroy', clearNameWatcher);\n          } else {\n            el.on('$destroy', clearNameWatcher);\n          }\n        }\n      }\n\n      /**\n       * Find the theme name from the parent controller or element data\n       */\n      function lookupThemeName() {\n        // As a few components (dialog) add their controllers later, we should also watch for a controller init.\n        return ctrl && ctrl.$mdTheme || (defaultTheme === 'default' ? '' : defaultTheme);\n      }\n\n      /**\n       * Remove old theme class and apply a new one\n       * NOTE: if not a valid theme name, then the current name is not changed\n       */\n      function updateThemeClass(theme) {\n        if (!theme) return;\n        if (!registered(theme)) {\n          $log.warn('Attempted to use unregistered theme \\'' + theme + '\\'. ' +\n                    'Register it with $mdThemingProvider.theme().');\n        }\n\n        var oldTheme = el.data('$mdThemeName');\n        if (oldTheme) el.removeClass('md-' + oldTheme +'-theme');\n        el.addClass('md-' + theme + '-theme');\n        el.data('$mdThemeName', theme);\n        if (ctrl) {\n          el.data('$mdThemeController', ctrl);\n        }\n      }\n    }\n\n  }\n}\n\nfunction ThemingDirective($mdTheming, $interpolate, $parse, $mdUtil, $q, $log) {\n  return {\n    priority: 101, // has to be more than 100 to be before interpolation (issue on IE)\n    link: {\n      pre: function(scope, el, attrs) {\n        var registeredCallbacks = [];\n\n        var startSymbol = $interpolate.startSymbol();\n        var endSymbol = $interpolate.endSymbol();\n\n        var theme = attrs.mdTheme.trim();\n\n        var hasInterpolation =\n          theme.substr(0, startSymbol.length) === startSymbol &&\n          theme.lastIndexOf(endSymbol) === theme.length - endSymbol.length;\n\n        var oneTimeOperator = '::';\n        var oneTimeBind = attrs.mdTheme\n            .split(startSymbol).join('')\n            .split(endSymbol).join('')\n            .trim()\n            .substr(0, oneTimeOperator.length) === oneTimeOperator;\n\n        var getTheme = function () {\n          var interpolation = $interpolate(attrs.mdTheme)(scope);\n          return $parse(interpolation)(scope) || interpolation;\n        };\n\n        var ctrl = {\n          isAsyncTheme: angular.isFunction(getTheme()) || angular.isFunction(getTheme().then),\n          registerChanges: function (cb, context) {\n            if (context) {\n              cb = angular.bind(context, cb);\n            }\n\n            registeredCallbacks.push(cb);\n\n            return function () {\n              var index = registeredCallbacks.indexOf(cb);\n\n              if (index > -1) {\n                registeredCallbacks.splice(index, 1);\n              }\n            };\n          },\n          $setTheme: function (theme) {\n            if (!$mdTheming.registered(theme)) {\n              $log.warn('attempted to use unregistered theme \\'' + theme + '\\'');\n            }\n\n            ctrl.$mdTheme = theme;\n\n            // Iterating backwards to support unregistering during iteration\n            // http://stackoverflow.com/a/9882349/890293\n            // we don't use `reverse()` of array because it mutates the array and we don't want it\n            // to get re-indexed\n            for (var i = registeredCallbacks.length; i--;) {\n              registeredCallbacks[i](theme);\n            }\n          },\n          $shouldWatch: $mdUtil.parseAttributeBoolean(el.attr('md-theme-watch')) ||\n                        $mdTheming.ALWAYS_WATCH ||\n                        (hasInterpolation && !oneTimeBind)\n        };\n\n        el.data('$mdThemeController', ctrl);\n\n        var setParsedTheme = function (theme) {\n          if (typeof theme === 'string') {\n            return ctrl.$setTheme(theme);\n          }\n\n          $q.when(angular.isFunction(theme) ?  theme() : theme)\n            .then(function(name) {\n              ctrl.$setTheme(name);\n            });\n        };\n\n        setParsedTheme(getTheme());\n\n        var unwatch = scope.$watch(getTheme, function(theme) {\n          if (theme) {\n            setParsedTheme(theme);\n\n            if (!ctrl.$shouldWatch) {\n              unwatch();\n            }\n          }\n        });\n      }\n    }\n  };\n}\n\n/**\n * Special directive that will disable ALL runtime Theme style generation and DOM injection\n *\n * <link rel=\"stylesheet\" href=\"angular-material.min.css\">\n * <link rel=\"stylesheet\" href=\"angular-material.themes.css\">\n *\n * <body md-themes-disabled>\n *  ...\n * </body>\n *\n * Note: Using md-themes-css directive requires the developer to load external\n * theme stylesheets; e.g. custom themes from Material-Tools:\n *\n *       `angular-material.themes.css`\n *\n * Another option is to use the ThemingProvider to configure and disable the attribute\n * conversions; this would obviate the use of the `md-themes-css` directive\n *\n */\nfunction disableThemesDirective() {\n  themeConfig.disableTheming = true;\n\n  // Return a 1x-only, first-match attribute directive\n  return {\n    restrict : 'A',\n    priority : '900'\n  };\n}\n\nfunction ThemableDirective($mdTheming) {\n  return $mdTheming;\n}\n\nfunction parseRules(theme, colorType, rules) {\n  checkValidPalette(theme, colorType);\n\n  rules = rules.replace(/THEME_NAME/g, theme.name);\n  var themeNameRegex = new RegExp('\\\\.md-' + theme.name + '-theme', 'g');\n  // Matches '{{ primary-color }}', etc\n  var hueRegex = new RegExp('([\\'\"])?{{\\\\s*([a-zA-Z]+)-?(color|default)?-?(contrast)?-?((?:\\\\d\\\\.?\\\\d*)|(?:[a-zA-Z]+))?\\\\s*}}([\"\\'])?','g');\n  var simpleVariableRegex = /'?\"?{{\\s*([a-zA-Z]+)-(A?\\d+|hue-[0-3]|shadow|default)-?(contrast)?-?((?:\\d\\.?\\d*)|(?:[a-zA-Z]+))?\\s*}}'?\"?/g;\n  var defaultBgHue = theme.colors['background'].hues['default'];\n  var defaultBgContrastType = PALETTES[theme.colors['background'].name][defaultBgHue].contrastType;\n\n  // find and replace simple variables where we use a specific hue, not an entire palette\n  // eg. \"{{primary-100}}\"\n  // \\(' + THEME_COLOR_TYPES.join('\\|') + '\\)'\n  rules = rules.replace(simpleVariableRegex, function(match, colorType, hue, contrast, opacity) {\n    var regexColorType = colorType;\n    if (colorType === 'foreground') {\n      if (hue === 'shadow') {\n        return theme.foregroundShadow;\n      } else if (theme.foregroundPalette[hue]) {\n        // Use user defined palette number (ie: foreground-2)\n        return rgba(colorToRgbaArray(theme.foregroundPalette[hue]));\n      } else if (theme.foregroundPalette['1']){\n        return rgba(colorToRgbaArray(theme.foregroundPalette['1']));\n      }\n      // Default to background-default-contrast-{opacity}\n      colorType = 'background';\n      contrast = 'contrast';\n      if (!opacity && hue) {\n        // Convert references to legacy hues to opacities (i.e. foreground-4 to *-divider)\n        switch (hue) {\n          // hue-1 uses default opacity\n          case '2':\n            opacity = 'secondary';\n            break;\n          case '3':\n            opacity = 'disabled';\n            break;\n          case '4':\n            opacity = 'divider';\n        }\n      }\n      hue = 'default';\n    }\n\n    // `default` is also accepted as a hue-value, because the background palettes are\n    // using it as a name for the default hue.\n    if (hue.indexOf('hue') === 0 || hue === 'default') {\n      hue = theme.colors[colorType].hues[hue];\n    }\n\n    var colorDetails = (PALETTES[ theme.colors[colorType].name ][hue] || '');\n\n    // If user has specified a foreground color, use those\n    if (colorType === 'background' && contrast && regexColorType !== 'foreground' &&\n        colorDetails.contrastType === defaultBgContrastType) {\n      // Don't process if colorType was changed\n      switch (opacity) {\n        case 'secondary':\n        case 'icon':\n          if (theme.foregroundPalette['2']) {\n            return rgba(colorToRgbaArray(theme.foregroundPalette['2']));\n          }\n          break;\n        case 'disabled':\n        case 'hint':\n          if (theme.foregroundPalette['3']) {\n            return rgba(colorToRgbaArray(theme.foregroundPalette['3']));\n          }\n          break;\n        case 'divider':\n          if (theme.foregroundPalette['4']) {\n            return rgba(colorToRgbaArray(theme.foregroundPalette['4']));\n          }\n          break;\n        default:\n          if (theme.foregroundPalette['1']) {\n            return rgba(colorToRgbaArray(theme.foregroundPalette['1']));\n          }\n          break;\n      }\n    }\n\n    if (contrast && opacity) {\n      opacity = colorDetails.opacity[opacity] || opacity;\n    }\n\n    return rgba(colorDetails[contrast ? 'contrast' : 'value'], opacity);\n  });\n\n  var generatedRules = [];\n\n  // For each type, generate rules for each hue (ie. default, md-hue-1, md-hue-2, md-hue-3)\n  angular.forEach(['default', 'hue-1', 'hue-2', 'hue-3'], function(hueName) {\n    var newRule = rules\n      .replace(hueRegex, function(match, _, matchedColorType, hueType, contrast, opacity) {\n        var color = theme.colors[matchedColorType];\n        var palette = PALETTES[color.name];\n        var hueValue = color.hues[hueName];\n        if (contrast && opacity) {\n          opacity = palette[hueValue].opacity[opacity] || opacity;\n        }\n        return rgba(palette[hueValue][hueType === 'color' ? 'value' : 'contrast'], opacity);\n      });\n    if (hueName !== 'default') {\n      newRule = newRule.replace(themeNameRegex, '.md-' + theme.name + '-theme.md-' + hueName);\n    }\n\n    // Don't apply a selector rule to the default theme, making it easier to override\n    // styles of the base-component\n    if (theme.name === 'default') {\n      var themeRuleRegex = /((?:\\s|>|\\.|\\w|-|:|\\(|\\)|\\[|]|\"|'|=)*)\\.md-default-theme((?:\\s|>|\\.|\\w|-|:|\\(|\\)|\\[|]|\"|'|=)*)/g;\n\n      newRule = newRule.replace(themeRuleRegex, function(match, start, end) {\n        return match + ', ' + start + end;\n      });\n    }\n    generatedRules.push(newRule);\n  });\n\n  return generatedRules;\n}\n\nvar rulesByType = {};\n\n// Generate our themes at run time given the state of THEMES and PALETTES\nfunction generateAllThemes($injector, $mdTheming) {\n  var head = document.head;\n  var firstChild = head ? head.firstElementChild : null;\n  var themeCss = !themeConfig.disableTheming && $injector.has('$MD_THEME_CSS') ? $injector.get('$MD_THEME_CSS') : '';\n\n  // Append our custom registered styles to the theme stylesheet.\n  themeCss += themeConfig.registeredStyles.join('');\n\n  if (!firstChild) return;\n  if (themeCss.length === 0) return; // no rules, so no point in running this expensive task\n\n  // Expose contrast colors for palettes to ensure that text is always readable\n  angular.forEach(PALETTES, sanitizePalette);\n\n  // MD_THEME_CSS is a string generated by the build process that includes all the themeable\n  // components as templates\n\n  // Break the CSS into individual rules\n  var rules = splitCss(themeCss).map(function(rule) {\n    return rule.trim();\n  });\n\n  THEME_COLOR_TYPES.forEach(function(type) {\n    rulesByType[type] = '';\n  });\n\n  // Sort the rules based on type, allowing us to do color substitution on a per-type basis\n  rules.forEach(function(rule) {\n    // First: test that if the rule has '.md-accent', it goes into the accent set of rules\n    for (var i = 0, type; type = THEME_COLOR_TYPES[i]; i++) {\n      if (rule.indexOf('.md-' + type) > -1) {\n        return rulesByType[type] += rule;\n      }\n    }\n\n    // If no eg 'md-accent' class is found, try to just find 'accent' in the rule and guess from\n    // there\n    for (i = 0; type = THEME_COLOR_TYPES[i]; i++) {\n      if (rule.indexOf(type) > -1) {\n        return rulesByType[type] += rule;\n      }\n    }\n\n    // Default to the primary array\n    return rulesByType[DEFAULT_COLOR_TYPE] += rule;\n  });\n\n  // If themes are being generated on-demand, quit here. The user will later manually\n  // call generateTheme to do this on a theme-by-theme basis.\n  if (themeConfig.generateOnDemand) return;\n\n  angular.forEach($mdTheming.THEMES, function(theme) {\n    if (!GENERATED[theme.name] && !($mdTheming.defaultTheme() !== 'default' && theme.name === 'default')) {\n      generateTheme(theme, theme.name, themeConfig.nonce);\n    }\n  });\n\n\n  // *************************\n  // Internal functions\n  // *************************\n\n  /**\n   * The user specifies a 'default' contrast color as either light or dark, then explicitly lists\n   * which hues are the opposite contrast (eg. A100 has dark, A200 has light).\n   * @param {!object} palette to sanitize\n   */\n  function sanitizePalette(palette) {\n    var defaultContrast = palette.contrastDefaultColor;\n    var lightColors = palette.contrastLightColors || [];\n    var strongLightColors = palette.contrastStrongLightColors || [];\n    var darkColors = palette.contrastDarkColors || [];\n\n    // These colors are provided as space-separated lists\n    if (typeof lightColors === 'string') lightColors = lightColors.split(' ');\n    if (typeof strongLightColors === 'string') strongLightColors = strongLightColors.split(' ');\n    if (typeof darkColors === 'string') darkColors = darkColors.split(' ');\n\n    // Cleanup after ourselves\n    delete palette.contrastDefaultColor;\n    delete palette.contrastLightColors;\n    delete palette.contrastStrongLightColors;\n    delete palette.contrastDarkColors;\n\n    /**\n     * @param {string} hueName\n     * @return {'dark'|'light'|'strongLight'}\n     */\n    function getContrastType(hueName) {\n      if (defaultContrast === 'light' ? darkColors.indexOf(hueName) !== -1  :\n        (lightColors.indexOf(hueName) === -1 && strongLightColors.indexOf(hueName) === -1)) {\n        return 'dark';\n      }\n      if (strongLightColors.indexOf(hueName) !== -1) {\n        return 'strongLight';\n      }\n      return 'light';\n    }\n\n    /**\n     * @param {'dark'|'light'|'strongLight'} contrastType\n     * @return {[number, number, number]} [red, green, blue] array\n     */\n    function getContrastColor(contrastType) {\n      switch (contrastType) {\n        default:\n        case 'strongLight':\n          return STRONG_LIGHT_CONTRAST_COLOR;\n        case 'light':\n          return LIGHT_CONTRAST_COLOR;\n        case 'dark':\n          return DARK_CONTRAST_COLOR;\n      }\n    }\n\n    /**\n     * @param {'dark'|'light'|'strongLight'} contrastType\n     * @return {{secondary: number, divider: number, hint: number, icon: number, disabled: number}}\n     */\n    function getOpacityValues(contrastType) {\n      switch (contrastType) {\n        default:\n        case 'strongLight':\n          return STRONG_LIGHT_CONTRAST_OPACITY;\n        case 'light':\n          return LIGHT_CONTRAST_OPACITY;\n        case 'dark':\n          return DARK_CONTRAST_OPACITY;\n      }\n    }\n    // Change { 'A100': '#fffeee' } to { 'A100': { value: '#fffeee', contrast:DARK_CONTRAST_COLOR }\n    angular.forEach(palette, function(hueValue, hueName) {\n      if (angular.isObject(hueValue)) return; // Already converted\n      // Map everything to rgb colors\n      var rgbValue = colorToRgbaArray(hueValue);\n      if (!rgbValue) {\n        throw new Error(\"Color %1, in palette %2's hue %3, is invalid. Hex or rgb(a) color expected.\"\n                        .replace('%1', hueValue)\n                        .replace('%2', palette.name)\n                        .replace('%3', hueName));\n      }\n\n      var contrastType = getContrastType(hueName);\n      palette[hueName] = {\n        hex: palette[hueName],\n        value: rgbValue,\n        contrastType: contrastType,\n        contrast: getContrastColor(contrastType),\n        opacity: getOpacityValues(contrastType)\n      };\n    });\n  }\n\n  /**\n   * @param {string} themeCss\n   * @returns {[]} a string representing a CSS file that is split, producing an array with a rule\n   *  at each index.\n   */\n  function splitCss(themeCss) {\n    var result = [];\n    var currentRule = '';\n    var openedCurlyBrackets = 0;\n    var closedCurlyBrackets = 0;\n\n    for (var i = 0; i < themeCss.length; i++) {\n      var character = themeCss.charAt(i);\n\n      // Check for content in quotes\n      if (character === '\\'' || character === '\"') {\n        // Append text in quotes to current rule\n        var textInQuotes = themeCss.substring(i, themeCss.indexOf(character, i + 1));\n        currentRule += textInQuotes;\n\n        // Jump to the closing quote char\n        i += textInQuotes.length;\n      } else {\n        currentRule += character;\n\n        if (character === '}') {\n          closedCurlyBrackets++;\n          if (closedCurlyBrackets === openedCurlyBrackets) {\n            closedCurlyBrackets = 0;\n            openedCurlyBrackets = 0;\n            result.push(currentRule);\n            currentRule = '';\n          }\n        } else if (character === '{') {\n          openedCurlyBrackets++;\n        }\n      }\n    }\n    // Add comments added after last valid rule.\n    if (currentRule !== '') {\n      result.push(currentRule);\n    }\n\n    return result;\n  }\n}\n\nfunction generateTheme(theme, name, nonce) {\n  var head = document.head;\n  var firstChild = head ? head.firstElementChild : null;\n\n  if (!GENERATED[name]) {\n    // For each theme, use the color palettes specified for\n    // `primary`, `warn` and `accent` to generate CSS rules.\n    THEME_COLOR_TYPES.forEach(function(colorType) {\n      var styleStrings = parseRules(theme, colorType, rulesByType[colorType]);\n      while (styleStrings.length) {\n        var styleContent = styleStrings.shift();\n        if (styleContent) {\n          var style = document.createElement('style');\n          style.setAttribute('md-theme-style', '');\n          if (nonce) {\n            style.setAttribute('nonce', nonce);\n          }\n          style.appendChild(document.createTextNode(styleContent));\n          head.insertBefore(style, firstChild);\n        }\n      }\n    });\n\n    GENERATED[theme.name] = true;\n  }\n\n}\n\n\nfunction checkValidPalette(theme, colorType) {\n  // If theme attempts to use a palette that doesnt exist, throw error\n  if (!PALETTES[ (theme.colors[colorType] || {}).name ]) {\n    throw new Error(\n      \"You supplied an invalid color palette for theme %1's %2 palette. Available palettes: %3\"\n                    .replace('%1', theme.name)\n                    .replace('%2', colorType)\n                    .replace('%3', Object.keys(PALETTES).join(', '))\n    );\n  }\n}\n\n/**\n * @param {string} clr rbg or rgba color\n * @return {number[]|undefined} [red, green, blue] array if it can be computed\n */\nfunction colorToRgbaArray(clr) {\n  if (angular.isArray(clr) && clr.length === 3) return clr;\n  if (/^rgb/.test(clr)) {\n    return clr.replace(/(^\\s*rgba?\\(|\\)\\s*$)/g, '').split(',').map(function(value, i) {\n      return i === 3 ? parseFloat(value) : parseInt(value, 10);\n    });\n  }\n  if (clr.charAt(0) === '#') clr = clr.substring(1);\n  if (!/^([a-fA-F0-9]{3}){1,2}$/g.test(clr)) return;\n\n  var dig = clr.length / 3;\n  var red = clr.substr(0, dig);\n  var grn = clr.substr(dig, dig);\n  var blu = clr.substr(dig * 2);\n  if (dig === 1) {\n    red += red;\n    grn += grn;\n    blu += blu;\n  }\n  return [parseInt(red, 16), parseInt(grn, 16), parseInt(blu, 16)];\n}\n\nfunction rgba(rgbArray, opacity) {\n  if (!rgbArray) return \"rgb('0,0,0')\";\n\n  if (rgbArray.length === 4) {\n    rgbArray = angular.copy(rgbArray);\n    opacity ? rgbArray.pop() : opacity = rgbArray.pop();\n  }\n  return opacity && (typeof opacity == 'number' || (typeof opacity == 'string' && opacity.length)) ?\n    'rgba(' + rgbArray.join(',') + ',' + opacity + ')' :\n    'rgb(' + rgbArray.join(',') + ')';\n}\n\n\n})(window.angular);\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.autocomplete\n */\n/*\n * @see js folder for autocomplete implementation\n */\nangular.module('material.components.autocomplete', [\n  'material.core',\n  'material.components.icon',\n  'material.components.virtualRepeat'\n]);\n\n})();\n(function(){\n\"use strict\";\n\n\nMdAutocompleteCtrl.$inject = [\"$scope\", \"$element\", \"$mdUtil\", \"$mdConstant\", \"$mdTheming\", \"$window\", \"$animate\", \"$rootElement\", \"$attrs\", \"$q\", \"$log\", \"$mdLiveAnnouncer\"];angular\n    .module('material.components.autocomplete')\n    .controller('MdAutocompleteCtrl', MdAutocompleteCtrl);\n\nvar ITEM_HEIGHT   = 48,\n    MAX_ITEMS     = 5,\n    MENU_PADDING  = 8,\n    INPUT_PADDING = 2, // Padding provided by `md-input-container`\n    MODE_STANDARD = 'standard',\n    MODE_VIRTUAL = 'virtual';\n\nfunction MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming, $window,\n                             $animate, $rootElement, $attrs, $q, $log, $mdLiveAnnouncer) {\n\n  // Internal Variables.\n  var ctrl                 = this,\n      itemParts            = $scope.itemsExpr.split(/ in /i),\n      itemExpr             = itemParts[ 1 ],\n      elements             = null,\n      cache                = {},\n      noBlur               = false,\n      selectedItemWatchers = [],\n      hasFocus             = false,\n      fetchesInProgress    = 0,\n      enableWrapScroll     = null,\n      inputModelCtrl       = null,\n      debouncedOnResize    = $mdUtil.debounce(onWindowResize),\n      mode                 = MODE_VIRTUAL; // default\n\n  /**\n   * The root document element. This is used for attaching a top-level click handler to\n   * close the options panel when a click outside said panel occurs. We use `documentElement`\n   * instead of body because, when scrolling is disabled, some browsers consider the body element\n   * to be completely off the screen and propagate events directly to the html element.\n   * @type {!Object} angular.JQLite\n   */\n  ctrl.documentElement = angular.element(document.documentElement);\n\n  // Public Exported Variables with handlers\n  defineProperty('hidden', handleHiddenChange, true);\n\n  // Public Exported Variables\n  ctrl.scope = $scope;\n  ctrl.parent = $scope.$parent;\n  ctrl.itemName = itemParts[0];\n  ctrl.matches = [];\n  ctrl.loading = false;\n  ctrl.hidden = true;\n  ctrl.index = -1;\n  ctrl.activeOption = null;\n  ctrl.id = $mdUtil.nextUid();\n  ctrl.isDisabled = null;\n  ctrl.isRequired = null;\n  ctrl.isReadonly = null;\n  ctrl.hasNotFound = false;\n  ctrl.selectedMessage = $scope.selectedMessage || 'selected';\n  ctrl.noMatchMessage = $scope.noMatchMessage || 'There are no matches available.';\n  ctrl.singleMatchMessage = $scope.singleMatchMessage || 'There is 1 match available.';\n  ctrl.multipleMatchStartMessage = $scope.multipleMatchStartMessage || 'There are ';\n  ctrl.multipleMatchEndMessage = $scope.multipleMatchEndMessage || ' matches available.';\n  ctrl.defaultEscapeOptions = 'clear';\n\n  // Public Exported Methods\n  ctrl.keydown = keydown;\n  ctrl.blur = blur;\n  ctrl.focus = focus;\n  ctrl.clear = clearValue;\n  ctrl.select = select;\n  ctrl.listEnter = onListEnter;\n  ctrl.listLeave = onListLeave;\n  ctrl.focusInput = focusInputElement;\n  ctrl.getCurrentDisplayValue = getCurrentDisplayValue;\n  ctrl.registerSelectedItemWatcher = registerSelectedItemWatcher;\n  ctrl.unregisterSelectedItemWatcher = unregisterSelectedItemWatcher;\n  ctrl.notFoundVisible = notFoundVisible;\n  ctrl.loadingIsVisible = loadingIsVisible;\n  ctrl.positionDropdown = positionDropdown;\n\n  /**\n   * Report types to be used for the $mdLiveAnnouncer\n   * @enum {number} Unique flag id.\n   */\n  var ReportType = {\n    Count: 1,\n    Selected: 2\n  };\n\n  return init();\n\n  // initialization methods\n\n  /**\n   * Initialize the controller, setup watchers, gather elements\n   */\n  function init () {\n\n    $mdUtil.initOptionalProperties($scope, $attrs, {\n      searchText: '',\n      selectedItem: null,\n      clearButton: false,\n      disableVirtualRepeat: false,\n    });\n\n    $mdTheming($element);\n    configureWatchers();\n    $mdUtil.nextTick(function () {\n\n      gatherElements();\n      moveDropdown();\n\n      // Touch devices often do not send a click event on tap. We still want to focus the input\n      // and open the options pop-up in these cases.\n      $element.on('touchstart', focusInputElement);\n\n      // Forward all focus events to the input element when autofocus is enabled\n      if ($scope.autofocus) {\n        $element.on('focus', focusInputElement);\n      }\n      if ($scope.inputAriaDescribedBy) {\n        elements.input.setAttribute('aria-describedby', $scope.inputAriaDescribedBy);\n      }\n      if (!$scope.floatingLabel) {\n        if ($scope.inputAriaLabel) {\n          elements.input.setAttribute('aria-label', $scope.inputAriaLabel);\n        } else if ($scope.inputAriaLabelledBy) {\n          elements.input.setAttribute('aria-labelledby', $scope.inputAriaLabelledBy);\n        } else if ($scope.placeholder) {\n          // If no aria-label or aria-labelledby references are defined, then just label using the\n          // placeholder.\n          elements.input.setAttribute('aria-label', $scope.placeholder);\n        }\n      }\n    });\n  }\n\n  function updateModelValidators() {\n    if (!$scope.requireMatch || !inputModelCtrl) return;\n\n    inputModelCtrl.$setValidity('md-require-match', !!$scope.selectedItem || !$scope.searchText);\n  }\n\n  /**\n   * Calculates the dropdown's position and applies the new styles to the menu element\n   * @returns {*}\n   */\n  function positionDropdown () {\n    if (!elements) {\n      return $mdUtil.nextTick(positionDropdown, false, $scope);\n    }\n\n    var dropdownHeight = ($scope.dropdownItems || MAX_ITEMS) * ITEM_HEIGHT;\n    var hrect  = elements.wrap.getBoundingClientRect(),\n        vrect  = elements.snap.getBoundingClientRect(),\n        root   = elements.root.getBoundingClientRect(),\n        top    = vrect.bottom - root.top,\n        bot    = root.bottom - vrect.top,\n        left   = hrect.left - root.left,\n        width  = hrect.width,\n        offset = getVerticalOffset(),\n        position = $scope.dropdownPosition,\n        styles, enoughBottomSpace, enoughTopSpace;\n    var bottomSpace = root.bottom - vrect.bottom - MENU_PADDING + $mdUtil.getViewportTop();\n    var topSpace = vrect.top - MENU_PADDING;\n\n    // Automatically determine dropdown placement based on available space in viewport.\n    if (!position) {\n      enoughTopSpace = topSpace > dropdownHeight;\n      enoughBottomSpace = bottomSpace > dropdownHeight;\n      if (enoughBottomSpace) {\n        position = 'bottom';\n      } else if (enoughTopSpace) {\n        position = 'top';\n      } else {\n        position = topSpace > bottomSpace ? 'top' : 'bottom';\n      }\n    }\n    // Adjust the width to account for the padding provided by `md-input-container`\n    if ($attrs.mdFloatingLabel) {\n      left += INPUT_PADDING;\n      width -= INPUT_PADDING * 2;\n    }\n    styles = {\n      left:     left + 'px',\n      minWidth: width + 'px',\n      maxWidth: Math.max(hrect.right - root.left, root.right - hrect.left) - MENU_PADDING + 'px'\n    };\n\n    if (position === 'top') {\n      styles.top       = 'auto';\n      styles.bottom    = bot + 'px';\n      styles.maxHeight = Math.min(dropdownHeight, topSpace) + 'px';\n    } else {\n      bottomSpace = root.bottom - hrect.bottom - MENU_PADDING + $mdUtil.getViewportTop();\n\n      styles.top       = (top - offset) + 'px';\n      styles.bottom    = 'auto';\n      styles.maxHeight = Math.min(dropdownHeight, bottomSpace) + 'px';\n    }\n\n    elements.$.scrollContainer.css(styles);\n    $mdUtil.nextTick(correctHorizontalAlignment, false, $scope);\n\n    /**\n     * Calculates the vertical offset for floating label examples to account for ngMessages\n     * @returns {number}\n     */\n    function getVerticalOffset () {\n      var offset = 0;\n      var inputContainer = $element.find('md-input-container');\n      if (inputContainer.length) {\n        var input = inputContainer.find('input');\n        offset = inputContainer.prop('offsetHeight');\n        offset -= input.prop('offsetTop');\n        offset -= input.prop('offsetHeight');\n        // add in the height left up top for the floating label text\n        offset += inputContainer.prop('offsetTop');\n      }\n      return offset;\n    }\n\n    /**\n     * Makes sure that the menu doesn't go off of the screen on either side.\n     */\n    function correctHorizontalAlignment () {\n      var dropdown = elements.scrollContainer.getBoundingClientRect(),\n          styles   = {};\n      if (dropdown.right > root.right) {\n        styles.left = (hrect.right - dropdown.width) + 'px';\n      }\n      elements.$.scrollContainer.css(styles);\n    }\n  }\n\n  /**\n   * Moves the dropdown menu to the body tag in order to avoid z-index and overflow issues.\n   */\n  function moveDropdown () {\n    if (!elements.$.root.length) return;\n    $mdTheming(elements.$.scrollContainer);\n    elements.$.scrollContainer.detach();\n    elements.$.root.append(elements.$.scrollContainer);\n    if ($animate.pin) $animate.pin(elements.$.scrollContainer, $rootElement);\n  }\n\n  /**\n   * Sends focus to the input element.\n   */\n  function focusInputElement () {\n    elements.input.focus();\n  }\n\n  /**\n   * Update the activeOption based on the selected item in the listbox.\n   * The activeOption is used in the template to set the aria-activedescendant attribute, which\n   * enables screen readers to properly handle visual focus within the listbox and announce the\n   * item's place in the list. I.e. \"List item 3 of 50\". Anytime that `ctrl.index` changes, this\n   * function needs to be called to update the activeOption.\n   */\n  function updateActiveOption() {\n    var selectedOption = elements.scroller.querySelector('.selected');\n    if (selectedOption) {\n      ctrl.activeOption = selectedOption.id;\n    } else {\n      ctrl.activeOption = null;\n    }\n  }\n\n  /**\n   * Sets up any watchers used by autocomplete\n   */\n  function configureWatchers () {\n    var wait = parseInt($scope.delay, 10) || 0;\n\n    $attrs.$observe('disabled', function (value) { ctrl.isDisabled = $mdUtil.parseAttributeBoolean(value, false); });\n    $attrs.$observe('required', function (value) { ctrl.isRequired = $mdUtil.parseAttributeBoolean(value, false); });\n    $attrs.$observe('readonly', function (value) { ctrl.isReadonly = $mdUtil.parseAttributeBoolean(value, false); });\n\n    $scope.$watch('searchText', wait ? $mdUtil.debounce(handleSearchText, wait) : handleSearchText);\n    $scope.$watch('selectedItem', selectedItemChange);\n\n    angular.element($window).on('resize', debouncedOnResize);\n\n    $scope.$on('$destroy', cleanup);\n  }\n\n  /**\n   * Removes any events or leftover elements created by this controller\n   */\n  function cleanup () {\n    if (!ctrl.hidden) {\n      $mdUtil.enableScrolling();\n    }\n\n    angular.element($window).off('resize', debouncedOnResize);\n\n    if (elements){\n      var items = ['ul', 'scroller', 'scrollContainer', 'input'];\n      angular.forEach(items, function(key){\n        elements.$[key].remove();\n      });\n    }\n  }\n\n  /**\n   * Event handler to be called whenever the window resizes.\n   */\n  function onWindowResize() {\n    if (!ctrl.hidden) {\n      positionDropdown();\n    }\n  }\n\n  /**\n   * Gathers all of the elements needed for this controller\n   */\n  function gatherElements () {\n\n    var snapWrap = gatherSnapWrap();\n\n    elements = {\n      main:  $element[0],\n      scrollContainer: $element[0].querySelector('.md-virtual-repeat-container, .md-standard-list-container'),\n      scroller: $element[0].querySelector('.md-virtual-repeat-scroller, .md-standard-list-scroller'),\n      ul:    $element.find('ul')[0],\n      input: $element.find('input')[0],\n      wrap:  snapWrap.wrap,\n      snap:  snapWrap.snap,\n      root:  document.body,\n    };\n\n    elements.li   = elements.ul.getElementsByTagName('li');\n    elements.$    = getAngularElements(elements);\n    mode = elements.scrollContainer.classList.contains('md-standard-list-container') ? MODE_STANDARD : MODE_VIRTUAL;\n    inputModelCtrl = elements.$.input.controller('ngModel');\n  }\n\n  /**\n   * Gathers the snap and wrap elements\n   *\n   */\n  function gatherSnapWrap() {\n    var element;\n    var value;\n    for (element = $element; element.length; element = element.parent()) {\n      value = element.attr('md-autocomplete-snap');\n      if (angular.isDefined(value)) break;\n    }\n\n    if (element.length) {\n      return {\n        snap: element[0],\n        wrap: (value.toLowerCase() === 'width') ? element[0] : $element.find('md-autocomplete-wrap')[0]\n      };\n    }\n\n    var wrap = $element.find('md-autocomplete-wrap')[0];\n    return {\n      snap: wrap,\n      wrap: wrap\n    };\n  }\n\n  /**\n   * Gathers angular-wrapped versions of each element\n   * @param elements\n   * @returns {{}}\n   */\n  function getAngularElements (elements) {\n    var obj = {};\n    for (var key in elements) {\n      if (elements.hasOwnProperty(key)) obj[ key ] = angular.element(elements[ key ]);\n    }\n    return obj;\n  }\n\n  // event/change handlers\n\n  /**\n   * @param {Event} $event\n   */\n  function preventDefault($event) {\n    $event.preventDefault();\n  }\n\n  /**\n   * @param {Event} $event\n   */\n  function stopPropagation($event) {\n    $event.stopPropagation();\n  }\n\n  /**\n   * Handles changes to the `hidden` property.\n   * @param {boolean} hidden true to hide the options pop-up, false to show it.\n   * @param {boolean} oldHidden the previous value of hidden\n   */\n  function handleHiddenChange (hidden, oldHidden) {\n    var scrollContainerElement;\n\n    if (elements) {\n      scrollContainerElement = angular.element(elements.scrollContainer);\n    }\n    if (!hidden && oldHidden) {\n      positionDropdown();\n\n      // Report in polite mode, because the screen reader should finish the default description of\n      // the input element.\n      reportMessages(true, ReportType.Count | ReportType.Selected);\n\n      if (elements) {\n        $mdUtil.disableScrollAround(elements.scrollContainer);\n        enableWrapScroll = disableElementScrollEvents(elements.wrap);\n        if ($mdUtil.isIos) {\n          ctrl.documentElement.on('touchend', handleTouchOutsidePanel);\n          if (scrollContainerElement) {\n            scrollContainerElement.on('touchstart touchmove touchend', stopPropagation);\n          }\n        }\n        ctrl.index = getDefaultIndex();\n        $mdUtil.nextTick(function() {\n          updateActiveOption();\n          updateScroll();\n        });\n      }\n    } else if (hidden && !oldHidden) {\n      if ($mdUtil.isIos) {\n        ctrl.documentElement.off('touchend', handleTouchOutsidePanel);\n        if (scrollContainerElement) {\n          scrollContainerElement.off('touchstart touchmove touchend', stopPropagation);\n        }\n      }\n      $mdUtil.enableScrolling();\n\n      if (enableWrapScroll) {\n        enableWrapScroll();\n        enableWrapScroll = null;\n      }\n    }\n  }\n\n  /**\n   * Handling touch events that bubble up to the document is required for closing the dropdown\n   * panel on touch outside of the options pop-up panel on iOS.\n   * @param {Event} $event\n   */\n  function handleTouchOutsidePanel($event) {\n    ctrl.hidden = true;\n    // iOS does not blur the pop-up for touches on the scroll mask, so we have to do it.\n    doBlur(true);\n  }\n\n  /**\n   * Disables scrolling for a specific element.\n   * @param {!string|!DOMElement} element to disable scrolling\n   * @return {Function} function to call to re-enable scrolling for the element\n   */\n  function disableElementScrollEvents(element) {\n    var elementToDisable = angular.element(element);\n    elementToDisable.on('wheel touchmove', preventDefault);\n\n    return function() {\n      elementToDisable.off('wheel touchmove', preventDefault);\n    };\n  }\n\n  /**\n   * When the user mouses over the dropdown menu, ignore blur events.\n   */\n  function onListEnter () {\n    noBlur = true;\n  }\n\n  /**\n   * When the user's mouse leaves the menu, blur events may hide the menu again.\n   */\n  function onListLeave () {\n    if (!hasFocus && !ctrl.hidden) elements.input.focus();\n    noBlur = false;\n    ctrl.hidden = shouldHide();\n  }\n\n  /**\n   * Handles changes to the selected item.\n   * @param selectedItem\n   * @param previousSelectedItem\n   */\n  function selectedItemChange (selectedItem, previousSelectedItem) {\n\n    updateModelValidators();\n\n    if (selectedItem) {\n      getDisplayValue(selectedItem).then(function (val) {\n        $scope.searchText = val;\n        handleSelectedItemChange(selectedItem, previousSelectedItem);\n      });\n    } else if (previousSelectedItem && $scope.searchText) {\n      getDisplayValue(previousSelectedItem).then(function(displayValue) {\n        // Clear the searchText, when the selectedItem is set to null.\n        // Do not clear the searchText, when the searchText isn't matching with the previous\n        // selected item.\n        if (angular.isString($scope.searchText)\n          && displayValue.toString().toLowerCase() === $scope.searchText.toLowerCase()) {\n          $scope.searchText = '';\n        }\n      });\n    }\n\n    if (selectedItem !== previousSelectedItem) {\n      announceItemChange();\n    }\n  }\n\n  /**\n   * Use the user-defined expression to announce changes each time a new item is selected\n   */\n  function announceItemChange () {\n    angular.isFunction($scope.itemChange) &&\n      $scope.itemChange(getItemAsNameVal($scope.selectedItem));\n  }\n\n  /**\n   * Use the user-defined expression to announce changes each time the search text is changed\n   */\n  function announceTextChange () {\n    angular.isFunction($scope.textChange) && $scope.textChange();\n  }\n\n  /**\n   * Calls any external watchers listening for the selected item.  Used in conjunction with\n   * `registerSelectedItemWatcher`.\n   * @param selectedItem\n   * @param previousSelectedItem\n   */\n  function handleSelectedItemChange (selectedItem, previousSelectedItem) {\n    selectedItemWatchers.forEach(function (watcher) {\n      watcher(selectedItem, previousSelectedItem);\n    });\n  }\n\n  /**\n   * Register a function to be called when the selected item changes.\n   * @param cb\n   */\n  function registerSelectedItemWatcher (cb) {\n    if (selectedItemWatchers.indexOf(cb) === -1) {\n      selectedItemWatchers.push(cb);\n    }\n  }\n\n  /**\n   * Unregister a function previously registered for selected item changes.\n   * @param cb\n   */\n  function unregisterSelectedItemWatcher (cb) {\n    var i = selectedItemWatchers.indexOf(cb);\n    if (i !== -1) {\n      selectedItemWatchers.splice(i, 1);\n    }\n  }\n\n  /**\n   * Handles changes to the searchText property.\n   * @param {string} searchText\n   * @param {string} previousSearchText\n   */\n  function handleSearchText (searchText, previousSearchText) {\n    ctrl.index = getDefaultIndex();\n\n    // do nothing on init\n    if (searchText === previousSearchText) return;\n\n    updateModelValidators();\n\n    getDisplayValue($scope.selectedItem).then(function (val) {\n      // clear selected item if search text no longer matches it\n      if (searchText !== val) {\n        $scope.selectedItem = null;\n\n        // trigger change event if available\n        if (searchText !== previousSearchText) {\n          announceTextChange();\n        }\n\n        // cancel results if search text is not long enough\n        if (!isMinLengthMet()) {\n          ctrl.matches = [];\n\n          setLoading(false);\n          reportMessages(true, ReportType.Count);\n\n        } else {\n          handleQuery();\n        }\n      }\n    });\n\n  }\n\n  /**\n   * Handles input blur event, determines if the dropdown should hide.\n   * @param {Event=} $event\n   */\n  function blur($event) {\n    hasFocus = false;\n\n    if (!noBlur) {\n      ctrl.hidden = shouldHide();\n      evalAttr('ngBlur', { $event: $event });\n    } else if (angular.isObject($event)) {\n      $event.stopImmediatePropagation();\n    }\n  }\n\n  /**\n   * Force blur on input element\n   * @param {boolean} forceBlur\n   */\n  function doBlur(forceBlur) {\n    if (forceBlur) {\n      noBlur = false;\n      hasFocus = false;\n    }\n    elements.input.blur();\n  }\n\n  /**\n   * Handles input focus event, determines if the dropdown should show.\n   */\n  function focus($event) {\n    hasFocus = true;\n\n    if (isSearchable() && isMinLengthMet()) {\n      handleQuery();\n    }\n\n    ctrl.hidden = shouldHide();\n\n    evalAttr('ngFocus', { $event: $event });\n  }\n\n  /**\n   * Handles keyboard input.\n   * @param event\n   */\n  function keydown (event) {\n    switch (event.keyCode) {\n      case $mdConstant.KEY_CODE.DOWN_ARROW:\n        if (ctrl.loading || hasSelection()) return;\n        event.stopPropagation();\n        event.preventDefault();\n        ctrl.index = ctrl.index + 1 > ctrl.matches.length - 1 ? 0 : Math.min(ctrl.index + 1, ctrl.matches.length - 1);\n        $mdUtil.nextTick(updateActiveOption);\n        updateScroll();\n        break;\n      case $mdConstant.KEY_CODE.UP_ARROW:\n        if (ctrl.loading || hasSelection()) return;\n        event.stopPropagation();\n        event.preventDefault();\n        ctrl.index = ctrl.index - 1 < 0 ? ctrl.matches.length - 1 : Math.max(0, ctrl.index - 1);\n        $mdUtil.nextTick(updateActiveOption);\n        updateScroll();\n        break;\n      case $mdConstant.KEY_CODE.TAB:\n        // If we hit tab, assume that we've left the list so it will close\n        onListLeave();\n\n        if (ctrl.hidden || ctrl.loading || ctrl.index < 0 || ctrl.matches.length < 1) return;\n        select(ctrl.index);\n        break;\n      case $mdConstant.KEY_CODE.ENTER:\n        if (ctrl.hidden || ctrl.loading || ctrl.index < 0 || ctrl.matches.length < 1) return;\n        if (hasSelection()) return;\n        event.stopImmediatePropagation();\n        event.preventDefault();\n        select(ctrl.index);\n        break;\n      case $mdConstant.KEY_CODE.ESCAPE:\n        event.preventDefault(); // Prevent browser from always clearing input\n        if (!shouldProcessEscape()) return;\n        event.stopPropagation();\n\n        clearSelectedItem();\n        if ($scope.searchText && hasEscapeOption('clear')) {\n          clearSearchText();\n        }\n\n        // Manually hide (needed for mdNotFound support)\n        ctrl.hidden = true;\n\n        if (hasEscapeOption('blur')) {\n          // Force the component to blur if they hit escape\n          doBlur(true);\n        }\n\n        break;\n      default:\n    }\n  }\n\n  // getters\n\n  /**\n   * Returns the minimum length needed to display the dropdown.\n   * @returns {*}\n   */\n  function getMinLength () {\n    return angular.isNumber($scope.minLength) ? $scope.minLength : 1;\n  }\n\n  /**\n   * Returns the display value for an item.\n   * @param {*} item\n   * @returns {*}\n   */\n  function getDisplayValue (item) {\n    return $q.when(getItemText(item) || item).then(function(itemText) {\n      if (itemText && !angular.isString(itemText)) {\n        $log.warn('md-autocomplete: Could not resolve display value to a string. ' +\n          'Please check the `md-item-text` attribute.');\n      }\n\n      return itemText;\n    });\n\n    /**\n     * Getter function to invoke user-defined expression (in the directive)\n     * to convert your object to a single string.\n     * @param {*} item\n     * @returns {string|null}\n     */\n    function getItemText (item) {\n      return (item && $scope.itemText) ? $scope.itemText(getItemAsNameVal(item)) : null;\n    }\n  }\n\n  /**\n   * Returns the locals object for compiling item templates.\n   * @param {*} item\n   * @returns {Object|undefined}\n   */\n  function getItemAsNameVal (item) {\n    if (!item) {\n      return undefined;\n    }\n\n    var locals = {};\n    if (ctrl.itemName) {\n      locals[ ctrl.itemName ] = item;\n    }\n\n    return locals;\n  }\n\n  /**\n   * Returns the default index based on whether or not autoselect is enabled.\n   * @returns {number} 0 if autoselect is enabled, -1 if not.\n   */\n  function getDefaultIndex () {\n    return $scope.autoselect ? 0 : -1;\n  }\n\n  /**\n   * Sets the loading parameter and updates the hidden state.\n   * @param value {boolean} Whether or not the component is currently loading.\n   */\n  function setLoading(value) {\n    if (ctrl.loading !== value) {\n      ctrl.loading = value;\n    }\n\n    // Always refresh the hidden variable as something else might have changed\n    ctrl.hidden = shouldHide();\n  }\n\n  /**\n   * Determines if the menu should be hidden.\n   * @returns {boolean} true if the menu should be hidden\n   */\n  function shouldHide () {\n    return !shouldShow();\n  }\n\n  /**\n   * Determines whether the autocomplete is able to query within the current state.\n   * @returns {boolean} true if the query can be run\n   */\n  function isSearchable() {\n    if (ctrl.loading && !hasMatches()) {\n      // No query when query is in progress.\n      return false;\n    } else if (hasSelection()) {\n      // No query if there is already a selection\n      return false;\n    }\n    else if (!hasFocus) {\n      // No query if the input does not have focus\n      return false;\n    }\n    return true;\n  }\n\n  /**\n   * @returns {boolean} if the escape keydown should be processed, return true.\n   *  Otherwise return false.\n   */\n  function shouldProcessEscape() {\n    return hasEscapeOption('blur') || !ctrl.hidden || ctrl.loading || hasEscapeOption('clear') && $scope.searchText;\n  }\n\n  /**\n   * @param {string} option check if this option is set\n   * @returns {boolean} if the specified escape option is set, return true. Return false otherwise.\n   */\n  function hasEscapeOption(option) {\n    if (!angular.isString($scope.escapeOptions)) {\n      return ctrl.defaultEscapeOptions.indexOf(option) !== -1;\n    } else {\n      return $scope.escapeOptions.toLowerCase().indexOf(option) !== -1;\n    }\n  }\n\n  /**\n   * Determines if the menu should be shown.\n   * @returns {boolean} true if the menu should be shown\n   */\n  function shouldShow() {\n    if (ctrl.isReadonly) {\n      // Don't show if read only is set\n      return false;\n    } else if (!isSearchable()) {\n      // Don't show if a query is in progress, there is already a selection,\n      // or the input is not focused.\n      return false;\n    }\n    return (isMinLengthMet() && hasMatches()) || notFoundVisible();\n  }\n\n  /**\n   * @returns {boolean} true if the search text has matches.\n   */\n  function hasMatches() {\n    return ctrl.matches.length ? true : false;\n  }\n\n  /**\n   * @returns {boolean} true if the autocomplete has a valid selection.\n   */\n  function hasSelection() {\n    return ctrl.scope.selectedItem ? true : false;\n  }\n\n  /**\n   * @returns {boolean} true if the loading indicator is, or should be, visible.\n   */\n  function loadingIsVisible() {\n    return ctrl.loading && !hasSelection();\n  }\n\n  /**\n   * @returns {*} the display value of the current item.\n   */\n  function getCurrentDisplayValue () {\n    return getDisplayValue(ctrl.matches[ ctrl.index ]);\n  }\n\n  /**\n   * Determines if the minimum length is met by the search text.\n   * @returns {*} true if the minimum length is met by the search text\n   */\n  function isMinLengthMet () {\n    return ($scope.searchText || '').length >= getMinLength();\n  }\n\n  // actions\n\n  /**\n   * Defines a public property with a handler and a default value.\n   * @param {string} key\n   * @param {Function} handler function\n   * @param {*} defaultValue default value\n   */\n  function defineProperty (key, handler, defaultValue) {\n    Object.defineProperty(ctrl, key, {\n      get: function () { return defaultValue; },\n      set: function (newValue) {\n        var oldValue = defaultValue;\n        defaultValue        = newValue;\n        handler(newValue, oldValue);\n      }\n    });\n  }\n\n  /**\n   * Selects the item at the given index.\n   * @param {number} index to select\n   */\n  function select (index) {\n    // force form to update state for validation\n    $mdUtil.nextTick(function () {\n      getDisplayValue(ctrl.matches[ index ]).then(function (val) {\n        var ngModel = elements.$.input.controller('ngModel');\n        $mdLiveAnnouncer.announce(val + ' ' + ctrl.selectedMessage, 'assertive');\n        ngModel.$setViewValue(val);\n        ngModel.$render();\n      }).finally(function () {\n        $scope.selectedItem = ctrl.matches[ index ];\n        setLoading(false);\n      });\n    }, false);\n  }\n\n  /**\n   * Clears the searchText value and selected item.\n   * @param {Event} $event\n   */\n  function clearValue ($event) {\n    if ($event) {\n      $event.stopPropagation();\n    }\n    clearSelectedItem();\n    clearSearchText();\n  }\n\n  /**\n   * Clears the selected item\n   */\n  function clearSelectedItem () {\n    // Reset our variables\n    ctrl.index = -1;\n    $mdUtil.nextTick(updateActiveOption);\n    ctrl.matches = [];\n  }\n\n  /**\n   * Clears the searchText value\n   */\n  function clearSearchText () {\n    // Set the loading to true so we don't see flashes of content.\n    // The flashing will only occur when an async request is running.\n    // So the loading process will stop when the results had been retrieved.\n    setLoading(true);\n\n    $scope.searchText = '';\n\n    // Normally, triggering the change / input event is unnecessary, because the browser detects it properly.\n    // But some browsers are not detecting it properly, which means that we have to trigger the event.\n    // Using the `input` is not working properly, because for example IE11 is not supporting the `input` event.\n    // The `change` event is a good alternative and is supported by all supported browsers.\n    var eventObj = document.createEvent('CustomEvent');\n    eventObj.initCustomEvent('change', true, true, { value: '' });\n    elements.input.dispatchEvent(eventObj);\n\n    // For some reason, firing the above event resets the value of $scope.searchText if\n    // $scope.searchText has a space character at the end, so we blank it one more time and then\n    // focus.\n    elements.input.blur();\n    $scope.searchText = '';\n    elements.input.focus();\n  }\n\n  /**\n   * Fetches the results for the provided search text.\n   * @param searchText\n   */\n  function fetchResults (searchText) {\n    var items = $scope.$parent.$eval(itemExpr),\n        term  = searchText.toLowerCase(),\n        isList = angular.isArray(items),\n        isPromise = !!items.then; // Every promise should contain a `then` property\n\n    if (isList) onResultsRetrieved(items);\n    else if (isPromise) handleAsyncResults(items);\n\n    function handleAsyncResults(items) {\n      if (!items) return;\n\n      items = $q.when(items);\n      fetchesInProgress++;\n      setLoading(true);\n\n      $mdUtil.nextTick(function () {\n          items\n            .then(onResultsRetrieved)\n            .finally(function(){\n              if (--fetchesInProgress === 0) {\n                setLoading(false);\n              }\n            });\n      },true, $scope);\n    }\n\n    function onResultsRetrieved(matches) {\n      cache[term] = matches;\n\n      // Just cache the results if the request is now outdated.\n      // The request becomes outdated, when the new searchText has changed during the result fetching.\n      if ((searchText || '') !== ($scope.searchText || '')) {\n        return;\n      }\n\n      handleResults(matches);\n    }\n  }\n\n\n  /**\n   * Reports given message types to supported screen readers.\n   * @param {boolean} isPolite Whether the announcement should be polite.\n   * @param {!number} types Message flags to be reported to the screen reader.\n   */\n  function reportMessages(isPolite, types) {\n    var politeness = isPolite ? 'polite' : 'assertive';\n    var messages = [];\n\n    if (types & ReportType.Selected && ctrl.index !== -1) {\n      messages.push(getCurrentDisplayValue());\n    }\n\n    if (types & ReportType.Count) {\n      messages.push($q.resolve(getCountMessage()));\n    }\n\n    $q.all(messages).then(function(data) {\n      $mdLiveAnnouncer.announce(data.join(' '), politeness);\n    });\n  }\n\n  /**\n   * @returns {string} the ARIA message for how many results match the current query.\n   */\n  function getCountMessage () {\n    switch (ctrl.matches.length) {\n      case 0:\n        return ctrl.noMatchMessage;\n      case 1:\n        return ctrl.singleMatchMessage;\n      default:\n        return ctrl.multipleMatchStartMessage + ctrl.matches.length + ctrl.multipleMatchEndMessage;\n    }\n  }\n\n  /**\n   * Makes sure that the focused element is within view.\n   */\n  function updateScroll () {\n    if (!elements.li[0]) return;\n    if (mode === MODE_STANDARD) {\n      updateStandardScroll();\n    } else {\n      updateVirtualScroll();\n    }\n  }\n\n  function updateVirtualScroll() {\n    // elements in virtual scroll have consistent heights\n    var optionHeight = elements.li[0].offsetHeight,\n        top = optionHeight * Math.max(0, ctrl.index),\n        bottom = top + optionHeight,\n        containerHeight = elements.scroller.clientHeight,\n        scrollTop = elements.scroller.scrollTop;\n\n    if (top < scrollTop) {\n      scrollTo(top);\n    } else if (bottom > scrollTop + containerHeight) {\n      scrollTo(bottom - containerHeight);\n    }\n  }\n\n  function updateStandardScroll() {\n    // elements in standard scroll have variable heights\n    var selected =  elements.li[Math.max(0, ctrl.index)];\n    var containerHeight = elements.scrollContainer.offsetHeight,\n        top = selected && selected.offsetTop || 0,\n        bottom = top + selected.clientHeight,\n        scrollTop = elements.scrollContainer.scrollTop;\n\n    if (top < scrollTop) {\n      scrollTo(top);\n    } else if (bottom > scrollTop + containerHeight) {\n      scrollTo(bottom - containerHeight);\n    }\n  }\n\n  function isPromiseFetching() {\n    return fetchesInProgress !== 0;\n  }\n\n  function scrollTo (offset) {\n    if (mode === MODE_STANDARD) {\n      elements.scrollContainer.scrollTop = offset;\n    } else {\n      elements.$.scrollContainer.controller('mdVirtualRepeatContainer').scrollTo(offset);\n    }\n  }\n\n  function notFoundVisible () {\n    var textLength = (ctrl.scope.searchText || '').length;\n\n    return ctrl.hasNotFound && !hasMatches() && (!ctrl.loading || isPromiseFetching()) && textLength >= getMinLength() && (hasFocus || noBlur) && !hasSelection();\n  }\n\n  /**\n   * Starts the query to gather the results for the current searchText.  Attempts to return cached\n   * results first, then forwards the process to `fetchResults` if necessary.\n   */\n  function handleQuery () {\n    var searchText = $scope.searchText || '';\n    var term = searchText.toLowerCase();\n\n    // If caching is enabled and the current searchText is stored in the cache\n    if (!$scope.noCache && cache[term]) {\n      // The results should be handled as same as a normal un-cached request does.\n      handleResults(cache[term]);\n    } else {\n      fetchResults(searchText);\n    }\n\n    ctrl.hidden = shouldHide();\n  }\n\n  /**\n   * Handles the retrieved results by showing them in the autocompletes dropdown.\n   * @param results Retrieved results\n   */\n  function handleResults(results) {\n    ctrl.matches = results;\n    ctrl.hidden  = shouldHide();\n\n    // If loading is in progress, then we'll end the progress. This is needed for example,\n    // when the `clear` button was clicked, because there we always show the loading process, to prevent flashing.\n    if (ctrl.loading) setLoading(false);\n\n    if ($scope.selectOnMatch) selectItemOnMatch();\n\n    positionDropdown();\n    reportMessages(true, ReportType.Count);\n  }\n\n  /**\n   * If there is only one matching item and the search text matches its display value exactly,\n   * automatically select that item.  Note: This function is only called if the user uses the\n   * `md-select-on-match` flag.\n   */\n  function selectItemOnMatch () {\n    var searchText = $scope.searchText,\n        matches    = ctrl.matches,\n        item       = matches[ 0 ];\n    if (matches.length === 1) getDisplayValue(item).then(function (displayValue) {\n      var isMatching = searchText === displayValue;\n      if ($scope.matchInsensitive && !isMatching) {\n        isMatching = searchText.toLowerCase() === displayValue.toLowerCase();\n      }\n\n      if (isMatching) {\n        select(0);\n      }\n    });\n  }\n\n  /**\n   * Evaluates an attribute expression against the parent scope.\n   * @param {String} attr Name of the attribute to be evaluated.\n   * @param {Object?} locals Properties to be injected into the evaluation context.\n   */\n function evalAttr(attr, locals) {\n    if ($attrs[attr]) {\n      $scope.$parent.$eval($attrs[attr], locals || {});\n    }\n  }\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMdAutocomplete.$inject = [\"$$mdSvgRegistry\"];angular\n    .module('material.components.autocomplete')\n    .directive('mdAutocomplete', MdAutocomplete);\n\n/**\n * @ngdoc directive\n * @name mdAutocomplete\n * @module material.components.autocomplete\n *\n * @description\n * `<md-autocomplete>` is a special input component with a drop-down of all possible matches to a\n *     custom query. This component allows you to provide real-time suggestions as the user types\n *     in the input area.\n *\n * To start, you will need to specify the required parameters and provide a template for your\n *     results. The content inside `md-autocomplete` will be treated as a template.\n *\n * In more complex cases, you may want to include other content such as a message to display when\n *     no matches were found.  You can do this by wrapping your template in `md-item-template` and\n *     adding a tag for `md-not-found`.  An example of this is shown below.\n *\n * To reset the displayed value you must clear both values for `md-search-text` and\n * `md-selected-item`.\n *\n * ### Validation\n *\n * You can use `ng-messages` to include validation the same way that you would normally validate;\n *     however, if you want to replicate a standard input with a floating label, you will have to\n *     do the following:\n *\n * - Make sure that your template is wrapped in `md-item-template`\n * - Add your `ng-messages` code inside of `md-autocomplete`\n * - Add your validation properties to `md-autocomplete` (ie. `required`)\n * - Add a `name` to `md-autocomplete` (to be used on the generated `input`)\n *\n * There is an example below of how this should look.\n *\n * ### Snapping Drop-Down\n *\n * You can cause the autocomplete drop-down to snap to an ancestor element by applying the\n *     `md-autocomplete-snap` attribute to that element. You can also snap to the width of\n *     the `md-autocomplete-snap` element by setting the attribute's value to `width`\n *     (ie. `md-autocomplete-snap=\"width\"`).\n *\n * ### Notes\n *\n * **Autocomplete Dropdown Items Rendering**\n *\n * The `md-autocomplete` uses the the <a ng-href=\"api/directive/mdVirtualRepeat\">\n *   mdVirtualRepeat</a> directive for displaying the results inside of the dropdown.<br/>\n *\n * > When encountering issues regarding the item template please take a look at the\n *   <a ng-href=\"api/directive/mdVirtualRepeatContainer\">VirtualRepeatContainer</a> documentation.\n *\n * **Autocomplete inside of a Virtual Repeat**\n *\n * When using the `md-autocomplete` directive inside of a\n * <a ng-href=\"api/directive/mdVirtualRepeatContainer\">VirtualRepeatContainer</a> the dropdown items\n * might not update properly, because caching of the results is enabled by default.\n *\n * The autocomplete will then show invalid dropdown items, because the Virtual Repeat only updates\n * the scope bindings rather than re-creating the `md-autocomplete`. This means that the previous\n * cached results will be used.\n *\n * > To avoid such problems, ensure that the autocomplete does not cache any results via\n * `md-no-cache=\"true\"`:\n *\n * <hljs lang=\"html\">\n *   <md-autocomplete\n *       md-no-cache=\"true\"\n *       md-selected-item=\"selectedItem\"\n *       md-items=\"item in items\"\n *       md-search-text=\"searchText\"\n *       md-item-text=\"item.display\">\n *     <span>{{ item.display }}</span>\n *   </md-autocomplete>\n * </hljs>\n *\n *\n * @param {expression} md-items An expression in the format of `item in results` to iterate over\n *     matches for your search.<br/><br/>\n *     The `results` expression can be also a function, which returns the results synchronously\n *     or asynchronously (per Promise).\n * @param {expression=} md-selected-item-change An expression to be run each time a new item is\n *     selected.\n * @param {expression=} md-search-text-change An expression to be run each time the search text\n *     updates.\n * @param {expression=} md-search-text A model to bind the search query text to.\n * @param {object=} md-selected-item A model to bind the selected item to.\n * @param {expression=} md-item-text An expression that will convert your object to a single string.\n * @param {string=} placeholder Placeholder text that will be forwarded to the input.\n * @param {boolean=} md-no-cache Disables the internal caching that happens in autocomplete.\n * @param {boolean=} ng-disabled Determines whether or not to disable the input field.\n * @param {boolean=} md-require-match When set to true, the autocomplete will add a validator,\n *     which will evaluate to false, when no item is currently selected.\n * @param {number=} md-min-length Specifies the minimum length of text before autocomplete will\n *     make suggestions.\n * @param {number=} md-delay Specifies the amount of time (in milliseconds) to wait before looking\n *     for results.\n * @param {boolean=} md-clear-button Whether the clear button for the autocomplete input should show\n *     up or not. When `md-floating-label` is set, defaults to false, defaults to true otherwise.\n * @param {boolean=} md-autofocus If true, the autocomplete will be automatically focused when a\n *     `$mdDialog`, `$mdBottomsheet` or `$mdSidenav`, which contains the autocomplete, is opening.\n *     <br/><br/>\n *     Also the autocomplete will immediately focus the input element.\n * @param {boolean=} md-no-asterisk When present, asterisk will not be appended to the floating\n *     label.\n * @param {boolean=} md-autoselect If set to true, the first item will be automatically selected\n *     in the dropdown upon open.\n * @param {string=} md-input-name The name attribute given to the input element to be used with\n *     FormController.\n * @param {string=} md-menu-class This class will be applied to the dropdown menu for styling.\n * @param {string=} md-menu-container-class This class will be applied to the parent container\n *     of the dropdown panel.\n * @param {string=} md-input-class This will be applied to the input for styling. This attribute\n *     is only valid when a `md-floating-label` is defined.\n * @param {string=} md-floating-label This will add a floating label to autocomplete and wrap it in\n *     `md-input-container`.\n * @param {string=} md-select-on-focus When present the input's text will be automatically selected\n *     on focus.\n * @param {string=} md-input-id An ID to be added to the input element.\n * @param {number=} md-input-minlength The minimum length for the input's value for validation.\n * @param {number=} md-input-maxlength The maximum length for the input's value for validation.\n * @param {boolean=} md-select-on-match When set, autocomplete will automatically select\n *     the item if the search text is an exact match. <br/><br/>\n *     An exact match is when only one match is displayed.\n * @param {boolean=} md-match-case-insensitive When set and using `md-select-on-match`, autocomplete\n *     will select on case-insensitive match.\n * @param {string=} md-escape-options Override escape key logic. Default is `clear`.<br/>\n *     Options: `blur`, `clear`, `none`.\n * @param {string=} md-dropdown-items Specifies the maximum amount of items to be shown in\n *     the dropdown.<br/><br/>\n *     When the dropdown doesn't fit into the viewport, the dropdown will shrink\n *     as much as possible.\n * @param {string=} md-dropdown-position Overrides the default dropdown position. Options: `top`,\n *    `bottom`.\n * @param {string=} input-aria-describedby A space-separated list of element IDs. This should\n *     contain the IDs of any elements that describe this autocomplete. Screen readers will read the\n *     content of these elements at the end of announcing that the autocomplete has been selected\n *     and describing its current state. The descriptive elements do not need to be visible on the\n *     page.\n * @param {string=} input-aria-labelledby A space-separated list of element IDs. The ideal use case\n *     is that this would contain the ID of a `<label>` element that is associated with this\n *     autocomplete. This will only have affect when `md-floating-label` is not defined.<br><br>\n *     For `<label id=\"state\">US State</label>`, you would set this to\n *     `input-aria-labelledby=\"state\"`.\n * @param {string=} input-aria-label A label that will be applied to the autocomplete's input.\n *    This will be announced by screen readers before the placeholder.\n *    This will only have affect when `md-floating-label` is not defined. If you define both\n *    `input-aria-label` and `input-aria-labelledby`, then `input-aria-label` will take precedence.\n * @param {string=} md-selected-message Attribute to specify the text that the screen reader will\n *    announce after a value is selected. Default is: \"selected\". If `Alaska` is selected in the\n *    options panel, it will read \"Alaska selected\". You will want to override this when your app\n *    runs in a non-English locale.\n * @param {string=} md-no-match-message Attribute to specify the text that the screen reader will\n *    announce after a query returns no matching results.\n *    Default is: \"There are no matches available.\". You will want to override this when your app\n *    runs in a non-English locale.\n * @param {string=} md-single-match-message Attribute to specify the text that the screen reader\n *    will announce after a query returns a single matching result.\n *    Default is: \"There is 1 match available.\". You will want to override this when your app\n *    runs in a non-English locale.\n * @param {string=} md-multiple-match-start-message Attribute to specify the text that the screen\n *    reader will announce after a query returns multiple matching results. The number of matching\n *    results will be read after this text. Default is: \"There are \". You will want to override this\n *    when your app runs in a non-English locale.\n * @param {string=} md-multiple-match-end-message Attribute to specify the text that the screen\n *    reader will announce after a query returns multiple matching results. The number of matching\n *    results will be read before this text. Default is: \" matches available.\". You will want to\n *    override this when your app runs in a non-English locale.\n * @param {boolean=} ng-trim If set to false, the search text will be not trimmed automatically.\n *     Defaults to true.\n * @param {string=} ng-pattern Adds the pattern validator to the ngModel of the search text.\n *     See the [ngPattern Directive](https://docs.angularjs.org/api/ng/directive/ngPattern)\n *     for more details.\n * @param {string=} md-mode Specify the repeat mode for suggestion lists. Acceptable values include\n *     `virtual` (md-virtual-repeat) and `standard` (ng-repeat). See the\n *     `Specifying Repeat Mode` example for mode details. Default is `virtual`.\n *\n * @usage\n * ### Basic Example\n * <hljs lang=\"html\">\n *   <md-autocomplete\n *       md-selected-item=\"selectedItem\"\n *       md-search-text=\"searchText\"\n *       md-items=\"item in getMatches(searchText)\"\n *       md-item-text=\"item.display\">\n *     <span md-highlight-text=\"searchText\">{{item.display}}</span>\n *   </md-autocomplete>\n * </hljs>\n *\n * ### Example with \"not found\" message\n * <hljs lang=\"html\">\n * <md-autocomplete\n *     md-selected-item=\"selectedItem\"\n *     md-search-text=\"searchText\"\n *     md-items=\"item in getMatches(searchText)\"\n *     md-item-text=\"item.display\">\n *   <md-item-template>\n *     <span md-highlight-text=\"searchText\">{{item.display}}</span>\n *   </md-item-template>\n *   <md-not-found>\n *     No matches found.\n *   </md-not-found>\n * </md-autocomplete>\n * </hljs>\n *\n * In this example, our code utilizes `md-item-template` and `md-not-found` to specify the\n *     different parts that make up our component.\n *\n * ### Clear button for the input\n * By default, the clear button is displayed when there is input. This aligns with the spec's\n * [Search Pattern](https://material.io/archive/guidelines/patterns/search.html#search-in-app-search).\n * In floating label mode, when `md-floating-label=\"My Label\"` is applied, the clear button is not\n * displayed by default (see the spec's\n * [Autocomplete Text Field](https://material.io/archive/guidelines/components/text-fields.html#text-fields-layout)).\n *\n * Nevertheless, developers are able to explicitly toggle the clear button for all autocomplete\n * components with `md-clear-button`.\n *\n * <hljs lang=\"html\">\n *   <md-autocomplete ... md-clear-button=\"true\"></md-autocomplete>\n *   <md-autocomplete ... md-clear-button=\"false\"></md-autocomplete>\n * </hljs>\n *\n * In previous versions, the clear button was always hidden when the component was disabled.\n * This changed in `1.1.5` to give the developer control of this behavior. This example\n * will hide the clear button only when the component is disabled.\n *\n * <hljs lang=\"html\">\n *   <md-autocomplete ... ng-disabled=\"disabled\" md-clear-button=\"!disabled\"></md-autocomplete>\n * </hljs>\n *\n * ### Example with validation\n * <hljs lang=\"html\">\n * <form name=\"autocompleteForm\">\n *   <md-autocomplete\n *       required\n *       md-input-name=\"autocomplete\"\n *       md-selected-item=\"selectedItem\"\n *       md-search-text=\"searchText\"\n *       md-items=\"item in getMatches(searchText)\"\n *       md-item-text=\"item.display\">\n *     <md-item-template>\n *       <span md-highlight-text=\"searchText\">{{item.display}}</span>\n *     </md-item-template>\n *     <div ng-messages=\"autocompleteForm.autocomplete.$error\">\n *       <div ng-message=\"required\">This field is required</div>\n *     </div>\n *   </md-autocomplete>\n * </form>\n * </hljs>\n *\n * In this example, our code utilizes `md-item-template` and `ng-messages` to specify\n *     input validation for the field.\n *\n * ### Asynchronous Results\n * The autocomplete items expression also supports promises, which will resolve with the query\n * results.\n *\n * <hljs lang=\"js\">\n *   function AppController($scope, $http) {\n *     $scope.query = function(searchText) {\n *       return $http\n *         .get(BACKEND_URL + '/items/' + searchText)\n *         .then(function(data) {\n *           // Map the response object to the data object.\n *           return data;\n *         });\n *     };\n *   }\n * </hljs>\n *\n * <hljs lang=\"html\">\n *   <md-autocomplete\n *       md-selected-item=\"selectedItem\"\n *       md-search-text=\"searchText\"\n *       md-items=\"item in query(searchText)\">\n *     <md-item-template>\n *       <span md-highlight-text=\"searchText\">{{item}}</span>\n *     </md-item-template>\n * </md-autocomplete>\n * </hljs>\n *\n * ### Specifying Repeat Mode\n * You can use `md-mode` to specify whether to use standard or virtual lists for\n * rendering autocomplete options.\n * The `md-mode` accepts two values:\n * - `virtual` (default) Uses `md-virtual-repeat` to render list items. Virtual\n *    mode requires you to have consistent heights for all suggestions.\n * - `standard` uses `ng-repeat` to render list items. This allows you to have\n *    options of varying heights.\n *\n * Note that using 'standard' mode will require you to address any list\n * performance issues (e.g. pagination) separately within your application.\n *\n * <hljs lang=\"html\">\n *   <md-autocomplete\n *       md-selected-item=\"selectedItem\"\n *       md-search-text=\"searchText\"\n *       md-items=\"item in getMatches(searchText)\"\n *       md-item-text=\"item.display\"\n *       md-mode=\"standard\">\n *     <span md-highlight-text=\"searchText\">{{item.display}}</span>\n *   </md-autocomplete>\n * </hljs>\n */\nfunction MdAutocomplete ($$mdSvgRegistry) {\n  var REPEAT_STANDARD = 'standard';\n  var REPEAT_VIRTUAL = 'virtual';\n  var REPEAT_MODES = [REPEAT_STANDARD, REPEAT_VIRTUAL];\n\n  /** get a valid repeat mode from an md-mode attribute string. */\n  function getRepeatMode(modeStr) {\n    if (!modeStr) { return REPEAT_VIRTUAL; }\n    modeStr = modeStr.toLowerCase();\n    return  REPEAT_MODES.indexOf(modeStr) > -1 ? modeStr : REPEAT_VIRTUAL;\n  }\n\n  return {\n    controller:   'MdAutocompleteCtrl',\n    controllerAs: '$mdAutocompleteCtrl',\n    scope:        {\n      inputName:          '@mdInputName',\n      inputMinlength:     '@mdInputMinlength',\n      inputMaxlength:     '@mdInputMaxlength',\n      searchText:         '=?mdSearchText',\n      selectedItem:       '=?mdSelectedItem',\n      itemsExpr:          '@mdItems',\n      itemText:           '&mdItemText',\n      placeholder:        '@placeholder',\n      inputAriaDescribedBy: '@?inputAriaDescribedby',\n      inputAriaLabelledBy: '@?inputAriaLabelledby',\n      inputAriaLabel:     '@?inputAriaLabel',\n      noCache:            '=?mdNoCache',\n      requireMatch:       '=?mdRequireMatch',\n      selectOnMatch:      '=?mdSelectOnMatch',\n      matchInsensitive:   '=?mdMatchCaseInsensitive',\n      itemChange:         '&?mdSelectedItemChange',\n      textChange:         '&?mdSearchTextChange',\n      minLength:          '=?mdMinLength',\n      delay:              '=?mdDelay',\n      autofocus:          '=?mdAutofocus',\n      floatingLabel:      '@?mdFloatingLabel',\n      autoselect:         '=?mdAutoselect',\n      menuClass:          '@?mdMenuClass',\n      menuContainerClass: '@?mdMenuContainerClass',\n      inputClass:         '@?mdInputClass',\n      inputId:            '@?mdInputId',\n      escapeOptions:      '@?mdEscapeOptions',\n      dropdownItems:      '=?mdDropdownItems',\n      dropdownPosition:   '@?mdDropdownPosition',\n      clearButton:        '=?mdClearButton',\n      selectedMessage:    '@?mdSelectedMessage',\n      noMatchMessage:     '@?mdNoMatchMessage',\n      singleMatchMessage: '@?mdSingleMatchMessage',\n      multipleMatchStartMessage: '@?mdMultipleMatchStartMessage',\n      multipleMatchEndMessage: '@?mdMultipleMatchEndMessage',\n      mdMode: '=?mdMode'\n    },\n    compile: function(tElement, tAttrs) {\n      var attributes = ['md-select-on-focus', 'md-no-asterisk', 'ng-trim', 'ng-pattern'];\n      var input = tElement.find('input');\n\n      attributes.forEach(function(attribute) {\n        var attrValue = tAttrs[tAttrs.$normalize(attribute)];\n\n        if (attrValue !== null) {\n          input.attr(attribute, attrValue);\n        }\n      });\n\n      return function(scope, element, attrs, ctrl) {\n        // Retrieve the state of using a md-not-found template by using our attribute, which will\n        // be added to the element in the template function.\n        ctrl.hasNotFound = !!element.attr('md-has-not-found');\n\n        // By default the inset autocomplete should show the clear button when not explicitly\n        // overwritten or in floating label mode.\n        if (!angular.isDefined(attrs.mdClearButton) && !scope.floatingLabel) {\n          scope.clearButton = true;\n        }\n\n        scope.mdMode = getRepeatMode(attrs.mdMode);\n\n        // Stop click events from bubbling up to the document and triggering a flicker of the\n        // options panel while still supporting ng-click to be placed on md-autocomplete.\n        element.on('click touchstart touchend', function(event) {\n          event.stopPropagation();\n        });\n      };\n    },\n    template: function (element, attr) {\n      var noItemsTemplate = getNoItemsTemplate(),\n          itemTemplate    = getItemTemplate(),\n          leftover        = element.html(),\n          tabindex        = attr.tabindex;\n\n      // Set our attribute for the link function above which runs later.\n      // We will set an attribute, because otherwise the stored variables will be trashed when\n      // removing the element is hidden while retrieving the template. For example when using ngIf.\n      if (noItemsTemplate) element.attr('md-has-not-found', true);\n\n      // Always set our tabindex of the autocomplete directive to -1, because our input\n      // will hold the actual tabindex.\n      element.attr('tabindex', '-1');\n\n      return '\\\n        <md-autocomplete-wrap\\\n            ng-class=\"{ \\'md-whiteframe-z1\\': !floatingLabel, \\\n                        \\'md-menu-showing\\': !$mdAutocompleteCtrl.hidden, \\\n                        \\'md-show-clear-button\\': !!clearButton }\">\\\n          ' + getInputElement() + '\\\n          ' + getClearButton() + '\\\n          <md-progress-linear\\\n              class=\"' + (attr.mdFloatingLabel ? 'md-inline' : '') + '\"\\\n              ng-if=\"$mdAutocompleteCtrl.loadingIsVisible()\"\\\n              md-mode=\"indeterminate\"></md-progress-linear>\\\n          ' + getContainer(attr.mdMenuContainerClass, attr.mdMode) + '\\\n            <ul class=\"md-autocomplete-suggestions\"\\\n                ng-class=\"::menuClass\"\\\n                id=\"ul-{{$mdAutocompleteCtrl.id}}\"\\\n                ng-mouseup=\"$mdAutocompleteCtrl.focusInput()\"\\\n                role=\"listbox\">\\\n              <li class=\"md-autocomplete-suggestion\" ' + getRepeatType(attr.mdMode) + ' =\"item in $mdAutocompleteCtrl.matches\"\\\n                  ng-class=\"{ selected: $index === $mdAutocompleteCtrl.index }\"\\\n                  ng-attr-id=\"{{\\'md-option-\\' + $mdAutocompleteCtrl.id + \\'-\\' + $index}}\"\\\n                  ng-click=\"$mdAutocompleteCtrl.select($index)\"\\\n                  role=\"option\"\\\n                  aria-setsize=\"{{$mdAutocompleteCtrl.matches.length}}\"\\\n                  aria-posinset=\"{{$index+1}}\"\\\n                  aria-selected=\"{{$index === $mdAutocompleteCtrl.index ? true : false}}\" \\\n                  md-extra-name=\"$mdAutocompleteCtrl.itemName\">\\\n                  ' + itemTemplate + '\\\n                  </li>' + noItemsTemplate + '\\\n            </ul>\\\n          '  + getContainerClosingTags(attr.mdMode) + '\\\n        </md-autocomplete-wrap>';\n\n      function getItemTemplate() {\n        var templateTag = element.find('md-item-template').detach(),\n            html = templateTag.length ? templateTag.html() : element.html();\n        if (!templateTag.length) element.empty();\n        return '<md-autocomplete-parent-scope md-autocomplete-replace>' + html +\n               '</md-autocomplete-parent-scope>';\n      }\n\n      function getNoItemsTemplate() {\n        var templateTag = element.find('md-not-found').detach(),\n            template = templateTag.length ? templateTag.html() : '';\n        return template\n            ? '<li ng-if=\"$mdAutocompleteCtrl.notFoundVisible()\" class=\"md-autocomplete-suggestion\"\\\n                         md-autocomplete-parent-scope>' + template + '</li>'\n            : '';\n      }\n\n      function getContainer(menuContainerClass, repeatMode) {\n        // prepend a space if needed\n        menuContainerClass = menuContainerClass ? ' ' + menuContainerClass : '';\n\n        if (isVirtualRepeatDisabled(repeatMode)) {\n          return '\\\n            <div \\\n                ng-hide=\"$mdAutocompleteCtrl.hidden\"\\\n                class=\"md-standard-list-container md-autocomplete-suggestions-container md-whiteframe-z1' + menuContainerClass + '\"\\\n                ng-class=\"{ \\'md-not-found\\': $mdAutocompleteCtrl.notFoundVisible() }\"\\\n                ng-mouseenter=\"$mdAutocompleteCtrl.listEnter()\"\\\n                ng-mouseleave=\"$mdAutocompleteCtrl.listLeave()\"\\\n                role=\"presentation\">\\\n              <div class=\"md-standard-list-scroller\" role=\"presentation\">';\n        }\n\n        return '\\\n          <md-virtual-repeat-container\\\n              md-auto-shrink\\\n              md-auto-shrink-min=\"1\"\\\n              ng-hide=\"$mdAutocompleteCtrl.hidden\"\\\n              class=\"md-virtual-repeat-container md-autocomplete-suggestions-container md-whiteframe-z1' + menuContainerClass + '\"\\\n              ng-class=\"{ \\'md-not-found\\': $mdAutocompleteCtrl.notFoundVisible() }\"\\\n              ng-mouseenter=\"$mdAutocompleteCtrl.listEnter()\"\\\n              ng-mouseleave=\"$mdAutocompleteCtrl.listLeave()\"\\\n              role=\"presentation\">';\n      }\n\n      function getContainerClosingTags(repeatMode) {\n        return isVirtualRepeatDisabled(repeatMode) ?\n            '   </div>\\\n              </div>\\\n            </div>' : '</md-virtual-repeat-container>';\n      }\n\n      function getRepeatType(repeatMode) {\n        return isVirtualRepeatDisabled(repeatMode)  ?\n          'ng-repeat' : 'md-virtual-repeat';\n      }\n\n      function isVirtualRepeatDisabled(repeatMode) {\n        // ensure we have a valid repeat mode\n        var correctedRepeatMode = getRepeatMode(repeatMode);\n        return correctedRepeatMode !== REPEAT_VIRTUAL;\n      }\n\n      function getInputElement () {\n        if (attr.mdFloatingLabel) {\n          return '\\\n            <md-input-container ng-if=\"floatingLabel\">\\\n              <label>{{floatingLabel}}</label>\\\n              <input type=\"text\"\\\n                ' + (tabindex != null ? 'tabindex=\"' + tabindex + '\"' : '') + '\\\n                id=\"{{inputId || \\'fl-input-\\' + $mdAutocompleteCtrl.id}}\"\\\n                name=\"{{inputName || \\'fl-input-\\' + $mdAutocompleteCtrl.id }}\"\\\n                ng-class=\"::inputClass\"\\\n                autocomplete=\"off\"\\\n                ng-required=\"$mdAutocompleteCtrl.isRequired\"\\\n                ng-readonly=\"$mdAutocompleteCtrl.isReadonly\"\\\n                ng-minlength=\"inputMinlength\"\\\n                ng-maxlength=\"inputMaxlength\"\\\n                ng-disabled=\"$mdAutocompleteCtrl.isDisabled\"\\\n                ng-model=\"$mdAutocompleteCtrl.scope.searchText\"\\\n                ng-model-options=\"{ allowInvalid: true }\"\\\n                ng-mousedown=\"$mdAutocompleteCtrl.focusInput()\"\\\n                ng-keydown=\"$mdAutocompleteCtrl.keydown($event)\"\\\n                ng-blur=\"$mdAutocompleteCtrl.blur($event)\"\\\n                ng-focus=\"$mdAutocompleteCtrl.focus($event)\"\\\n                aria-label=\"{{floatingLabel}}\"\\\n                ng-attr-aria-autocomplete=\"{{$mdAutocompleteCtrl.isDisabled ? undefined : \\'list\\'}}\"\\\n                ng-attr-role=\"{{$mdAutocompleteCtrl.isDisabled ? undefined : \\'combobox\\'}}\"\\\n                aria-haspopup=\"{{!$mdAutocompleteCtrl.isDisabled}}\"\\\n                aria-expanded=\"{{!$mdAutocompleteCtrl.hidden}}\"\\\n                ng-attr-aria-owns=\"{{$mdAutocompleteCtrl.hidden || $mdAutocompleteCtrl.isDisabled ? undefined : \\'ul-\\' + $mdAutocompleteCtrl.id}}\"\\\n                ng-attr-aria-activedescendant=\"{{!$mdAutocompleteCtrl.hidden && $mdAutocompleteCtrl.activeOption ? $mdAutocompleteCtrl.activeOption : undefined}}\">\\\n              <div md-autocomplete-parent-scope md-autocomplete-replace>' + leftover + '</div>\\\n            </md-input-container>';\n        } else {\n          return '\\\n            <input type=\"text\"\\\n              ' + (tabindex != null ? 'tabindex=\"' + tabindex + '\"' : '') + '\\\n              id=\"{{inputId || \\'input-\\' + $mdAutocompleteCtrl.id}}\"\\\n              name=\"{{inputName || \\'input-\\' + $mdAutocompleteCtrl.id }}\"\\\n              ng-class=\"::inputClass\"\\\n              ng-if=\"!floatingLabel\"\\\n              autocomplete=\"off\"\\\n              ng-required=\"$mdAutocompleteCtrl.isRequired\"\\\n              ng-disabled=\"$mdAutocompleteCtrl.isDisabled\"\\\n              ng-readonly=\"$mdAutocompleteCtrl.isReadonly\"\\\n              ng-minlength=\"inputMinlength\"\\\n              ng-maxlength=\"inputMaxlength\"\\\n              ng-model=\"$mdAutocompleteCtrl.scope.searchText\"\\\n              ng-mousedown=\"$mdAutocompleteCtrl.focusInput()\"\\\n              ng-keydown=\"$mdAutocompleteCtrl.keydown($event)\"\\\n              ng-blur=\"$mdAutocompleteCtrl.blur($event)\"\\\n              ng-focus=\"$mdAutocompleteCtrl.focus($event)\"\\\n              placeholder=\"{{placeholder}}\"\\\n              aria-label=\"{{placeholder}}\"\\\n              ng-attr-aria-autocomplete=\"{{$mdAutocompleteCtrl.isDisabled ? undefined : \\'list\\'}}\"\\\n              ng-attr-role=\"{{$mdAutocompleteCtrl.isDisabled ? undefined : \\'combobox\\'}}\"\\\n              aria-haspopup=\"{{!$mdAutocompleteCtrl.isDisabled}}\"\\\n              aria-expanded=\"{{!$mdAutocompleteCtrl.hidden}}\"\\\n              ng-attr-aria-owns=\"{{$mdAutocompleteCtrl.hidden || $mdAutocompleteCtrl.isDisabled ? undefined : \\'ul-\\' + $mdAutocompleteCtrl.id}}\"\\\n              ng-attr-aria-activedescendant=\"{{!$mdAutocompleteCtrl.hidden && $mdAutocompleteCtrl.activeOption ? $mdAutocompleteCtrl.activeOption : undefined}}\">';\n        }\n      }\n\n      function getClearButton() {\n        return '' +\n          '<button ' +\n              'type=\"button\" ' +\n              'aria-label=\"Clear Input\" ' +\n              'tabindex=\"0\" ' +\n              'ng-if=\"clearButton && $mdAutocompleteCtrl.scope.searchText\" ' +\n              'ng-click=\"$mdAutocompleteCtrl.clear($event)\">' +\n            '<md-icon md-svg-src=\"' + $$mdSvgRegistry.mdClose + '\"></md-icon>' +\n          '</button>';\n        }\n    }\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMdAutocompleteItemScopeDirective.$inject = [\"$compile\", \"$mdUtil\"];angular\n  .module('material.components.autocomplete')\n  .directive('mdAutocompleteParentScope', MdAutocompleteItemScopeDirective);\n\nfunction MdAutocompleteItemScopeDirective($compile, $mdUtil) {\n  return {\n    restrict: 'AE',\n    compile: compile,\n    terminal: true,\n    transclude: 'element'\n  };\n\n  function compile(tElement, tAttr, transclude) {\n    return function postLink(scope, element, attr) {\n      var ctrl = scope.$mdAutocompleteCtrl;\n      var newScope = ctrl.parent.$new();\n      var itemName = ctrl.itemName;\n\n      // Watch for changes to our scope's variables and copy them to the new scope\n      watchVariable('$index', '$index');\n      watchVariable('item', itemName);\n\n      // Ensure that $digest calls on our scope trigger $digest on newScope.\n      connectScopes();\n\n      // Link the element against newScope.\n      transclude(newScope, function(clone) {\n        element.after(clone);\n      });\n\n      /**\n       * Creates a watcher for variables that are copied from the parent scope\n       * @param variable\n       * @param alias\n       */\n      function watchVariable(variable, alias) {\n        newScope[alias] = scope[variable];\n\n        scope.$watch(variable, function(value) {\n          $mdUtil.nextTick(function() {\n            newScope[alias] = value;\n          });\n        });\n      }\n\n      /**\n       * Creates watchers on scope and newScope that ensure that for any\n       * $digest of scope, newScope is also $digested.\n       */\n      function connectScopes() {\n        var scopeDigesting = false;\n        var newScopeDigesting = false;\n\n        scope.$watch(function() {\n          if (newScopeDigesting || scopeDigesting) {\n            return;\n          }\n\n          scopeDigesting = true;\n          scope.$$postDigest(function() {\n            if (!newScopeDigesting) {\n              newScope.$digest();\n            }\n\n            scopeDigesting = newScopeDigesting = false;\n          });\n        });\n\n        newScope.$watch(function() {\n          newScopeDigesting = true;\n        });\n      }\n    };\n  }\n}\n})();\n(function(){\n\"use strict\";\n\n\nMdHighlightCtrl.$inject = [\"$scope\", \"$element\", \"$attrs\", \"$mdUtil\"];angular\n    .module('material.components.autocomplete')\n    .controller('MdHighlightCtrl', MdHighlightCtrl);\n\nfunction MdHighlightCtrl ($scope, $element, $attrs, $mdUtil) {\n  this.$scope = $scope;\n  this.$element = $element;\n  this.$attrs = $attrs;\n  this.$mdUtil = $mdUtil;\n\n  // Cache the Regex to avoid rebuilding each time.\n  this.regex = null;\n}\n\nMdHighlightCtrl.prototype.init = function(unsafeTermFn, unsafeContentFn) {\n\n  this.flags = this.$attrs.mdHighlightFlags || '';\n\n  this.unregisterFn = this.$scope.$watch(function($scope) {\n    return {\n      term: unsafeTermFn($scope),\n      contentText: unsafeContentFn($scope)\n    };\n  }.bind(this), this.onRender.bind(this), true);\n\n  this.$element.on('$destroy', this.unregisterFn);\n};\n\n/**\n * Triggered once a new change has been recognized and the highlighted\n * text needs to be updated.\n */\nMdHighlightCtrl.prototype.onRender = function(state, prevState) {\n\n  var contentText = state.contentText;\n\n  /* Update the regex if it's outdated, because we don't want to rebuilt it constantly. */\n  if (this.regex === null || state.term !== prevState.term) {\n    this.regex = this.createRegex(state.term, this.flags);\n  }\n\n  /* If a term is available apply the regex to the content */\n  if (state.term) {\n    this.applyRegex(contentText);\n  } else {\n    this.$element.text(contentText);\n  }\n\n};\n\n/**\n * Decomposes the specified text into different tokens (whether match or not).\n * Breaking down the string guarantees proper XSS protection due to the native browser\n * escaping of unsafe text.\n */\nMdHighlightCtrl.prototype.applyRegex = function(text) {\n  var tokens = this.resolveTokens(text);\n\n  this.$element.empty();\n\n  tokens.forEach(function (token) {\n\n    if (token.isMatch) {\n      var tokenEl = angular.element('<span class=\"highlight\">').text(token.text);\n\n      this.$element.append(tokenEl);\n    } else {\n      this.$element.append(document.createTextNode(token));\n    }\n\n  }.bind(this));\n\n};\n\n  /**\n * Decomposes the specified text into different tokens by running the regex against the text.\n */\nMdHighlightCtrl.prototype.resolveTokens = function(string) {\n  var tokens = [];\n  var lastIndex = 0;\n\n  // Use replace here, because it supports global and single regular expressions at same time.\n  string.replace(this.regex, function(match, index) {\n    appendToken(lastIndex, index);\n\n    tokens.push({\n      text: match,\n      isMatch: true\n    });\n\n    lastIndex = index + match.length;\n  });\n\n  // Append the missing text as a token.\n  appendToken(lastIndex);\n\n  return tokens;\n\n  function appendToken(from, to) {\n    var targetText = string.slice(from, to);\n    targetText && tokens.push(targetText);\n  }\n};\n\n/** Creates a regex for the specified text with the given flags. */\nMdHighlightCtrl.prototype.createRegex = function(term, flags) {\n  var startFlag = '', endFlag = '';\n  var regexTerm = this.$mdUtil.sanitize(term);\n\n  if (flags.indexOf('^') >= 0) startFlag = '^';\n  if (flags.indexOf('$') >= 0) endFlag = '$';\n\n  return new RegExp(startFlag + regexTerm + endFlag, flags.replace(/[$^]/g, ''));\n};\n\n})();\n(function(){\n\"use strict\";\n\n\nMdHighlight.$inject = [\"$interpolate\", \"$parse\"];angular\n    .module('material.components.autocomplete')\n    .directive('mdHighlightText', MdHighlight);\n\n/**\n * @ngdoc directive\n * @name mdHighlightText\n * @module material.components.autocomplete\n *\n * @description\n * The `md-highlight-text` directive allows you to specify text that should be highlighted within\n *     an element.  Highlighted text will be wrapped in `<span class=\"highlight\"></span>` which can\n *     be styled through CSS.  Please note that child elements may not be used with this directive.\n *\n * @param {string} md-highlight-text A model to be searched for\n * @param {string=} md-highlight-flags A list of flags (loosely based on JavaScript RexExp flags).\n * #### **Supported flags**:\n * - `g`: Find all matches within the provided text\n * - `i`: Ignore case when searching for matches\n * - `$`: Only match if the text ends with the search term\n * - `^`: Only match if the text begins with the search term\n *\n * @usage\n * <hljs lang=\"html\">\n * <input placeholder=\"Enter a search term...\" ng-model=\"searchTerm\" type=\"text\" />\n * <ul>\n *   <li ng-repeat=\"result in results\" md-highlight-text=\"searchTerm\" md-highlight-flags=\"i\">\n *     {{result.text}}\n *   </li>\n * </ul>\n * </hljs>\n */\n\nfunction MdHighlight ($interpolate, $parse) {\n  return {\n    terminal: true,\n    controller: 'MdHighlightCtrl',\n    compile: function mdHighlightCompile(tElement, tAttr) {\n      var termExpr = $parse(tAttr.mdHighlightText);\n      var unsafeContentExpr = $interpolate(tElement.html());\n\n      return function mdHighlightLink(scope, element, attr, ctrl) {\n        ctrl.init(termExpr, unsafeContentExpr);\n      };\n    }\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n/*\n * @ngdoc module\n * @name material.components.backdrop\n * @description Backdrop\n */\n\n/**\n * @ngdoc directive\n * @name mdBackdrop\n * @module material.components.backdrop\n *\n * @restrict E\n *\n * @description\n * `<md-backdrop>` is a backdrop element used by other components, such as dialog and bottom sheet.\n * Apply class `opaque` to make the backdrop use the theme backdrop color.\n *\n */\n\nangular\n  .module('material.components.backdrop', ['material.core'])\n  .directive('mdBackdrop', [\"$mdTheming\", \"$mdUtil\", \"$animate\", \"$rootElement\", \"$window\", \"$log\", \"$$rAF\", \"$document\", function BackdropDirective($mdTheming, $mdUtil, $animate, $rootElement, $window, $log, $$rAF, $document) {\n    var ERROR_CSS_POSITION = '<md-backdrop> may not work properly in a scrolled, static-positioned parent container.';\n\n    return {\n      restrict: 'E',\n      link: postLink\n    };\n\n    function postLink(scope, element, attrs) {\n      // backdrop may be outside the $rootElement, tell ngAnimate to animate regardless\n      if ($animate.pin) $animate.pin(element, $rootElement);\n\n      var bodyStyles;\n\n      $$rAF(function() {\n        // If body scrolling has been disabled using mdUtil.disableBodyScroll(),\n        // adjust the 'backdrop' height to account for the fixed 'body' top offset.\n        // Note that this can be pretty expensive and is better done inside the $$rAF.\n        bodyStyles = $window.getComputedStyle($document[0].body);\n\n        if (bodyStyles.position === 'fixed') {\n          var resizeHandler = $mdUtil.debounce(function(){\n            bodyStyles = $window.getComputedStyle($document[0].body);\n            resize();\n          }, 60, null, false);\n\n          resize();\n          angular.element($window).on('resize', resizeHandler);\n\n          scope.$on('$destroy', function() {\n            angular.element($window).off('resize', resizeHandler);\n          });\n        }\n\n        // Often $animate.enter() is used to append the backDrop element\n        // so let's wait until $animate is done...\n        var parent = element.parent();\n\n        if (parent.length) {\n          if (parent[0].nodeName === 'BODY') {\n            element.css('position', 'fixed');\n          }\n\n          var styles = $window.getComputedStyle(parent[0]);\n\n          if (styles.position === 'static') {\n            // backdrop uses position:absolute and will not work properly with parent position:static (default)\n            $log.warn(ERROR_CSS_POSITION);\n          }\n\n          // Only inherit the parent if the backdrop has a parent.\n          $mdTheming.inherit(element, parent);\n        }\n      });\n\n      function resize() {\n        var viewportHeight = parseInt(bodyStyles.height, 10) + Math.abs(parseInt(bodyStyles.top, 10));\n        element.css('height', viewportHeight + 'px');\n      }\n    }\n\n  }]);\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.bottomSheet\n * @description\n * BottomSheet\n */\nMdBottomSheetDirective.$inject = [\"$mdBottomSheet\"];\nMdBottomSheetProvider.$inject = [\"$$interimElementProvider\"];\nangular\n  .module('material.components.bottomSheet', [\n    'material.core',\n    'material.components.backdrop'\n  ])\n  .directive('mdBottomSheet', MdBottomSheetDirective)\n  .provider('$mdBottomSheet', MdBottomSheetProvider);\n\n/* @ngInject */\nfunction MdBottomSheetDirective($mdBottomSheet) {\n  return {\n    restrict: 'E',\n    link : function postLink(scope, element) {\n      element.addClass('_md');     // private md component indicator for styling\n\n      // When navigation force destroys an interimElement, then\n      // listen and $destroy() that interim instance...\n      scope.$on('$destroy', function() {\n        $mdBottomSheet.destroy();\n      });\n    }\n  };\n}\n\n\n/**\n * @ngdoc service\n * @name $mdBottomSheet\n * @module material.components.bottomSheet\n *\n * @description\n * `$mdBottomSheet` opens a bottom sheet over the app and provides a simple promise API.\n *\n * ## Restrictions\n *\n * - The bottom sheet's template must have an outer `<md-bottom-sheet>` element.\n * - Add the `md-grid` class to the bottom sheet for a grid layout.\n * - Add the `md-list` class to the bottom sheet for a list layout.\n *\n * @usage\n * <hljs lang=\"html\">\n * <div ng-controller=\"MyController\">\n *   <md-button ng-click=\"openBottomSheet()\">\n *     Open a Bottom Sheet!\n *   </md-button>\n * </div>\n * </hljs>\n * <hljs lang=\"js\">\n * var app = angular.module('app', ['ngMaterial']);\n * app.controller('MyController', function($scope, $mdBottomSheet) {\n *   $scope.openBottomSheet = function() {\n *     $mdBottomSheet.show({\n *       template: '<md-bottom-sheet>' +\n *       'Hello! <md-button ng-click=\"closeBottomSheet()\">Close</md-button>' +\n *       '</md-bottom-sheet>'\n *     })\n *\n *     // Fires when the hide() method is used\n *     .then(function() {\n *       console.log('You clicked the button to close the bottom sheet!');\n *     })\n *\n *     // Fires when the cancel() method is used\n *     .catch(function() {\n *       console.log('You hit escape or clicked the backdrop to close.');\n *     });\n *   };\n *\n *   $scope.closeBottomSheet = function($scope, $mdBottomSheet) {\n *     $mdBottomSheet.hide();\n *   }\n *\n * });\n * </hljs>\n *\n * ### Custom Presets\n * Developers are also able to create their own preset, which can be easily used without repeating\n * their options each time.\n *\n * <hljs lang=\"js\">\n *   $mdBottomSheetProvider.addPreset('testPreset', {\n *     options: function() {\n *       return {\n *         template:\n *           '<md-bottom-sheet>' +\n *             'This is a custom preset' +\n *           '</md-bottom-sheet>',\n *         controllerAs: 'bottomSheet',\n *         bindToController: true,\n *         clickOutsideToClose: true,\n *         escapeToClose: true\n *       };\n *     }\n *   });\n * </hljs>\n *\n * After you create your preset during the config phase, you can easily access it.\n *\n * <hljs lang=\"js\">\n *   $mdBottomSheet.show(\n *     $mdBottomSheet.testPreset()\n *   );\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdBottomSheet#show\n *\n * @description\n * Show a bottom sheet with the specified options.\n *\n * <em><b>Note:</b> You should <b>always</b> provide a `.catch()` method in case the user hits the\n * `esc` key or clicks the background to close. In this case, the `cancel()` method will\n * automatically be called on the bottom sheet which will `reject()` the promise. See the @usage\n * section above for an example.\n *\n * Newer versions of Angular will throw a `Possibly unhandled rejection` exception if you forget\n * this.</em>\n *\n * @param {Object} optionsOrPreset Either provide an `$mdBottomSheetPreset` defined during the\n * config phase or an options object, with the following properties:\n *\n *   - `templateUrl` - `{string=}`: The url of an html template file that will\n *   be used as the content of the bottom sheet. Restrictions: the template must\n *   have an outer `md-bottom-sheet` element.\n *   - `template` - `{string=}`: Same as templateUrl, except this is an actual\n *   template string.\n *   - `scope` - `{Object=}`: the scope to link the template / controller to. If none is specified,\n *   it will create a new child scope. This scope will be destroyed when the bottom sheet is\n *   removed unless `preserveScope` is set to true.\n *   - `preserveScope` - `{boolean=}`: whether to preserve the scope when the element is removed.\n *   Default is false\n *   - `controller` - `{string=}`: The controller to associate with this bottom sheet.\n *   - `locals` - `{string=}`: An object containing key/value pairs. The keys will be used as names\n *   of values to inject into the controller. For example, `locals: {three: 3}` would inject\n *   `three` into the controller with the value of 3.\n *   - `clickOutsideToClose` - `{boolean=}`: Whether the user can click outside the bottom sheet to\n *     close it. Default true.\n *   - `bindToController` - `{boolean=}`: When set to true, the locals will be bound to the\n *   controller instance and available in it's $onInit function.\n *   - `disableBackdrop` - `{boolean=}`: When set to true, the bottomsheet will not show a backdrop.\n *   - `escapeToClose` - `{boolean=}`: Whether the user can press escape to close the bottom sheet.\n *     Default true.\n *   - `isLockedOpen` - `{boolean=}`: Disables all default ways of closing the bottom sheet.\n *   **Note:** this will override the `clickOutsideToClose` and `escapeToClose` options, leaving\n *   only the `hide` and `cancel` methods as ways of closing the bottom sheet. Defaults to false.\n *   - `resolve` - `{Object=}`: Similar to locals, except it takes promises as values\n *   and the bottom sheet will not open until the promises resolve.\n *   - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.\n *   - `parent` - `{element=}`: The element to append the bottom sheet to. The `parent` may be a\n *   `function`, `string`, `Object`, or null. Defaults to appending to the body of the root element\n *   (or the root element) of the application.\n *   e.g. angular.element(document.getElementById('content')) or \"#content\"\n *   - `disableParentScroll` - `{boolean=}`: Whether to disable scrolling while the bottom sheet is\n *   open. Default true.\n *\n * @returns {promise} A promise that can be resolved with `$mdBottomSheet.hide()` or\n * rejected with `$mdBottomSheet.cancel()`.\n */\n\n/**\n * @ngdoc method\n * @name $mdBottomSheet#hide\n *\n * @description\n * Hide the existing bottom sheet and resolve the promise returned from\n * `$mdBottomSheet.show()`. This call will close the most recently opened/current bottom sheet (if\n * any).\n *\n * <em><b>Note:</b> Use a `.then()` on your `.show()` to handle this callback.</em>\n *\n * @param {*=} response An argument for the resolved promise.\n *\n */\n\n/**\n * @ngdoc method\n * @name $mdBottomSheet#cancel\n *\n * @description\n * Hide the existing bottom sheet and reject the promise returned from\n * `$mdBottomSheet.show()`.\n *\n * <em><b>Note:</b> Use a `.catch()` on your `.show()` to handle this callback.</em>\n *\n * @param {*=} response An argument for the rejected promise.\n *\n */\n\nfunction MdBottomSheetProvider($$interimElementProvider) {\n  // how fast we need to flick down to close the sheet, pixels/ms\n  bottomSheetDefaults.$inject = [\"$animate\", \"$mdConstant\", \"$mdUtil\", \"$mdTheming\", \"$mdBottomSheet\", \"$rootElement\", \"$mdGesture\", \"$log\"];\n  var CLOSING_VELOCITY = 0.5;\n  var PADDING = 80; // same as css\n\n  return $$interimElementProvider('$mdBottomSheet')\n    .setDefaults({\n      methods: ['disableParentScroll', 'escapeToClose', 'clickOutsideToClose'],\n      options: bottomSheetDefaults\n    });\n\n  /* @ngInject */\n  function bottomSheetDefaults($animate, $mdConstant, $mdUtil, $mdTheming, $mdBottomSheet, $rootElement,\n                               $mdGesture, $log) {\n    var backdrop;\n\n    return {\n      themable: true,\n      onShow: onShow,\n      onRemove: onRemove,\n      disableBackdrop: false,\n      escapeToClose: true,\n      clickOutsideToClose: true,\n      disableParentScroll: true,\n      isLockedOpen: false\n    };\n\n    function onShow(scope, element, options) {\n      element = $mdUtil.extractElementByName(element, 'md-bottom-sheet');\n\n      // prevent tab focus or click focus on the bottom-sheet container\n      element.attr('tabindex', '-1');\n\n      // Once the md-bottom-sheet has `ng-cloak` applied on his template the opening animation will not work properly.\n      // This is a very common problem, so we have to notify the developer about this.\n      if (element.hasClass('ng-cloak')) {\n        var message = '$mdBottomSheet: using `<md-bottom-sheet ng-cloak>` will affect the bottom-sheet opening animations.';\n        $log.warn(message, element[0]);\n      }\n\n      if (options.isLockedOpen) {\n        options.clickOutsideToClose = false;\n        options.escapeToClose = false;\n      } else {\n        options.cleanupGestures = registerGestures(element, options.parent);\n      }\n\n      if (!options.disableBackdrop) {\n        // Add a backdrop that will close on click\n        backdrop = $mdUtil.createBackdrop(scope, \"md-bottom-sheet-backdrop md-opaque\");\n\n        // Prevent mouse focus on backdrop; ONLY programmatic focus allowed.\n        // This allows clicks on backdrop to propagate to the $rootElement and\n        // ESC key events to be detected properly.\n        backdrop[0].tabIndex = -1;\n\n        if (options.clickOutsideToClose) {\n          backdrop.on('click', function() {\n            $mdUtil.nextTick($mdBottomSheet.cancel, true);\n          });\n        }\n\n        $mdTheming.inherit(backdrop, options.parent);\n\n        $animate.enter(backdrop, options.parent, null);\n      }\n\n      $mdTheming.inherit(element, options.parent);\n\n      if (options.disableParentScroll) {\n        options.restoreScroll = $mdUtil.disableScrollAround(element, options.parent);\n      }\n\n      return $animate.enter(element, options.parent, backdrop)\n        .then(function() {\n          var focusable = $mdUtil.findFocusTarget(element) || angular.element(\n            element[0].querySelector('button') ||\n            element[0].querySelector('a') ||\n            element[0].querySelector($mdUtil.prefixer('ng-click', true))\n          ) || backdrop;\n\n          if (options.escapeToClose) {\n            options.rootElementKeyupCallback = function(e) {\n              if (e.keyCode === $mdConstant.KEY_CODE.ESCAPE) {\n                $mdUtil.nextTick($mdBottomSheet.cancel, true);\n              }\n            };\n\n            $rootElement.on('keyup', options.rootElementKeyupCallback);\n            focusable && focusable.focus();\n          }\n        });\n\n    }\n\n    function onRemove(scope, element, options) {\n      if (!options.disableBackdrop) $animate.leave(backdrop);\n\n      return $animate.leave(element).then(function() {\n        if (options.disableParentScroll) {\n          options.restoreScroll();\n          delete options.restoreScroll;\n        }\n\n        options.cleanupGestures && options.cleanupGestures();\n      });\n    }\n\n    /**\n     * Adds the drag gestures to the bottom sheet.\n     * @param {JQLite} element where CSS transitions will be applied\n     * @param {JQLite} parent used for registering gesture listeners\n     * @return {Function} function that removes gesture listeners that were set up by\n     *  registerGestures()\n     */\n    function registerGestures(element, parent) {\n      var deregister = $mdGesture.register(parent, 'drag', { horizontal: false });\n      parent.on('$md.dragstart', onDragStart)\n        .on('$md.drag', onDrag)\n        .on('$md.dragend', onDragEnd);\n\n      return function cleanupGestures() {\n        deregister();\n        parent.off('$md.dragstart', onDragStart);\n        parent.off('$md.drag', onDrag);\n        parent.off('$md.dragend', onDragEnd);\n      };\n\n      function onDragStart() {\n        // Disable transitions on transform so that it feels fast\n        element.css($mdConstant.CSS.TRANSITION_DURATION, '0ms');\n      }\n\n      function onDrag(ev) {\n        var transform = ev.pointer.distanceY;\n        if (transform < 5) {\n          // Slow down drag when trying to drag up, and stop after PADDING\n          transform = Math.max(-PADDING, transform / 2);\n        }\n        element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + transform) + 'px,0)');\n      }\n\n      function onDragEnd(ev) {\n        if (ev.pointer.distanceY > 0 &&\n            (ev.pointer.distanceY > 20 || Math.abs(ev.pointer.velocityY) > CLOSING_VELOCITY)) {\n          var distanceRemaining = element.prop('offsetHeight') - ev.pointer.distanceY;\n          var transitionDuration = Math.min(distanceRemaining / ev.pointer.velocityY * 0.75, 500);\n          element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDuration + 'ms');\n          $mdUtil.nextTick($mdBottomSheet.cancel, true);\n        } else {\n          element.css($mdConstant.CSS.TRANSITION_DURATION, '');\n          element.css($mdConstant.CSS.TRANSFORM, '');\n        }\n      }\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.button\n * @description\n *\n * Button\n */\nMdButtonDirective.$inject = [\"$mdButtonInkRipple\", \"$mdTheming\", \"$mdAria\", \"$mdInteraction\"];\nMdAnchorDirective.$inject = [\"$mdTheming\"];\nangular\n    .module('material.components.button', ['material.core'])\n    .directive('mdButton', MdButtonDirective)\n    .directive('a', MdAnchorDirective);\n\n\n/**\n * @private\n * @restrict E\n *\n * @description\n * `a` is an anchor directive used to inherit theme colors for md-primary, md-accent, etc.\n *\n * @usage\n *\n * <hljs lang=\"html\">\n *  <md-content md-theme=\"myTheme\">\n *    <a href=\"#chapter1\" class=\"md-accent\"></a>\n *  </md-content>\n * </hljs>\n */\nfunction MdAnchorDirective($mdTheming) {\n  return {\n    restrict : 'E',\n    link : function postLink(scope, element) {\n      // Make sure to inherit theme so stand-alone anchors\n      // support theme colors for md-primary, md-accent, etc.\n      $mdTheming(element);\n    }\n  };\n}\n\n\n/**\n * @ngdoc directive\n * @name mdButton\n * @module material.components.button\n *\n * @restrict E\n *\n * @description\n * `<md-button>` is a button directive with optional ink ripples (default enabled).\n *\n * If you supply a `href` or `ng-href` attribute, it will become an `<a>` element. Otherwise, it\n * will become a `<button>` element. As per the\n * [Material Design specifications](https://material.google.com/style/color.html#color-color-palette)\n * the FAB button background is filled with the accent color [by default]. The primary color palette\n * may be used with the `md-primary` class.\n *\n * Developers can also change the color palette of the button, by using the following classes\n * - `md-primary`\n * - `md-accent`\n * - `md-warn`\n *\n * See for example\n *\n * <hljs lang=\"html\">\n *   <md-button class=\"md-primary\">Primary Button</md-button>\n * </hljs>\n *\n * Button can be also raised, which means that they will use the current color palette to fill the button.\n *\n * <hljs lang=\"html\">\n *   <md-button class=\"md-accent md-raised\">Raised and Accent Button</md-button>\n * </hljs>\n *\n * It is also possible to disable the focus effect on the button, by using the following markup.\n *\n * <hljs lang=\"html\">\n *   <md-button class=\"md-no-focus\">No Focus Style</md-button>\n * </hljs>\n *\n * @param {string=} aria-label Adds alternative text to button for accessibility, useful for icon buttons.\n * If no default text is found, a warning will be logged.\n * @param {boolean=} md-no-ink If present, disable ink ripple effects.\n * @param {string=} md-ripple-size Overrides the default ripple size logic. Options: `full`, `partial`, `auto`.\n * @param {expression=} ng-disabled Disable the button when the expression is truthy.\n * @param {expression=} ng-blur Expression evaluated when focus is removed from the button.\n *\n * @usage\n *\n * Regular buttons:\n *\n * <hljs lang=\"html\">\n *  <md-button> Flat Button </md-button>\n *  <md-button href=\"http://google.com\"> Flat link </md-button>\n *  <md-button class=\"md-raised\"> Raised Button </md-button>\n *  <md-button ng-disabled=\"true\"> Disabled Button </md-button>\n *  <md-button>\n *    <md-icon md-svg-src=\"your/icon.svg\"></md-icon>\n *    Register Now\n *  </md-button>\n * </hljs>\n *\n * FAB buttons:\n *\n * <hljs lang=\"html\">\n *  <md-button class=\"md-fab\" aria-label=\"FAB\">\n *    <md-icon md-svg-src=\"your/icon.svg\"></md-icon>\n *  </md-button>\n *  <!-- mini-FAB -->\n *  <md-button class=\"md-fab md-mini\" aria-label=\"Mini FAB\">\n *    <md-icon md-svg-src=\"your/icon.svg\"></md-icon>\n *  </md-button>\n *  <!-- Button with SVG Icon -->\n *  <md-button class=\"md-icon-button\" aria-label=\"Custom Icon Button\">\n *    <md-icon md-svg-icon=\"path/to/your.svg\"></md-icon>\n *  </md-button>\n * </hljs>\n */\nfunction MdButtonDirective($mdButtonInkRipple, $mdTheming, $mdAria, $mdInteraction) {\n\n  return {\n    restrict: 'EA',\n    replace: true,\n    transclude: true,\n    template: getTemplate,\n    link: postLink\n  };\n\n  function isAnchor(attr) {\n    return angular.isDefined(attr.href) || angular.isDefined(attr.ngHref) || angular.isDefined(attr.ngLink) || angular.isDefined(attr.uiSref);\n  }\n\n  function getTemplate(element, attr) {\n    if (isAnchor(attr)) {\n      return '<a class=\"md-button\" ng-transclude></a>';\n    } else {\n      // If buttons don't have type=\"button\", they will submit forms automatically.\n      var btnType = (typeof attr.type === 'undefined') ? 'button' : attr.type;\n      return '<button class=\"md-button\" type=\"' + btnType + '\" ng-transclude></button>';\n    }\n  }\n\n  function postLink(scope, element, attr) {\n    $mdTheming(element);\n    $mdButtonInkRipple.attach(scope, element);\n\n    // Use async expect to support possible bindings in the button label\n    $mdAria.expectWithoutText(element, 'aria-label');\n\n    // For anchor elements, we have to set tabindex manually when the element is disabled.\n    // We don't do this for md-nav-bar anchors as the component manages its own tabindex values.\n    if (isAnchor(attr) && angular.isDefined(attr.ngDisabled) &&\n        !element.hasClass('_md-nav-button')) {\n      scope.$watch(attr.ngDisabled, function(isDisabled) {\n        element.attr('tabindex', isDisabled ? -1 : 0);\n      });\n    }\n\n    // disabling click event when disabled is true\n    element.on('click', function(e){\n      if (attr.disabled === true) {\n        e.preventDefault();\n        e.stopImmediatePropagation();\n      }\n    });\n\n    if (!element.hasClass('md-no-focus')) {\n\n      element.on('focus', function() {\n\n        // Only show the focus effect when being focused through keyboard interaction or programmatically\n        if (!$mdInteraction.isUserInvoked() || $mdInteraction.getLastInteractionType() === 'keyboard') {\n          element.addClass('md-focused');\n        }\n\n      });\n\n      element.on('blur', function() {\n        element.removeClass('md-focused');\n      });\n    }\n\n  }\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.card\n *\n * @description\n * Card components.\n */\nmdCardDirective.$inject = [\"$mdTheming\"];\nangular.module('material.components.card', [\n    'material.core'\n  ])\n  .directive('mdCard', mdCardDirective);\n\n\n/**\n * @ngdoc directive\n * @name mdCard\n * @module material.components.card\n *\n * @restrict E\n *\n * @description\n * The `<md-card>` directive is a container element used within `<md-content>` containers.\n *\n * An image included as a direct descendant will fill the card's width. If you want to avoid this,\n * you can add the `md-image-no-fill` class to the parent element. The `<md-card-content>`\n * container will wrap text content and provide padding. An `<md-card-footer>` element can be\n * optionally included to put content flush against the bottom edge of the card.\n *\n * Action buttons can be included in an `<md-card-actions>` element, similar to `<md-dialog-actions>`.\n * You can then position buttons using layout attributes.\n *\n * Card is built with:\n * * `<md-card-header>` - Header for the card, holds avatar, text and squared image\n *  - `<md-card-avatar>` - Card avatar\n *    - `md-user-avatar` - Class for user image\n *    - `<md-icon>`\n *  - `<md-card-header-text>` - Contains elements for the card description\n *    - `md-title` - Class for the card title\n *    - `md-subhead` - Class for the card sub header\n * * `<img>` - Image for the card\n * * `<md-card-title>` - Card content title\n *  - `<md-card-title-text>`\n *    - `md-headline` - Class for the card content title\n *    - `md-subhead` - Class for the card content sub header\n *  - `<md-card-title-media>` - Squared image within the title\n *    - `md-media-sm` - Class for small image\n *    - `md-media-md` - Class for medium image\n *    - `md-media-lg` - Class for large image\n *    - `md-media-xl` - Class for extra large image\n * * `<md-card-content>` - Card content\n * * `<md-card-actions>` - Card actions\n *  - `<md-card-icon-actions>` - Icon actions\n *\n * Cards have constant width and variable heights; where the maximum height is limited to what can\n * fit within a single view on a platform, but it can temporarily expand as needed.\n *\n * @usage\n * ### Card with optional footer\n * <hljs lang=\"html\">\n * <md-card>\n *  <img src=\"card-image.png\" class=\"md-card-image\" alt=\"image caption\">\n *  <md-card-content>\n *    <h2>Card headline</h2>\n *    <p>Card content</p>\n *  </md-card-content>\n *  <md-card-footer>\n *    Card footer\n *  </md-card-footer>\n * </md-card>\n * </hljs>\n *\n * ### Card with actions\n * <hljs lang=\"html\">\n * <md-card>\n *  <img src=\"card-image.png\" class=\"md-card-image\" alt=\"image caption\">\n *  <md-card-content>\n *    <h2>Card headline</h2>\n *    <p>Card content</p>\n *  </md-card-content>\n *  <md-card-actions layout=\"row\" layout-align=\"end center\">\n *    <md-button>Action 1</md-button>\n *    <md-button>Action 2</md-button>\n *  </md-card-actions>\n * </md-card>\n * </hljs>\n *\n * ### Card with header, image, title actions and content\n * <hljs lang=\"html\">\n * <md-card>\n *   <md-card-header>\n *     <md-card-avatar>\n *       <img class=\"md-user-avatar\" src=\"avatar.png\"/>\n *     </md-card-avatar>\n *     <md-card-header-text>\n *       <span class=\"md-title\">Title</span>\n *       <span class=\"md-subhead\">Sub header</span>\n *     </md-card-header-text>\n *   </md-card-header>\n *   <img ng-src=\"card-image.png\" class=\"md-card-image\" alt=\"image caption\">\n *   <md-card-title>\n *     <md-card-title-text>\n *       <span class=\"md-headline\">Card headline</span>\n *       <span class=\"md-subhead\">Card subheader</span>\n *     </md-card-title-text>\n *   </md-card-title>\n *   <md-card-actions layout=\"row\" layout-align=\"start center\">\n *     <md-button>Action 1</md-button>\n *     <md-button>Action 2</md-button>\n *     <md-card-icon-actions>\n *       <md-button class=\"md-icon-button\" aria-label=\"icon\">\n *         <md-icon md-svg-icon=\"icon\"></md-icon>\n *       </md-button>\n *     </md-card-icon-actions>\n *   </md-card-actions>\n *   <md-card-content>\n *     <p>\n *      Card content\n *     </p>\n *   </md-card-content>\n * </md-card>\n * </hljs>\n */\nfunction mdCardDirective($mdTheming) {\n  return {\n    restrict: 'E',\n    link: function ($scope, $element, attr) {\n      $element.addClass('_md');     // private md component indicator for styling\n      $mdTheming($element);\n    }\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.checkbox\n * @description Checkbox module!\n */\nMdCheckboxDirective.$inject = [\"inputDirective\", \"$mdAria\", \"$mdConstant\", \"$mdTheming\", \"$mdUtil\", \"$mdInteraction\"];\nangular\n  .module('material.components.checkbox', ['material.core'])\n  .directive('mdCheckbox', MdCheckboxDirective);\n\n/**\n * @ngdoc directive\n * @name mdCheckbox\n * @module material.components.checkbox\n * @restrict E\n *\n * @description\n * The checkbox directive is used like the normal\n * [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).\n *\n * As per the [Material Design spec](https://material.io/archive/guidelines/style/color.html#color-color-palette)\n * the checkbox is in the accent color by default. The primary color palette may be used with\n * the `md-primary` class.\n *\n * @param {expression} ng-model Assignable angular expression to data-bind to.\n * @param {string=} name Property name of the form under which the control is published.\n * @param {expression=} ng-true-value The value to which the expression should be set when selected.\n * @param {expression=} ng-false-value The value to which the expression should be set when not\n *    selected.\n * @param {expression=} ng-change Expression to be executed when the model value changes.\n * @param {boolean=} md-no-ink If present, disable ink ripple effects.\n * @param {string=} aria-label Adds label to checkbox for accessibility.\n *    Defaults to checkbox's text. If no default text is found, a warning will be logged.\n * @param {expression=} md-indeterminate This determines when the checkbox should be rendered as\n *    'indeterminate'. If a truthy expression or no value is passed in the checkbox renders in the\n *    md-indeterminate state. If falsy expression is passed in it just looks like a normal unchecked\n *    checkbox. The indeterminate, checked, and unchecked states are mutually exclusive. A box\n *    cannot be in any two states at the same time. Adding the 'md-indeterminate' attribute\n *    overrides any checked/unchecked rendering logic. When using the 'md-indeterminate' attribute\n *    use 'ng-checked' to define rendering logic instead of using 'ng-model'.\n * @param {expression=} ng-checked If this expression evaluates as truthy, the 'md-checked' css\n *    class is added to the checkbox and it will appear checked.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-checkbox ng-model=\"isChecked\" aria-label=\"Finished?\">\n *   Finished ?\n * </md-checkbox>\n *\n * <md-checkbox md-no-ink ng-model=\"hasInk\" aria-label=\"No Ink Effects\">\n *   No Ink Effects\n * </md-checkbox>\n *\n * <md-checkbox ng-disabled=\"true\" ng-model=\"isDisabled\" aria-label=\"Disabled\">\n *   Disabled\n * </md-checkbox>\n *\n * </hljs>\n *\n */\nfunction MdCheckboxDirective(inputDirective, $mdAria, $mdConstant, $mdTheming, $mdUtil, $mdInteraction) {\n  inputDirective = inputDirective[0];\n\n  return {\n    restrict: 'E',\n    transclude: true,\n    require: ['^?mdInputContainer', '?ngModel', '?^form'],\n    priority: $mdConstant.BEFORE_NG_ARIA,\n    template:\n      '<div class=\"md-container\" md-ink-ripple md-ink-ripple-checkbox>' +\n        '<div class=\"md-icon\"></div>' +\n      '</div>' +\n      '<div ng-transclude class=\"md-label\"></div>',\n    compile: compile\n  };\n\n  // **********************************************************\n  // Private Methods\n  // **********************************************************\n\n  function compile (tElement, tAttrs) {\n    tAttrs.$set('tabindex', tAttrs.tabindex || '0');\n    tAttrs.$set('type', 'checkbox');\n    tAttrs.$set('role', tAttrs.type);\n    tElement.addClass('md-auto-horizontal-margin');\n\n    return  {\n      pre: function(scope, element) {\n        // Attach a click handler during preLink, in order to immediately stop propagation\n        // (especially for ng-click) when the checkbox is disabled.\n        element.on('click', function(e) {\n          if (this.hasAttribute('disabled')) {\n            e.stopImmediatePropagation();\n          }\n        });\n      },\n      post: postLink\n    };\n\n    function postLink(scope, element, attr, ctrls) {\n      var isIndeterminate;\n      var containerCtrl = ctrls[0];\n      var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();\n      var formCtrl = ctrls[2];\n      var labelHasLink = element.find('a').length > 0;\n\n      // The original component structure is not accessible when the checkbox's label contains a link.\n      // In order to keep backwards compatibility, we're only changing the structure of the component\n      // when we detect a link within the label. Using a span after the md-checkbox and attaching it\n      // via aria-labelledby allows screen readers to find and work with the link within the label.\n      if (labelHasLink) {\n        var labelId = 'label-' + $mdUtil.nextUid();\n        attr.$set('aria-labelledby', labelId);\n\n        var label = element.children()[1];\n        // Use jQLite here since ChildNode.remove() is not supported in IE11.\n        angular.element(label).remove();\n        label.removeAttribute('ng-transclude');\n        label.className = 'md-checkbox-link-label';\n        label.setAttribute('id', labelId);\n        element.after(label);\n        // Make sure that clicking on the label still causes the checkbox to be toggled, when appropriate.\n        var externalLabel = element.next();\n        externalLabel.on('click', listener);\n      }\n\n      if (containerCtrl) {\n        var isErrorGetter = containerCtrl.isErrorGetter || function() {\n          return ngModelCtrl.$invalid && (ngModelCtrl.$touched || (formCtrl && formCtrl.$submitted));\n        };\n\n        containerCtrl.input = element;\n\n        scope.$watch(isErrorGetter, containerCtrl.setInvalid);\n      }\n\n      $mdTheming(element);\n\n      // Redirect focus events to the root element, because IE11 is always focusing the container element instead\n      // of the md-checkbox element. This causes issues when using ngModelOptions: `updateOnBlur`\n      element.children().on('focus', function() {\n        element.focus();\n      });\n\n      if ($mdUtil.parseAttributeBoolean(attr.mdIndeterminate)) {\n        setIndeterminateState();\n        scope.$watch(attr.mdIndeterminate, setIndeterminateState);\n      }\n\n      if (attr.ngChecked) {\n        scope.$watch(scope.$eval.bind(scope, attr.ngChecked), function(value) {\n          ngModelCtrl.$setViewValue(value);\n          ngModelCtrl.$render();\n        });\n      }\n\n      $$watchExpr('ngDisabled', 'tabindex', {\n        true: '-1',\n        false: attr.tabindex\n      });\n\n      // Don't emit a warning when the label has a link within it. In that case we'll use\n      // aria-labelledby to point to another span that should be read as the label.\n      if (!labelHasLink) {\n        $mdAria.expectWithText(element, 'aria-label');\n      }\n\n      // Reuse the original input[type=checkbox] directive from AngularJS core.\n      // This is a bit hacky as we need our own event listener and own render\n      // function.\n      inputDirective.link.pre(scope, {\n        on: angular.noop,\n        0: {}\n      }, attr, [ngModelCtrl]);\n\n      element.on('click', listener)\n        .on('keypress', keypressHandler)\n        .on('focus', function() {\n          if ($mdInteraction.getLastInteractionType() === 'keyboard') {\n            element.addClass('md-focused');\n          }\n        })\n        .on('blur', function() {\n          element.removeClass('md-focused');\n        });\n\n      ngModelCtrl.$render = render;\n\n      function $$watchExpr(expr, htmlAttr, valueOpts) {\n        if (attr[expr]) {\n          scope.$watch(attr[expr], function(val) {\n            if (valueOpts[val]) {\n              element.attr(htmlAttr, valueOpts[val]);\n            }\n          });\n        }\n      }\n\n      /**\n       * @param {KeyboardEvent} ev 'keypress' event to handle\n       */\n      function keypressHandler(ev) {\n        var keyCode = ev.which || ev.keyCode;\n        var submit, form;\n\n        ev.preventDefault();\n        switch (keyCode) {\n          case $mdConstant.KEY_CODE.SPACE:\n            element.addClass('md-focused');\n            listener(ev);\n            break;\n          case $mdConstant.KEY_CODE.ENTER:\n            // Match the behavior of the native <input type=\"checkbox\">.\n            // When the enter key is pressed while focusing a native checkbox inside a form,\n            // the browser will trigger a `click` on the first non-disabled submit button/input\n            // in the form. Note that this is different from text inputs, which\n            // will directly submit the form without needing a submit button/input to be present.\n            form = $mdUtil.getClosest(ev.target, 'form');\n            if (form) {\n              submit = form.querySelector('button[type=\"submit\"]:enabled, input[type=\"submit\"]:enabled');\n              if (submit) {\n                submit.click();\n              }\n            }\n            break;\n        }\n      }\n\n      function listener(ev) {\n        // skipToggle boolean is used by the switch directive to prevent the click event\n        // when releasing the drag. There will be always a click if releasing the drag over the checkbox.\n        // If the click came from a link in the checkbox, don't toggle the value.\n        // We want the link to be opened without changing the value in this case.\n        if (element[0].hasAttribute('disabled') || scope.skipToggle || ev.target.tagName === 'A') {\n          return;\n        }\n\n        scope.$apply(function() {\n          // Toggle the checkbox value...\n          var viewValue = attr.ngChecked && attr.ngClick ? attr.checked : !ngModelCtrl.$viewValue;\n\n          ngModelCtrl.$setViewValue(viewValue, ev && ev.type);\n          ngModelCtrl.$render();\n        });\n      }\n\n      function render() {\n        // Cast the $viewValue to a boolean since it could be undefined\n        var checked = !!ngModelCtrl.$viewValue && !isIndeterminate;\n        element.toggleClass('md-checked', checked);\n        if (!isIndeterminate) {\n          if (checked) {\n            element.attr('aria-checked', 'true');\n          } else {\n            element.attr('aria-checked', 'false');\n          }\n        }\n      }\n\n      /**\n       * @param {string=} newValue\n       */\n      function setIndeterminateState(newValue) {\n        isIndeterminate = newValue !== false;\n        if (isIndeterminate) {\n          element.attr('aria-checked', 'mixed');\n        }\n        element.toggleClass('md-indeterminate', isIndeterminate);\n        ngModelCtrl.$render();\n      }\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.chips\n */\n/*\n * @see js folder for chips implementation\n */\nangular.module('material.components.chips', [\n  'material.core',\n  'material.components.autocomplete'\n]);\n\n})();\n(function(){\n\"use strict\";\n\n\nMdChipCtrl.$inject = [\"$scope\", \"$element\", \"$mdConstant\", \"$timeout\", \"$mdUtil\"];angular\n  .module('material.components.chips')\n  .controller('MdChipCtrl', MdChipCtrl);\n\n/**\n * Controller for the MdChip component. Responsible for handling keyboard\n * events and editing the chip if needed.\n *\n * @param $scope\n * @param $element\n * @param $mdConstant\n * @param $timeout\n * @param $mdUtil\n * @constructor\n */\nfunction MdChipCtrl ($scope, $element, $mdConstant, $timeout, $mdUtil) {\n  /**\n   * @type {$scope}\n   */\n  this.$scope = $scope;\n\n  /**\n   * @type {$element}\n   */\n  this.$element = $element;\n\n  /**\n   * @type {$mdConstant}\n   */\n  this.$mdConstant = $mdConstant;\n\n  /**\n   * @type {$timeout}\n   */\n  this.$timeout = $timeout;\n\n  /**\n   * @type {$mdUtil}\n   */\n  this.$mdUtil = $mdUtil;\n\n  /**\n   * @type {boolean}\n   */\n  this.isEditing = false;\n\n  /**\n   * @type {MdChipsCtrl}\n   */\n  this.parentController = undefined;\n\n  /**\n   * @type {boolean}\n   */\n  this.enableChipEdit = false;\n}\n\n\n/**\n * @param {MdChipsCtrl} controller\n */\nMdChipCtrl.prototype.init = function(controller) {\n  this.parentController = controller;\n  this.enableChipEdit = this.parentController.enableChipEdit;\n\n  if (this.enableChipEdit) {\n    this.$element.on('keydown', this.chipKeyDown.bind(this));\n    this.$element.on('dblclick', this.chipMouseDoubleClick.bind(this));\n    this.getChipContent().addClass('_md-chip-content-edit-is-enabled');\n  }\n};\n\n\n/**\n * @return {Object} first element with the md-chip-content class\n */\nMdChipCtrl.prototype.getChipContent = function() {\n  var chipContents = this.$element[0].getElementsByClassName('md-chip-content');\n  return angular.element(chipContents[0]);\n};\n\n\n/**\n * When editing the chip, if the user modifies the existing contents, we'll get a span back and\n * need to ignore text elements as they only contain blank space.\n * `children()` ignores text elements.\n *\n * When editing the chip, if the user deletes the contents and then enters some new content\n * we'll only get a text element back.\n * @return {Object} jQuery object representing the content element of the chip\n */\nMdChipCtrl.prototype.getContentElement = function() {\n  var contentElement = angular.element(this.getChipContent().children()[0]);\n  if (!contentElement || contentElement.length === 0) {\n    contentElement = angular.element(this.getChipContent().contents()[0]);\n  }\n  return contentElement;\n};\n\n\n/**\n * @return {number} index of this chip\n */\nMdChipCtrl.prototype.getChipIndex = function() {\n  return parseInt(this.$element.attr('index'));\n};\n\n\n/**\n * Update the chip's contents, focus the chip if it's selected, and exit edit mode.\n * If the contents were updated to be empty, remove the chip and re-focus the input element.\n */\nMdChipCtrl.prototype.goOutOfEditMode = function() {\n  if (!this.isEditing) {\n    return;\n  }\n\n  this.isEditing = false;\n  this.$element.removeClass('_md-chip-editing');\n  this.getChipContent()[0].contentEditable = 'false';\n  var chipIndex = this.getChipIndex();\n\n  var content = this.getContentElement().text();\n  if (content) {\n    this.parentController.updateChipContents(chipIndex, content);\n\n    this.$mdUtil.nextTick(function() {\n      if (this.parentController.selectedChip === chipIndex) {\n        this.parentController.focusChip(chipIndex);\n      }\n    }.bind(this));\n  } else {\n    this.parentController.removeChipAndFocusInput(chipIndex);\n  }\n};\n\n\n/**\n * Given an HTML element. Selects contents of it.\n * @param {Element} node\n */\nMdChipCtrl.prototype.selectNodeContents = function(node) {\n  var range, selection;\n  if (document.body.createTextRange) {\n    range = document.body.createTextRange();\n    range.moveToElementText(node);\n    range.select();\n  } else if (window.getSelection) {\n    selection = window.getSelection();\n    range = document.createRange();\n    range.selectNodeContents(node);\n    selection.removeAllRanges();\n    selection.addRange(range);\n  }\n};\n\n\n/**\n * Presents an input element to edit the contents of the chip.\n */\nMdChipCtrl.prototype.goInEditMode = function() {\n  this.isEditing = true;\n  this.$element.addClass('_md-chip-editing');\n  this.getChipContent()[0].contentEditable = 'true';\n  this.getChipContent().on('blur', function() {\n    this.goOutOfEditMode();\n  }.bind(this));\n\n  this.selectNodeContents(this.getChipContent()[0]);\n};\n\n\n/**\n * Handles the keydown event on the chip element. If enable-chip-edit attribute is\n * set to true, space or enter keys can trigger going into edit mode. Enter can also\n * trigger submitting if the chip is already being edited.\n * @param {KeyboardEvent} event\n */\nMdChipCtrl.prototype.chipKeyDown = function(event) {\n  if (!this.isEditing &&\n    (event.keyCode === this.$mdConstant.KEY_CODE.ENTER ||\n      event.keyCode === this.$mdConstant.KEY_CODE.SPACE)) {\n    event.preventDefault();\n    this.goInEditMode();\n  } else if (this.isEditing && event.keyCode === this.$mdConstant.KEY_CODE.ENTER) {\n    event.preventDefault();\n    this.goOutOfEditMode();\n  }\n};\n\n\n/**\n * Enter edit mode if we're not already editing and the enable-chip-edit attribute is enabled.\n */\nMdChipCtrl.prototype.chipMouseDoubleClick = function() {\n  if (this.enableChipEdit && !this.isEditing) {\n    this.goInEditMode();\n  }\n};\n\n})();\n(function(){\n\"use strict\";\n\n\nMdChip.$inject = [\"$mdTheming\", \"$mdUtil\", \"$compile\", \"$timeout\"];angular\n  .module('material.components.chips')\n  .directive('mdChip', MdChip);\n\n/**\n * @ngdoc directive\n * @name mdChip\n * @module material.components.chips\n *\n * @description\n * `<md-chip>` is a component used within `<md-chips>`. It is responsible for rendering an\n * individual chip.\n *\n *\n * @usage\n * <hljs lang=\"html\">\n *   <md-chips>\n *     <md-chip>{{$chip}}</md-chip>\n *   </md-chips>\n * </hljs>\n *\n */\n\n/**\n * MDChip Directive Definition\n *\n * @param $mdTheming\n * @param $mdUtil\n * @param $compile\n * @param $timeout\n * @ngInject\n */\nfunction MdChip($mdTheming, $mdUtil, $compile, $timeout) {\n  return {\n    restrict: 'E',\n    require: ['^?mdChips', 'mdChip'],\n    link: postLink,\n    controller: 'MdChipCtrl'\n  };\n\n  function postLink(scope, element, attr, ctrls) {\n    var chipsController = ctrls.shift();\n    var chipController = ctrls.shift();\n    var chipContentElement = angular.element(element[0].querySelector('.md-chip-content'));\n\n    $mdTheming(element);\n\n    if (chipsController) {\n      chipController.init(chipsController);\n\n      // When a chip is blurred, make sure to unset (or reset) the selected chip so that tabbing\n      // through elements works properly\n      chipContentElement.on('blur', function() {\n        chipsController.resetSelectedChip();\n        chipsController.$scope.$applyAsync();\n      });\n    }\n\n    // Use $timeout to ensure we run AFTER the element has been added to the DOM so we can focus it.\n    $timeout(function() {\n      if (!chipsController) {\n        return;\n      }\n\n      if (chipsController.shouldFocusLastChip) {\n        chipsController.focusLastChipThenInput();\n      }\n    });\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMdChipRemove.$inject = [\"$timeout\"];angular\n    .module('material.components.chips')\n    .directive('mdChipRemove', MdChipRemove);\n\n/**\n * @ngdoc directive\n * @name mdChipRemove\n * @restrict A\n * @module material.components.chips\n *\n * @description\n * Indicates that the associated element should be used as the delete button template for all chips.\n * The associated element must be a child of `md-chips`.\n *\n * The provided button template will be appended to each chip and will remove the associated chip\n * on click.\n *\n * The button is not styled or themed based on the theme set on the `md-chips` component. A theme\n * class and custom icon can be specified in your template.\n *\n * You can also specify the `type` of the button in your template.\n *\n * @usage\n * ### With Standard Chips\n * <hljs lang=\"html\">\n *   <md-chips ...>\n *     <button md-chip-remove type=\"button\" aria-label=\"Remove {{$chip}}\">\n *       <md-icon md-svg-icon=\"md-cancel\"></md-icon>\n *     </button>\n *   </md-chips>\n * </hljs>\n *\n * ### With Object Chips\n * <hljs lang=\"html\">\n *   <md-chips ...>\n *     <button md-chip-remove type=\"button\" aria-label=\"Remove {{$chip.name}}\">\n *       <md-icon md-svg-icon=\"md-cancel\"></md-icon>\n *     </button>\n *   </md-chips>\n * </hljs>\n */\n\n\n/**\n * MdChipRemove Directive Definition.\n *\n * @param $timeout\n * @returns {{restrict: string, require: string[], link: Function, scope: boolean}}\n * @constructor\n */\nfunction MdChipRemove ($timeout) {\n  return {\n    restrict: 'A',\n    require: '^mdChips',\n    scope: false,\n    link: postLink\n  };\n\n  function postLink(scope, element, attr, ctrl) {\n    element.on('click', function() {\n      scope.$apply(function() {\n        ctrl.removeChip(scope.$$replacedScope.$index);\n      });\n    });\n\n    // Child elements aren't available until after a $timeout tick as they are hidden by an\n    // `ng-if`. see http://goo.gl/zIWfuw\n    $timeout(function() {\n      element.attr({ 'tabindex': '-1', 'aria-hidden': 'true' });\n      element.find('button').attr('tabindex', '-1');\n    });\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMdChipTransclude.$inject = [\"$compile\"];angular\n    .module('material.components.chips')\n    .directive('mdChipTransclude', MdChipTransclude);\n\nfunction MdChipTransclude ($compile) {\n  return {\n    restrict: 'EA',\n    terminal: true,\n    link: link,\n    scope: false\n  };\n  function link (scope, element, attr) {\n    var ctrl = scope.$parent.$mdChipsCtrl,\n        newScope = ctrl.parent.$new(false, ctrl.parent);\n    newScope.$$replacedScope = scope;\n    newScope.$chip = scope.$chip;\n    newScope.$index = scope.$index;\n    newScope.$mdChipsCtrl = ctrl;\n\n    var newHtml = ctrl.$scope.$eval(attr.mdChipTransclude);\n\n    element.html(newHtml);\n    $compile(element.contents())(newScope);\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * The default chip append delay.\n *\n * @type {number}\n */\nMdChipsCtrl.$inject = [\"$scope\", \"$attrs\", \"$mdConstant\", \"$log\", \"$element\", \"$timeout\", \"$mdUtil\", \"$mdLiveAnnouncer\", \"$exceptionHandler\"];\nvar DEFAULT_CHIP_APPEND_DELAY = 300;\n\nangular\n    .module('material.components.chips')\n    .controller('MdChipsCtrl', MdChipsCtrl);\n\n/**\n * Controller for the MdChips component. Responsible for adding to and\n * removing from the list of chips, marking chips as selected, and binding to\n * the models of various input components.\n *\n * @param $scope\n * @param $attrs\n * @param $mdConstant\n * @param $log\n * @param $element\n * @param $timeout\n * @param $mdUtil\n * @param $mdLiveAnnouncer\n * @param $exceptionHandler\n * @constructor\n */\nfunction MdChipsCtrl ($scope, $attrs, $mdConstant, $log, $element, $timeout, $mdUtil,\n                      $mdLiveAnnouncer, $exceptionHandler) {\n  /** @type {Function} **/\n  this.$timeout = $timeout;\n\n  /** @type {Object} */\n  this.$mdConstant = $mdConstant;\n\n  /** @type {angular.$scope} */\n  this.$scope = $scope;\n\n  /** @type {angular.$scope} */\n  this.parent = $scope.$parent;\n\n  /** @type {$mdUtil} */\n  this.$mdUtil = $mdUtil;\n\n  /** @type {$log} */\n  this.$log = $log;\n\n  /** @type {$mdLiveAnnouncer} */\n  this.$mdLiveAnnouncer = $mdLiveAnnouncer;\n\n  /** @type {$exceptionHandler} */\n  this.$exceptionHandler = $exceptionHandler;\n\n  /** @type {$element} */\n  this.$element = $element;\n\n  /** @type {$attrs} */\n  this.$attrs = $attrs;\n\n  /** @type {angular.NgModelController} */\n  this.ngModelCtrl = null;\n\n  /** @type {angular.NgModelController} */\n  this.userInputNgModelCtrl = null;\n\n  /** @type {MdAutocompleteCtrl} */\n  this.autocompleteCtrl = null;\n\n  /** @type {Element} */\n  this.userInputElement = null;\n\n  /** @type {Array.<Object>} */\n  this.items = [];\n\n  /** @type {number} */\n  this.selectedChip = -1;\n\n  /** @type {string} */\n  this.enableChipEdit = $mdUtil.parseAttributeBoolean($attrs.mdEnableChipEdit);\n\n  /** @type {string} */\n  this.addOnBlur = $mdUtil.parseAttributeBoolean($attrs.mdAddOnBlur);\n\n  /**\n   * The class names to apply to the autocomplete or input.\n   * @type {string}\n   */\n  this.inputClass = '';\n\n  /**\n   * The text to be used as the aria-label for the input.\n   * @type {string}\n   */\n  this.inputAriaLabel = 'Chips input.';\n\n  /**\n   * Label text to describe the chips container. Used to give context and instructions to screen\n   * reader users when the chips container is selected.\n   * @type {string}\n   */\n  this.containerHint = 'Chips container. Use arrow keys to select chips.';\n\n  /**\n   * Label text to describe the chips container when it is empty. Used to give context and\n   * instructions to screen reader users when the chips container is selected and it contains\n   * no chips.\n   * @type {string}\n   */\n  this.containerEmptyHint =\n    'Chips container. Enter the text area, then type text, and press enter to add a chip.';\n\n  /**\n   * Hidden hint text for how to delete a chip. Used to give context to screen readers.\n   * @type {string}\n   */\n  this.deleteHint = 'Press delete to remove this chip.';\n\n  /**\n   * Hidden label for the delete button. Used to give context to screen readers.\n   * @type {string}\n   */\n  this.deleteButtonLabel = 'Remove';\n\n  /**\n   * Model used by the input element.\n   * @type {string}\n   */\n  this.chipBuffer = '';\n\n  /**\n   * Whether to use the transformChip expression to transform the chip buffer\n   * before appending it to the list.\n   * @type {boolean}\n   */\n  this.useTransformChip = false;\n\n  /**\n   * Whether to use the onAdd expression to notify of chip additions.\n   * @type {boolean}\n   */\n  this.useOnAdd = false;\n\n  /**\n   * Whether to use the onRemove expression to notify of chip removals.\n   * @type {boolean}\n   */\n  this.useOnRemove = false;\n\n  /**\n   * The ID of the chips wrapper which is used to build unique IDs for the chips and the aria-owns\n   * attribute.\n   *\n   * Defaults to '_md-chips-wrapper-' plus a unique number.\n   *\n   * @type {string}\n   */\n  this.wrapperId = '';\n\n  /**\n   * Array of unique numbers which will be auto-generated any time the items change, and is used to\n   * create unique IDs for the aria-owns attribute.\n   *\n   * @type {Array<number>}\n   */\n  this.contentIds = [];\n\n  /**\n   * The index of the chip that should have it's `tabindex` property set to `0` so it is selectable\n   * via the keyboard.\n   *\n   * @type {number|null}\n   */\n  this.ariaTabIndex = null;\n\n  /**\n   * After appending a chip, the chip will be focused for this number of milliseconds before the\n   * input is refocused.\n   *\n   * **Note:** This is **required** for compatibility with certain screen readers in order for\n   * them to properly allow keyboard access.\n   *\n   * @type {number}\n   */\n  this.chipAppendDelay = DEFAULT_CHIP_APPEND_DELAY;\n\n  /**\n   * Collection of functions to call to un-register watchers\n   *\n   * @type {Array}\n   */\n  this.deRegister = [];\n\n  /**\n   * The screen reader will announce the chip content followed by this message when a chip is added.\n   * @type {string}\n   */\n  this.addedMessage = 'added';\n\n  /**\n   * The screen reader will announce the chip content followed by this message when a chip is\n   * removed.\n   * @type {string}\n   */\n  this.removedMessage = 'removed';\n\n  this.init();\n}\n\n/**\n * Initializes variables and sets up watchers\n */\nMdChipsCtrl.prototype.init = function() {\n  var ctrl = this;\n\n  // Set the wrapper ID\n  this.wrapperId = '_md-chips-wrapper-' + this.$mdUtil.nextUid();\n\n  // If we're using static chips, then we need to initialize a few things.\n  if (!this.$element.attr('ng-model')) {\n    this.setupStaticChips();\n  }\n\n  // Setup a watcher which manages the role and aria-owns attributes.\n  // This is never called for static chips since items is not defined.\n  this.deRegister.push(\n    this.$scope.$watchCollection('$mdChipsCtrl.items', function() {\n      // Make sure our input and wrapper have the correct ARIA attributes\n      ctrl.setupInputAria();\n      ctrl.setupWrapperAria();\n    })\n  );\n\n  this.deRegister.push(\n    this.$attrs.$observe('mdChipAppendDelay', function(newValue) {\n      ctrl.chipAppendDelay = parseInt(newValue) || DEFAULT_CHIP_APPEND_DELAY;\n    })\n  );\n};\n\n/**\n * Destructor for cleanup\n */\nMdChipsCtrl.prototype.$onDestroy = function $onDestroy() {\n  var $destroyFn;\n  while (($destroyFn = this.deRegister.pop())) {\n    $destroyFn.call(this);\n  }\n};\n\n/**\n * If we have an input, ensure it has the appropriate ARIA attributes.\n */\nMdChipsCtrl.prototype.setupInputAria = function() {\n  var input = this.$element.find('input');\n\n  // If we have no input, just return\n  if (!input) {\n    return;\n  }\n\n  input.attr('role', 'textbox');\n  input.attr('aria-multiline', true);\n  if (this.inputAriaDescribedBy) {\n    input.attr('aria-describedby', this.inputAriaDescribedBy);\n  }\n  if (this.inputAriaLabelledBy) {\n    input.attr('aria-labelledby', this.inputAriaLabelledBy);\n    input.removeAttr('aria-label');\n  } else {\n    input.attr('aria-label', this.inputAriaLabel);\n  }\n};\n\n/**\n * Ensure our wrapper has the appropriate ARIA attributes.\n */\nMdChipsCtrl.prototype.setupWrapperAria = function() {\n  var ctrl = this,\n      wrapper = this.$element.find('md-chips-wrap');\n\n  if (this.items && this.items.length) {\n    // Dynamically add the listbox role on every change because it must be removed when there are\n    // no items.\n    wrapper.attr('role', 'listbox');\n\n    // Generate some random (but unique) IDs for each chip\n    this.contentIds = this.items.map(function() {\n      return ctrl.wrapperId + '-chip-' + ctrl.$mdUtil.nextUid();\n    });\n\n    // Use the contentIDs above to generate the aria-owns attribute\n    wrapper.attr('aria-owns', this.contentIds.join(' '));\n    wrapper.attr('aria-label', this.containerHint);\n  } else {\n    // If we have no items, then the role and aria-owns attributes MUST be removed\n    wrapper.removeAttr('role');\n    wrapper.removeAttr('aria-owns');\n    wrapper.attr('aria-label', this.containerEmptyHint);\n  }\n};\n\n/**\n * Apply specific roles and aria attributes for static chips\n */\nMdChipsCtrl.prototype.setupStaticChips = function() {\n  var ctrl = this, i, staticChips;\n  var wrapper = this.$element.find('md-chips-wrap');\n\n  this.$timeout(function() {\n    wrapper.attr('role', 'list');\n    staticChips = wrapper[0].children;\n    for (i = 0; i < staticChips.length; i++) {\n      staticChips[i].setAttribute('role', 'listitem');\n      staticChips[i].setAttribute('aria-setsize', staticChips.length);\n    }\n    if (ctrl.inputAriaDescribedBy) {\n      wrapper.attr('aria-describedby', ctrl.inputAriaDescribedBy);\n    }\n    if (ctrl.inputAriaLabelledBy) {\n      wrapper.attr('aria-labelledby', ctrl.inputAriaLabelledBy);\n      wrapper.removeAttr('aria-label');\n    } else {\n      wrapper.attr('aria-label', ctrl.inputAriaLabel);\n    }\n  }, 10);\n};\n\n/**\n * Handles the keydown event on the input element: by default <enter> appends\n * the buffer to the chip list, while backspace removes the last chip in the\n * list if the current buffer is empty.\n * @param {jQuery.Event|KeyboardEvent} event\n */\nMdChipsCtrl.prototype.inputKeydown = function(event) {\n  var chipBuffer = this.getChipBuffer();\n\n  // If we have an autocomplete, and it handled the event, we have nothing to do\n  if (this.autocompleteCtrl && event.isDefaultPrevented && event.isDefaultPrevented()) {\n    return;\n  }\n\n  if (event.keyCode === this.$mdConstant.KEY_CODE.BACKSPACE) {\n    // Only select and focus the previous chip, if the current caret position of the\n    // input element is at the beginning.\n    if (this.getCursorPosition(event.target) !== 0) {\n      return;\n    }\n\n    event.preventDefault();\n    event.stopPropagation();\n\n    if (this.items.length) {\n      this.selectAndFocusChipSafe(this.items.length - 1);\n    }\n\n    return;\n  }\n\n  // By default <enter> appends the buffer to the chip list.\n  if (!this.separatorKeys || this.separatorKeys.length < 1) {\n    this.separatorKeys = [this.$mdConstant.KEY_CODE.ENTER];\n  }\n\n  // Support additional separator key codes in an array of `md-separator-keys`.\n  if (this.separatorKeys.indexOf(event.keyCode) !== -1) {\n    if ((this.autocompleteCtrl && this.requireMatch) || !chipBuffer) return;\n    event.preventDefault();\n\n    // Only append the chip and reset the chip buffer if the max chips limit isn't reached.\n    if (this.hasMaxChipsReached()) return;\n\n    this.appendChip(chipBuffer.trim());\n    this.resetChipBuffer();\n\n    return false;\n  }\n};\n\n/**\n * Returns the cursor position of the specified input element.\n * @param {HTMLInputElement} element relevant input element\n * @returns {Number} Cursor Position of the input.\n */\nMdChipsCtrl.prototype.getCursorPosition = function(element) {\n  /*\n   * Figure out whether the current input for the chips buffer is valid for using\n   * the selectionStart / end property to retrieve the cursor position.\n   * Some browsers do not allow the use of those attributes, on different input types.\n   */\n  try {\n    if (element.selectionStart === element.selectionEnd) {\n      return element.selectionStart;\n    }\n  } catch (e) {\n    if (!element.value) {\n      return 0;\n    }\n  }\n};\n\n\n/**\n * Updates the content of the chip at given index\n * @param {number} chipIndex\n * @param {string} chipContents\n */\nMdChipsCtrl.prototype.updateChipContents = function(chipIndex, chipContents) {\n  if (chipIndex >= 0 && chipIndex < this.items.length) {\n    this.items[chipIndex] = chipContents;\n    this.updateNgModel(true);\n  }\n};\n\n\n/**\n * @return {boolean} true if a chip is currently being edited. False otherwise.\n */\nMdChipsCtrl.prototype.isEditingChip = function() {\n  return !!this.$element[0].querySelector('._md-chip-editing');\n};\n\n/**\n * @param {string|Object} chip contents of a single chip\n * @returns {boolean} true if the chip is an Object, false otherwise.\n * @private\n */\nMdChipsCtrl.prototype._isChipObject = function(chip) {\n  return angular.isObject(chip);\n};\n\n/**\n * @returns {boolean} true if chips can be removed, false otherwise.\n */\nMdChipsCtrl.prototype.isRemovable = function() {\n  // Return false if we have static chips\n  if (!this.ngModelCtrl) {\n    return false;\n  }\n\n  return this.readonly ? this.removable :\n         angular.isDefined(this.removable) ? this.removable : true;\n};\n\n/**\n * Handles the keydown event on the chip elements: backspace removes the selected chip, arrow\n * keys switch which chip is active.\n * @param {KeyboardEvent} event\n */\nMdChipsCtrl.prototype.chipKeydown = function (event) {\n  if (this.getChipBuffer()) return;\n  if (this.isEditingChip()) return;\n\n  switch (event.keyCode) {\n    case this.$mdConstant.KEY_CODE.BACKSPACE:\n    case this.$mdConstant.KEY_CODE.DELETE:\n      if (this.selectedChip < 0) return;\n      event.preventDefault();\n      // Cancel the delete action only after the event cancel. Otherwise the page will go back.\n      if (!this.isRemovable()) return;\n      this.removeAndSelectAdjacentChip(this.selectedChip, event);\n      break;\n    case this.$mdConstant.KEY_CODE.LEFT_ARROW:\n      event.preventDefault();\n      // By default, allow selection of -1 which will focus the input; if we're readonly, don't go\n      // below 0.\n      if (this.selectedChip < 0 || (this.readonly && this.selectedChip === 0)) {\n        this.selectedChip = this.items.length;\n      }\n      if (this.items.length) this.selectAndFocusChipSafe(this.selectedChip - 1);\n      break;\n    case this.$mdConstant.KEY_CODE.RIGHT_ARROW:\n      event.preventDefault();\n      this.selectAndFocusChipSafe(this.selectedChip + 1);\n      break;\n    case this.$mdConstant.KEY_CODE.ESCAPE:\n    case this.$mdConstant.KEY_CODE.TAB:\n      if (this.selectedChip < 0) return;\n      event.preventDefault();\n      this.onFocus();\n      break;\n  }\n};\n\n/**\n * Get the input's placeholder - uses `placeholder` when list is empty and `secondary-placeholder`\n * when the list is non-empty. If `secondary-placeholder` is not provided, `placeholder` is used\n * always.\n * @returns {string}\n */\nMdChipsCtrl.prototype.getPlaceholder = function() {\n  // Allow `secondary-placeholder` to be blank.\n  var useSecondary = (this.items && this.items.length &&\n      (this.secondaryPlaceholder === '' || this.secondaryPlaceholder));\n  return useSecondary ? this.secondaryPlaceholder : this.placeholder;\n};\n\n/**\n * Removes chip at {@code index} and selects the adjacent chip.\n * @param {number} index adjacent chip to select\n * @param {Event=} event\n */\nMdChipsCtrl.prototype.removeAndSelectAdjacentChip = function(index, event) {\n  var self = this;\n  var selIndex = self.getAdjacentChipIndex(index);\n  var wrap = this.$element[0].querySelector('md-chips-wrap');\n  var chip = this.$element[0].querySelector('md-chip[index=\"' + index + '\"]');\n\n  self.removeChip(index, event);\n\n  // The double-timeout is currently necessary to ensure that the DOM has finalized and the select()\n  // will find the proper chip since the selection is index-based.\n  //\n  // TODO: Investigate calling from within chip $scope.$on('$destroy') to reduce/remove timeouts\n  self.$timeout(function() {\n    self.$timeout(function() {\n      self.selectAndFocusChipSafe(selIndex);\n    });\n  });\n};\n\n/**\n * Sets the selected chip index to -1.\n */\nMdChipsCtrl.prototype.resetSelectedChip = function() {\n  this.selectedChip = -1;\n  this.ariaTabIndex = null;\n};\n\n/**\n * Gets the index of an adjacent chip to select after deletion. Adjacency is\n * determined as the next chip in the list, unless the target chip is the\n * last in the list, then it is the chip immediately preceding the target. If\n * there is only one item in the list, -1 is returned (select none).\n * The number returned is the index to select AFTER the target has been removed.\n * If the current chip is not selected, then -1 is returned to select none.\n * @param {number} index\n * @returns {number}\n */\nMdChipsCtrl.prototype.getAdjacentChipIndex = function(index) {\n  var len = this.items.length - 1;\n  return (len === 0) ? -1 :\n      (index === len) ? index - 1 : index;\n};\n\n/**\n * Append the contents of the buffer to the chip list. This method will first\n * call out to the md-transform-chip method, if provided.\n * @param {string} newChip chip buffer contents that will be used to create the new chip\n */\nMdChipsCtrl.prototype.appendChip = function(newChip) {\n  this.shouldFocusLastChip = !this.addOnBlur;\n  if (this.useTransformChip && this.transformChip) {\n    var transformedChip = this.transformChip({'$chip': newChip});\n\n    // Check to make sure the chip is defined before assigning it, otherwise, we'll just assume\n    // they want the string version.\n    if (angular.isDefined(transformedChip)) {\n      newChip = transformedChip;\n    }\n  }\n\n  // If items contains an identical object to newChip, do not append\n  if (angular.isObject(newChip)) {\n    var identical = this.items.some(function(item) {\n      return angular.equals(newChip, item);\n    });\n    if (identical) return;\n  }\n\n  // Check for a null (but not undefined), or existing chip and cancel appending\n  if (newChip == null || this.items.indexOf(newChip) + 1) return;\n\n  // Append the new chip onto our list\n  var length = this.items.push(newChip);\n  var index = length - 1;\n\n  this.updateNgModel();\n\n  // Tell screen reader users that the chip was successfully added.\n  // TODO add a way for developers to specify which field of the object should be announced here.\n  var chipContent = angular.isObject(newChip) ? '' : newChip;\n  this.$mdLiveAnnouncer.announce(chipContent + ' ' + this.addedMessage, 'assertive');\n\n  // If the md-on-add attribute is specified, send a chip addition event\n  if (this.useOnAdd && this.onAdd) {\n    this.onAdd({ '$chip': newChip, '$index': index });\n  }\n};\n\n/**\n * Sets whether to use the md-transform-chip expression. This expression is\n * bound to scope and controller in {@code MdChipsDirective} as\n * {@code transformChip}. Due to the nature of directive scope bindings, the\n * controller cannot know on its own/from the scope whether an expression was\n * actually provided.\n */\nMdChipsCtrl.prototype.useTransformChipExpression = function() {\n  this.useTransformChip = true;\n};\n\n/**\n * Sets whether to use the md-on-add expression. This expression is\n * bound to scope and controller in {@code MdChipsDirective} as\n * {@code onAdd}. Due to the nature of directive scope bindings, the\n * controller cannot know on its own/from the scope whether an expression was\n * actually provided.\n */\nMdChipsCtrl.prototype.useOnAddExpression = function() {\n  this.useOnAdd = true;\n};\n\n/**\n * Sets whether to use the md-on-remove expression. This expression is\n * bound to scope and controller in {@code MdChipsDirective} as\n * {@code onRemove}. Due to the nature of directive scope bindings, the\n * controller cannot know on its own/from the scope whether an expression was\n * actually provided.\n */\nMdChipsCtrl.prototype.useOnRemoveExpression = function() {\n  this.useOnRemove = true;\n};\n\n/**\n * Sets whether to use the md-on-select expression. This expression is\n * bound to scope and controller in {@code MdChipsDirective} as\n * {@code onSelect}. Due to the nature of directive scope bindings, the\n * controller cannot know on its own/from the scope whether an expression was\n * actually provided.\n */\nMdChipsCtrl.prototype.useOnSelectExpression = function() {\n  this.useOnSelect = true;\n};\n\n/**\n * Gets the input buffer. The input buffer can be the model bound to the\n * default input item {@code this.chipBuffer}, the {@code selectedItem}\n * model of an {@code md-autocomplete}, or, through some magic, the model\n * bound to any input or text area element found within a\n * {@code md-input-container} element.\n * @return {string} the input buffer\n */\nMdChipsCtrl.prototype.getChipBuffer = function() {\n  var chipBuffer =  !this.userInputElement ? this.chipBuffer :\n                     this.userInputNgModelCtrl ? this.userInputNgModelCtrl.$viewValue :\n                     this.userInputElement[0].value;\n\n  // Ensure that the chip buffer is always a string. For example, the input element buffer\n  // might be falsy.\n  return angular.isString(chipBuffer) ? chipBuffer : '';\n};\n\n/**\n * Resets the input buffer for either the internal input or user provided input element.\n */\nMdChipsCtrl.prototype.resetChipBuffer = function() {\n  if (this.userInputElement) {\n    if (this.userInputNgModelCtrl) {\n      this.userInputNgModelCtrl.$setViewValue('');\n      this.userInputNgModelCtrl.$render();\n    } else {\n      this.userInputElement[0].value = '';\n    }\n  } else {\n    this.chipBuffer = '';\n  }\n};\n\n/**\n * @returns {boolean} true if the max chips limit has been reached, false otherwise.\n */\nMdChipsCtrl.prototype.hasMaxChipsReached = function() {\n  if (angular.isString(this.maxChips)) {\n    this.maxChips = parseInt(this.maxChips, 10) || 0;\n  }\n\n  return this.maxChips > 0 && this.items.length >= this.maxChips;\n};\n\n/**\n * Updates the validity properties for the ngModel.\n *\n * TODO add the md-max-chips validator to this.ngModelCtrl.validators so that the validation will\n * be performed automatically.\n */\nMdChipsCtrl.prototype.validateModel = function() {\n  this.ngModelCtrl.$setValidity('md-max-chips', !this.hasMaxChipsReached());\n  this.ngModelCtrl.$validate(); // rerun any registered validators\n};\n\n/**\n * Function to handle updating the model, validation, and change notification when a chip\n * is added, removed, or changed.\n * @param {boolean=} skipValidation true to skip calling validateModel()\n */\nMdChipsCtrl.prototype.updateNgModel = function(skipValidation) {\n  if (!skipValidation) {\n    this.validateModel();\n  }\n  // This will trigger ng-change to fire, even in cases where $setViewValue() would not.\n  angular.forEach(this.ngModelCtrl.$viewChangeListeners, function(listener) {\n    try {\n      listener();\n    } catch (e) {\n      this.$exceptionHandler(e);\n    }\n  });\n};\n\n/**\n * Removes the chip at the given index.\n * @param {number} index of chip to remove\n * @param {Event=} event optionally passed to the onRemove callback\n */\nMdChipsCtrl.prototype.removeChip = function(index, event) {\n  var removed = this.items.splice(index, 1);\n\n  this.updateNgModel();\n  this.ngModelCtrl.$setDirty();\n\n  // Tell screen reader users that the chip was successfully removed.\n  // TODO add a way for developers to specify which field of the object should be announced here.\n  var chipContent = angular.isObject(removed[0]) ? '' : removed[0];\n  this.$mdLiveAnnouncer.announce(chipContent + ' ' + this.removedMessage, 'assertive');\n\n  if (removed && removed.length && this.useOnRemove && this.onRemove) {\n    this.onRemove({ '$chip': removed[0], '$index': index, '$event': event });\n  }\n};\n\n/**\n * @param {number} index location of chip to remove\n * @param {Event=} $event\n */\nMdChipsCtrl.prototype.removeChipAndFocusInput = function (index, $event) {\n  this.removeChip(index, $event);\n\n  if (this.autocompleteCtrl) {\n    // Always hide the autocomplete dropdown before focusing the autocomplete input.\n    // Wait for the input to move horizontally, because the chip was removed.\n    // This can lead to an incorrect dropdown position.\n    this.autocompleteCtrl.hidden = true;\n    this.$mdUtil.nextTick(this.onFocus.bind(this));\n  } else {\n    this.onFocus();\n  }\n\n};\n/**\n * Selects the chip at `index`,\n * @param {number} index location of chip to select and focus\n */\nMdChipsCtrl.prototype.selectAndFocusChipSafe = function(index) {\n  // If we have no chips, or are asked to select a chip before the first, just focus the input\n  if (!this.items.length || index === -1) {\n    return this.focusInput();\n  }\n\n  // If we are asked to select a chip greater than the number of chips...\n  if (index >= this.items.length) {\n    if (this.readonly) {\n      // If we are readonly, jump back to the start (because we have no input)\n      index = 0;\n    } else {\n      // If we are not readonly, we should attempt to focus the input\n      return this.onFocus();\n    }\n  }\n\n  index = Math.max(index, 0);\n  index = Math.min(index, this.items.length - 1);\n\n  this.selectChip(index);\n  this.focusChip(index);\n};\n\n/**\n * Focus last chip, then focus the input. This is needed for screen reader support.\n */\nMdChipsCtrl.prototype.focusLastChipThenInput = function() {\n  var ctrl = this;\n\n  ctrl.shouldFocusLastChip = false;\n\n  ctrl.focusChip(this.items.length - 1);\n\n  ctrl.$timeout(function() {\n    ctrl.focusInput();\n  }, ctrl.chipAppendDelay);\n};\n\n/**\n * Focus the input element.\n */\nMdChipsCtrl.prototype.focusInput = function() {\n  this.selectChip(-1);\n  this.onFocus();\n};\n\n/**\n * Marks the chip at the given index as selected.\n * @param {number} index location of chip to select\n */\nMdChipsCtrl.prototype.selectChip = function(index) {\n  if (index >= -1 && index <= this.items.length) {\n    this.selectedChip = index;\n\n    // Fire the onSelect if provided\n    if (this.useOnSelect && this.onSelect) {\n      this.onSelect({'$chip': this.items[index] });\n    }\n  } else {\n    this.$log.warn('Selected Chip index out of bounds; ignoring.');\n  }\n};\n\n/**\n * Call {@code focus()} on the chip at {@code index}\n * @param {number} index location of chip to focus\n */\nMdChipsCtrl.prototype.focusChip = function(index) {\n  var chipContent = this.$element[0].querySelector(\n    'md-chip[index=\"' + index + '\"] .md-chip-content'\n  );\n\n  this.ariaTabIndex = index;\n\n  chipContent.focus();\n};\n\n/**\n * Configures the required interactions with the ngModel Controller.\n * Specifically, set {@code this.items} to the {@code NgModelController#$viewValue}.\n * @param {NgModelController} ngModelCtrl\n */\nMdChipsCtrl.prototype.configureNgModel = function(ngModelCtrl) {\n  this.ngModelCtrl = ngModelCtrl;\n\n  var self = this;\n\n  // in chips the meaning of $isEmpty changes\n  ngModelCtrl.$isEmpty = function(value) {\n    return !value || value.length === 0;\n  };\n\n  ngModelCtrl.$render = function() {\n    // model is updated. do something.\n    self.items = self.ngModelCtrl.$viewValue;\n  };\n};\n\nMdChipsCtrl.prototype.onFocus = function () {\n  var input = this.$element[0].querySelector('input');\n  input && input.focus();\n  this.resetSelectedChip();\n};\n\nMdChipsCtrl.prototype.onInputFocus = function () {\n  this.inputHasFocus = true;\n\n  // Make sure we have the appropriate ARIA attributes\n  this.setupInputAria();\n\n  // Make sure we don't have any chips selected\n  this.resetSelectedChip();\n};\n\nMdChipsCtrl.prototype.onInputBlur = function () {\n  this.inputHasFocus = false;\n\n  if (this.shouldAddOnBlur()) {\n    this.appendChip(this.getChipBuffer().trim());\n    this.resetChipBuffer();\n  }\n};\n\n/**\n * Configure event bindings on input element.\n * @param {angular.element} inputElement\n */\nMdChipsCtrl.prototype.configureInput = function configureInput(inputElement) {\n  // Find the NgModelCtrl for the input element\n  var ngModelCtrl = inputElement.controller('ngModel');\n  var ctrl = this;\n\n  if (ngModelCtrl) {\n\n    // sync touched-state from inner input to chips-element\n    this.deRegister.push(\n      this.$scope.$watch(\n        function() {\n          return ngModelCtrl.$touched;\n        },\n        function(isTouched) {\n          isTouched && ctrl.ngModelCtrl.$setTouched();\n        }\n      )\n    );\n\n    // sync dirty-state from inner input to chips-element\n    this.deRegister.push(\n      this.$scope.$watch(\n        function() {\n          return ngModelCtrl.$dirty;\n        },\n        function(isDirty) {\n          isDirty && ctrl.ngModelCtrl.$setDirty();\n        }\n      )\n    );\n  }\n};\n\n/**\n * Configure event bindings on a user-provided input element.\n * @param {angular.element} inputElement\n */\nMdChipsCtrl.prototype.configureUserInput = function(inputElement) {\n  this.userInputElement = inputElement;\n\n  // Find the NgModelCtrl for the input element\n  var ngModelCtrl = inputElement.controller('ngModel');\n  // `.controller` will look in the parent as well.\n  if (ngModelCtrl !== this.ngModelCtrl) {\n    this.userInputNgModelCtrl = ngModelCtrl;\n  }\n\n  var scope = this.$scope;\n  var ctrl = this;\n\n  // Run all of the events using evalAsync because a focus may fire a blur in the same digest loop\n  var scopeApplyFn = function(event, fn) {\n    scope.$evalAsync(angular.bind(ctrl, fn, event));\n  };\n\n  // Bind to keydown and focus events of input\n  inputElement\n      .attr({ tabindex: 0 })\n      .on('keydown', function(event) { scopeApplyFn(event, ctrl.inputKeydown); })\n      .on('focus', function(event) { scopeApplyFn(event, ctrl.onInputFocus); })\n      .on('blur', function(event) { scopeApplyFn(event, ctrl.onInputBlur); });\n};\n\n/**\n * @param {MdAutocompleteCtrl} ctrl controller from the autocomplete component\n */\nMdChipsCtrl.prototype.configureAutocomplete = function(ctrl) {\n  if (ctrl) {\n    this.autocompleteCtrl = ctrl;\n    // Update the default container empty hint when we're inside of an autocomplete.\n    if (!this.$element.attr('container-empty-hint')) {\n      this.containerEmptyHint = 'Chips container with autocompletion. Enter the text area, ' +\n        'type text to search, and then use the up and down arrow keys to select an option. ' +\n        'Press enter to add the selected option as a chip.';\n      this.setupWrapperAria();\n    }\n\n    ctrl.registerSelectedItemWatcher(angular.bind(this, function (item) {\n      if (item) {\n        // Only append the chip and reset the chip buffer if the max chips limit isn't reached.\n        if (this.hasMaxChipsReached()) return;\n\n        this.appendChip(item);\n        this.resetChipBuffer();\n      }\n    }));\n\n    this.$element.find('input')\n        .on('focus',angular.bind(this, this.onInputFocus))\n        .on('blur', angular.bind(this, this.onInputBlur));\n  }\n};\n\n/**\n * @returns {boolean} Whether the current chip buffer should be added on input blur or not.\n */\nMdChipsCtrl.prototype.shouldAddOnBlur = function() {\n\n  // Update the custom ngModel validators from the chips component.\n  this.validateModel();\n\n  var chipBuffer = this.getChipBuffer().trim();\n  // If the model value is empty and required is set on the element, then the model will be invalid.\n  // In that case, we still want to allow adding the chip. The main (but not only) case we want\n  // to disallow is adding a chip on blur when md-max-chips validation fails.\n  var isModelValid = this.ngModelCtrl.$isEmpty(this.ngModelCtrl.$modelValue) ||\n    this.ngModelCtrl.$valid;\n  var isAutocompleteShowing = this.autocompleteCtrl && !this.autocompleteCtrl.hidden;\n\n  if (this.userInputNgModelCtrl) {\n    isModelValid = isModelValid && this.userInputNgModelCtrl.$valid;\n  }\n\n  return this.addOnBlur && !this.requireMatch && chipBuffer && isModelValid &&\n    !isAutocompleteShowing;\n};\n\n/**\n * @returns {boolean} true if the input or a chip is focused. False otherwise.\n */\nMdChipsCtrl.prototype.hasFocus = function () {\n  return this.inputHasFocus || this.selectedChip >= 0;\n};\n\n/**\n * @param {number} index location of content id\n * @returns {number} unique id for the aria-owns attribute\n */\nMdChipsCtrl.prototype.contentIdFor = function(index) {\n  return this.contentIds[index];\n};\n\n})();\n(function(){\n\"use strict\";\n\n  \n  MdChips.$inject = [\"$mdTheming\", \"$mdUtil\", \"$compile\", \"$log\", \"$timeout\", \"$$mdSvgRegistry\"];angular\n      .module('material.components.chips')\n      .directive('mdChips', MdChips);\n\n  /**\n   * @ngdoc directive\n   * @name mdChips\n   * @module material.components.chips\n   *\n   * @description\n   * `<md-chips>` is an input component for building lists of strings or objects. The list items are\n   * displayed as 'chips'. This component can make use of an `<input>` element or an\n   * `<md-autocomplete>` element.\n   *\n   * ### Custom templates\n   * A custom template may be provided to render the content of each chip. This is achieved by\n   * specifying an `<md-chip-template>` element containing the custom content as a child of\n   * `<md-chips>`.\n   *\n   * Note: Any attributes on\n   * `<md-chip-template>` will be dropped as only the innerHTML is used for the chip template. The\n   * variables `$chip` and `$index` are available in the scope of `<md-chip-template>`, representing\n   * the chip object and its index in the list of chips, respectively.\n   * To override the chip delete control, include an element (ideally a button) with the attribute\n   * `md-chip-remove`. A click listener to remove the chip will be added automatically. The element\n   * is also placed as a sibling to the chip content (on which there are also click listeners) to\n   * avoid a nested ng-click situation.\n   *\n   * <!-- Note: We no longer want to include this in the site docs; but it should remain here for\n   * future developers and those looking at the documentation.\n   *\n   * <h3> Pending Features </h3>\n   * <ul style=\"padding-left:20px;\">\n   *\n   *   <ul>Style\n   *     <li>Colors for hover, press states (ripple?).</li>\n   *   </ul>\n   *\n   *   <ul>Validation\n   *     <li>allow a validation callback</li>\n   *     <li>highlighting style for invalid chips</li>\n   *   </ul>\n   *\n   *   <ul>Item mutation\n   *     <li>Support `\n   *       <md-chip-edit>` template, show/hide the edit element on tap/click? double tap/double\n   *       click?\n   *     </li>\n   *   </ul>\n   *\n   *   <ul>Truncation and Disambiguation (?)\n   *     <li>Truncate chip text where possible, but do not truncate entries such that two are\n   *     indistinguishable.</li>\n   *   </ul>\n   *\n   *   <ul>Drag and Drop\n   *     <li>Drag and drop chips between related `<md-chips>` elements.\n   *     </li>\n   *   </ul>\n   * </ul>\n   *\n   * //-->\n   *\n   * Sometimes developers want to limit the amount of possible chips.<br/>\n   * You can specify the maximum amount of chips by using the following markup.\n   *\n   * <hljs lang=\"html\">\n   *   <md-chips\n   *       ng-model=\"myItems\"\n   *       placeholder=\"Add an item\"\n   *       md-max-chips=\"5\">\n   *   </md-chips>\n   * </hljs>\n   *\n   * In some cases, you have an autocomplete inside of the `md-chips`.<br/>\n   * When the maximum amount of chips has been reached, you can also disable the autocomplete\n   * selection.<br/>\n   * Here is an example markup.\n   *\n   * <hljs lang=\"html\">\n   *   <md-chips ng-model=\"myItems\" md-max-chips=\"5\">\n   *     <md-autocomplete ng-hide=\"myItems.length > 5\" ...></md-autocomplete>\n   *   </md-chips>\n   * </hljs>\n   *\n   * ### Accessibility\n   *\n   * The `md-chips` component supports keyboard and screen reader users since Version 1.1.2. In\n   * order to achieve this, we modified the chips behavior to select newly appended chips for\n   * `300ms` before re-focusing the input and allowing the user to type.\n   *\n   * For most users, this delay is small enough that it will not be noticeable but allows certain\n   * screen readers to function properly (JAWS and NVDA in particular).\n   *\n   * We introduced a new `md-chip-append-delay` option to allow developers to better control this\n   * behavior.\n   *\n   * Please refer to the documentation of this option (below) for more information.\n   *\n   * @param {expression} ng-model Assignable AngularJS expression to be data-bound to the list of\n   *    chips. The expression should evaluate to a `string` or `Object` Array. The type of this\n   *    array should align with the return value of `md-transform-chip`.\n   * @param {expression=} ng-change AngularJS expression to be executed on chip addition, removal,\n   *    or content change.\n   * @param {string=} placeholder Placeholder text that will be forwarded to the input.\n   * @param {string=} secondary-placeholder Placeholder text that will be forwarded to the input,\n   *    displayed when there is at least one item in the list\n   * @param {boolean=} md-removable Enables or disables the deletion of chips through the\n   *    removal icon or the Delete/Backspace key. Defaults to true.\n   * @param {boolean=} readonly Disables list manipulation (deleting or adding list items), hiding\n   *    the input and delete buttons. If no `ng-model` is provided, the chips will automatically be\n   *    marked as readonly.<br/><br/>\n   *    When `md-removable` is not defined, the `md-remove` behavior will be overwritten and\n   *    disabled.\n   * @param {boolean=} md-enable-chip-edit Set this to `\"true\"` to enable editing of chip contents.\n   *    The user can go into edit mode by pressing the `space` or `enter` keys, or by double\n   *    clicking on the chip. Chip editing is only supported for chips using the basic template.\n   *    **Note:** This attribute is only evaluated once; it is not watched.\n   * @param {boolean=} ng-required Whether ng-model is allowed to be empty or not.\n   * @param {number=} md-max-chips The maximum number of chips allowed to add through user input.\n   *    <br/><br/>The validation property `md-max-chips` can be used when the max chips\n   *    amount is reached.\n   * @param {boolean=} md-add-on-blur When set to `\"true\"`, the remaining text inside of the input\n   *    will be converted into a new chip on blur.\n   *    **Note:** This attribute is only evaluated once; it is not watched.\n   * @param {expression} md-transform-chip An expression of form `myFunction($chip)` that when\n   *    called expects one of the following return values:\n   *    - an object representing the `$chip` input string\n   *    - `undefined` to simply add the `$chip` input string, or\n   *    - `null` to prevent the chip from being appended\n   * @param {expression=} md-on-add An expression which will be called when a chip has been\n   *    added with `$chip` and `$index` available as parameters.\n   * @param {expression=} md-on-remove An expression which will be called when a chip has been\n   *    removed with `$chip`, `$index`, and `$event` available as parameters.\n   * @param {expression=} md-on-select An expression which will be called when a chip is selected.\n   * @param {boolean=} md-require-match If true, and the chips template contains an autocomplete,\n   *    only allow selection of pre-defined chips (i.e. you cannot add new ones).\n   * @param {string=} md-input-class This class will be applied to the child input for custom\n   *    styling. If you are using an `md-autocomplete`, then you need to put this attribute on the\n   *    `md-autocomplete` rather than the `md-chips`.\n   * @param {string=} input-aria-describedby A space-separated list of element IDs. This should\n   *     contain the IDs of any elements that describe this autocomplete. Screen readers will read\n   *     the content of these elements at the end of announcing that the chips input has been\n   *     selected and describing its current state. The descriptive elements do not need to be\n   *     visible on the page.\n   * @param {string=} input-aria-labelledby A space-separated list of element IDs. The ideal use\n   *    case is that this would contain the ID of a `<label>` element that is associated with these\n   *    chips.<br><br>\n   *    For `<label id=\"state\">US State</label>`, you would set this to\n   *    `input-aria-labelledby=\"state\"`.\n   * @param {string=} input-aria-label A string read by screen readers to identify the input.\n   *    For static chips, this will be applied to the chips container.\n   * @param {string=} container-hint A string read by screen readers informing users of how to\n   *    navigate the chips when there are chips. Only applies when `ng-model` is defined.\n   * @param {string=} container-empty-hint A string read by screen readers informing users of how to\n   *    add chips when there are no chips. You will want to use this to override the default when\n   *    in a non-English locale. Only applies when `ng-model` is defined.\n   * @param {string=} delete-hint A string read by screen readers instructing users that pressing\n   *    the delete key will remove the chip. You will want to use this to override the default when\n   *    in a non-English locale.\n   * @param {string=} delete-button-label Text for the `aria-label` of the button with the\n   *    `md-chip-remove` class. If the chip is an Object, then this will be the only text in the\n   *    label. Otherwise, this is prepended to the string representation of the chip. Defaults to\n   *    \"Remove\", which would be \"Remove Apple\" for a chip that contained the string \"Apple\".\n   *    You will want to use this to override the default when in a non-English locale.\n   * @param {string=} md-removed-message Screen readers will announce this message following the\n   *    chips contents. The default is `\"removed\"`. If a chip with the content of \"Apple\" was\n   *    removed, the screen reader would read \"Apple removed\". You will want to use this to override\n   *    the default when in a non-English locale.\n   * @param {string=} md-added-message Screen readers will announce this message following the\n   *    chips contents. The default is `\"added\"`. If a chip with the content of \"Apple\" was\n   *    created, the screen reader would read \"Apple added\". You will want to use this to override\n   *    the default when in a non-English locale.\n   * @param {expression=} md-separator-keys An array of key codes used to separate chips.\n   * @param {string=} md-chip-append-delay The number of milliseconds that the component will select\n   *    a newly appended chip before allowing a user to type into the input. This is **necessary**\n   *    for keyboard accessibility for screen readers. It defaults to 300ms and any number less than\n   *    300 can cause issues with screen readers (particularly JAWS and sometimes NVDA).\n   *\n   *    _Available since Version 1.1.2._\n   *\n   *    **Note:** You can safely set this to `0` in one of the following two instances:\n   *\n   *    1. You are targeting an iOS or Safari-only application (where users would use VoiceOver) or\n   *    only ChromeVox users.\n   *\n   *    2. If you have utilized the `md-separator-keys` to disable the `enter` keystroke in\n   *    favor of another one (such as `,` or `;`).\n   *\n   * @usage\n   * <hljs lang=\"html\">\n   *   <md-chips\n   *       ng-model=\"myItems\"\n   *       placeholder=\"Add an item\"\n   *       readonly=\"isReadOnly\">\n   *   </md-chips>\n   * </hljs>\n   *\n   * <h3>Validation</h3>\n   * When using [ngMessages](https://docs.angularjs.org/api/ngMessages), you can show errors based\n   * on our custom validators.\n   * <hljs lang=\"html\">\n   *   <form name=\"userForm\">\n   *     <md-chips\n   *       name=\"fruits\"\n   *       ng-model=\"myItems\"\n   *       placeholder=\"Add an item\"\n   *       md-max-chips=\"5\">\n   *     </md-chips>\n   *     <div ng-messages=\"userForm.fruits.$error\" ng-if=\"userForm.$dirty\">\n   *       <div ng-message=\"md-max-chips\">You reached the maximum amount of chips</div>\n   *    </div>\n   *   </form>\n   * </hljs>\n   *\n   */\n\n  // TODO add a way for developers to specify which field of the object should used in the\n  // aria-label.\n  var MD_CHIPS_TEMPLATE = '\\\n      <md-chips-wrap\\\n          id=\"{{$mdChipsCtrl.wrapperId}}\"\\\n          tabindex=\"{{$mdChipsCtrl.readonly ? 0 : -1}}\"\\\n          ng-keydown=\"$mdChipsCtrl.chipKeydown($event)\"\\\n          ng-class=\"{ \\'md-focused\\': $mdChipsCtrl.hasFocus(), \\\n                      \\'md-readonly\\': !$mdChipsCtrl.ngModelCtrl || $mdChipsCtrl.readonly,\\\n                      \\'md-removable\\': $mdChipsCtrl.isRemovable() }\"\\\n          class=\"md-chips\">\\\n        <md-chip ng-repeat=\"$chip in $mdChipsCtrl.items\"\\\n            index=\"{{$index}}\" \\\n            ng-class=\"{\\'md-focused\\': $mdChipsCtrl.selectedChip == $index, \\'md-readonly\\': !$mdChipsCtrl.ngModelCtrl || $mdChipsCtrl.readonly}\">\\\n          <div class=\"md-chip-content\"\\\n              tabindex=\"{{$mdChipsCtrl.ariaTabIndex === $index ? 0 : -1}}\"\\\n              id=\"{{$mdChipsCtrl.contentIdFor($index)}}\"\\\n              role=\"option\"\\\n              aria-selected=\"{{$mdChipsCtrl.selectedChip === $index}}\"\\\n              aria-setsize=\"{{$mdChipsCtrl.items.length}}\"\\\n              aria-posinset=\"{{$index+1}}\"\\\n              ng-click=\"!$mdChipsCtrl.readonly && $mdChipsCtrl.focusChip($index)\"\\\n              aria-label=\"{{$mdChipsCtrl._isChipObject($chip) ? \\'\\' : $chip + \\'. \\'}}{{$mdChipsCtrl.isRemovable() ? \\'\\' + $mdChipsCtrl.deleteHint : \\'\\'}}\" \\\n              ng-focus=\"!$mdChipsCtrl.readonly && $mdChipsCtrl.selectChip($index)\"\\\n              md-chip-transclude=\"$mdChipsCtrl.chipContentsTemplate\"></div>\\\n          <div ng-if=\"$mdChipsCtrl.isRemovable()\"\\\n               class=\"md-chip-remove-container\"\\\n               tabindex=\"-1\"\\\n               md-chip-transclude=\"$mdChipsCtrl.chipRemoveTemplate\"></div>\\\n        </md-chip>\\\n        <div class=\"md-chip-input-container\" ng-if=\"!$mdChipsCtrl.readonly && $mdChipsCtrl.ngModelCtrl\">\\\n          <div md-chip-transclude=\"$mdChipsCtrl.chipInputTemplate\"></div>\\\n        </div>\\\n      </md-chips-wrap>';\n\n  var CHIP_INPUT_TEMPLATE = '\\\n        <input\\\n            class=\"md-input{{ $mdChipsCtrl.inputClass ? \\' \\' + $mdChipsCtrl.inputClass: \\'\\'}}\"\\\n            tabindex=\"0\"\\\n            aria-label=\"{{$mdChipsCtrl.inputAriaLabel}}\"\\\n            placeholder=\"{{$mdChipsCtrl.getPlaceholder()}}\"\\\n            ng-model=\"$mdChipsCtrl.chipBuffer\"\\\n            ng-focus=\"$mdChipsCtrl.onInputFocus()\"\\\n            ng-blur=\"$mdChipsCtrl.onInputBlur()\"\\\n            ng-keydown=\"$mdChipsCtrl.inputKeydown($event)\">';\n\n  var CHIP_DEFAULT_TEMPLATE = '\\\n      <span>{{$chip}}</span>';\n\n  var CHIP_REMOVE_TEMPLATE = '\\\n      <button\\\n          class=\"md-chip-remove\"\\\n          ng-if=\"$mdChipsCtrl.isRemovable()\"\\\n          ng-click=\"$mdChipsCtrl.removeChipAndFocusInput($$replacedScope.$index, $event)\"\\\n          type=\"button\"\\\n          tabindex=\"-1\"\\\n          aria-label=\"{{$mdChipsCtrl.deleteButtonLabel}}{{$mdChipsCtrl._isChipObject($chip) ? \\'\\' : \\' \\' + $chip}}\">\\\n        <md-icon md-svg-src=\"{{$mdChipsCtrl.mdCloseIcon}}\" aria-hidden=\"true\"></md-icon>\\\n      </button>';\n\n  /**\n   * MDChips Directive Definition\n   */\n  function MdChips ($mdTheming, $mdUtil, $compile, $log, $timeout, $$mdSvgRegistry) {\n    // Run our templates through $mdUtil.processTemplate() to allow custom start/end symbols\n    var templates = getTemplates();\n\n    return {\n      template: function(element, attrs) {\n        // Clone the element into an attribute. By prepending the attribute\n        // name with '$', AngularJS won't write it into the DOM. The cloned\n        // element propagates to the link function via the attrs argument,\n        // where various contained-elements can be consumed.\n        attrs['$mdUserTemplate'] = element.clone();\n        return templates.chips;\n      },\n      require: ['mdChips'],\n      restrict: 'E',\n      controller: 'MdChipsCtrl',\n      controllerAs: '$mdChipsCtrl',\n      bindToController: true,\n      compile: compile,\n      scope: {\n        readonly: '=?readonly',\n        removable: '=?mdRemovable',\n        placeholder: '@?',\n        secondaryPlaceholder: '@?',\n        maxChips: '@?mdMaxChips',\n        transformChip: '&mdTransformChip',\n        onAdd: '&?mdOnAdd',\n        onRemove: '&?mdOnRemove',\n        addedMessage: '@?mdAddedMessage',\n        removedMessage: '@?mdRemovedMessage',\n        onSelect: '&?mdOnSelect',\n        inputClass: '@?mdInputClass',\n        inputAriaDescribedBy: '@?inputAriaDescribedby',\n        inputAriaLabelledBy: '@?inputAriaLabelledby',\n        inputAriaLabel: '@?',\n        containerHint: '@?',\n        containerEmptyHint: '@?',\n        deleteHint: '@?',\n        deleteButtonLabel: '@?',\n        separatorKeys: '=?mdSeparatorKeys',\n        requireMatch: '=?mdRequireMatch',\n        chipAppendDelayString: '@?mdChipAppendDelay',\n        ngChange: '&?'\n      }\n    };\n\n    /**\n     * Builds the final template for `md-chips` and returns the postLink function.\n     *\n     * Building the template involves 3 key components:\n     * static chips\n     * chip template\n     * input control\n     *\n     * If no `ng-model` is provided, only the static chip work needs to be done.\n     *\n     * If no user-passed `md-chip-template` exists, the default template is used. This resulting\n     * template is appended to the chip content element.\n     *\n     * The remove button may be overridden by passing an element with an md-chip-remove attribute.\n     *\n     * If an `input` or `md-autocomplete` element is provided by the caller, it is set aside for\n     * transclusion later. The transclusion happens in `postLink` as the parent scope is required.\n     * If no user input is provided, a default one is appended to the input container node in the\n     * template.\n     *\n     * Static Chips (i.e. `md-chip` elements passed from the caller) are gathered and set aside for\n     * transclusion in the `postLink` function.\n     *\n     *\n     * @param element\n     * @param attr\n     * @returns {Function}\n     */\n    function compile(element, attr) {\n      // Grab the user template from attr and reset the attribute to null.\n      var userTemplate = attr['$mdUserTemplate'];\n      attr['$mdUserTemplate'] = null;\n\n      var chipTemplate = getTemplateByQuery('md-chips>md-chip-template');\n\n      var chipRemoveSelector = $mdUtil\n        .prefixer()\n        .buildList('md-chip-remove')\n        .map(function(attr) {\n          return 'md-chips>*[' + attr + ']';\n        })\n        .join(',');\n\n      // Set the chip remove, chip contents and chip input templates. The link function will put\n      // them on the scope for transclusion later.\n      var chipRemoveTemplate   = getTemplateByQuery(chipRemoveSelector) || templates.remove,\n          chipContentsTemplate = chipTemplate || templates.default,\n          chipInputTemplate    = getTemplateByQuery('md-chips>md-autocomplete')\n              || getTemplateByQuery('md-chips>input')\n              || templates.input,\n          staticChips = userTemplate.find('md-chip');\n\n      // Warn of malformed template. See #2545\n      if (userTemplate[0].querySelector('md-chip-template>*[md-chip-remove]')) {\n        $log.warn('invalid placement of md-chip-remove within md-chip-template.');\n      }\n\n      function getTemplateByQuery (query) {\n        if (!attr.ngModel) return;\n        var element = userTemplate[0].querySelector(query);\n        return element && element.outerHTML;\n      }\n\n      /**\n       * Configures controller and transcludes.\n       */\n      return function postLink(scope, element, attrs, controllers) {\n        $mdUtil.initOptionalProperties(scope, attr);\n\n        $mdTheming(element);\n        var mdChipsCtrl = controllers[0];\n        if (chipTemplate) {\n          // Chip editing functionality assumes we are using the default chip template.\n          mdChipsCtrl.enableChipEdit = false;\n        }\n\n        mdChipsCtrl.chipContentsTemplate = chipContentsTemplate;\n        mdChipsCtrl.chipRemoveTemplate   = chipRemoveTemplate;\n        mdChipsCtrl.chipInputTemplate    = chipInputTemplate;\n\n        mdChipsCtrl.mdCloseIcon = $$mdSvgRegistry.mdCancel;\n\n        element\n            .attr({ tabindex: -1 })\n            .on('focus', function () { mdChipsCtrl.onFocus(); })\n            .on('click', function () {\n              if (!mdChipsCtrl.readonly && mdChipsCtrl.selectedChip === -1) {\n                mdChipsCtrl.onFocus();\n              }\n            });\n\n        if (attr.ngModel) {\n          mdChipsCtrl.configureNgModel(element.controller('ngModel'));\n\n          // If an `md-transform-chip` attribute was set, tell the controller to use the expression\n          // before appending chips.\n          if (attrs.mdTransformChip) mdChipsCtrl.useTransformChipExpression();\n\n          // If an `md-on-add` attribute was set, tell the controller to use the expression\n          // when adding chips.\n          if (attrs.mdOnAdd) mdChipsCtrl.useOnAddExpression();\n\n          // If an `md-on-remove` attribute was set, tell the controller to use the expression\n          // when removing chips.\n          if (attrs.mdOnRemove) mdChipsCtrl.useOnRemoveExpression();\n\n          // If an `md-on-select` attribute was set, tell the controller to use the expression\n          // when selecting chips.\n          if (attrs.mdOnSelect) mdChipsCtrl.useOnSelectExpression();\n\n          // The md-autocomplete and input elements won't be compiled until after this directive\n          // is complete (due to their nested nature). Wait a tick before looking for them to\n          // configure the controller.\n          if (chipInputTemplate !== templates.input) {\n            // The autocomplete will not appear until the readonly attribute is not true (i.e.\n            // false or undefined), so we have to watch the readonly and then on the next tick\n            // after the chip transclusion has run, we can configure the autocomplete and user\n            // input.\n            scope.$watch('$mdChipsCtrl.readonly', function(readonly) {\n              if (!readonly) {\n\n                $mdUtil.nextTick(function(){\n\n                  if (chipInputTemplate.indexOf('<md-autocomplete') === 0) {\n                    var autocompleteEl = element.find('md-autocomplete');\n                    mdChipsCtrl.configureAutocomplete(autocompleteEl.controller('mdAutocomplete'));\n                  }\n\n                  mdChipsCtrl.configureUserInput(element.find('input'));\n                });\n              }\n            });\n          }\n\n          // At the next tick, if we find an input, make sure it has the md-input class\n          $mdUtil.nextTick(function() {\n            var input = element.find('input');\n\n            if (input) {\n              mdChipsCtrl.configureInput(input);\n              input.toggleClass('md-input', true);\n            }\n          });\n        }\n\n        // Compile with the parent's scope and prepend any static chips to the wrapper.\n        if (staticChips.length > 0) {\n          var compiledStaticChips = $compile(staticChips.clone())(scope.$parent);\n          $timeout(function() { element.find('md-chips-wrap').prepend(compiledStaticChips); });\n        }\n      };\n    }\n\n    function getTemplates() {\n      return {\n        chips: $mdUtil.processTemplate(MD_CHIPS_TEMPLATE),\n        input: $mdUtil.processTemplate(CHIP_INPUT_TEMPLATE),\n        default: $mdUtil.processTemplate(CHIP_DEFAULT_TEMPLATE),\n        remove: $mdUtil.processTemplate(CHIP_REMOVE_TEMPLATE)\n      };\n    }\n  }\n\n})();\n(function(){\n\"use strict\";\n\n\nMdContactChipsCtrl.$inject = [\"$attrs\", \"$element\", \"$timeout\"];angular\n    .module('material.components.chips')\n    .controller('MdContactChipsCtrl', MdContactChipsCtrl);\n\n/**\n * Controller for the MdContactChips component\n * @constructor\n */\nfunction MdContactChipsCtrl ($attrs, $element, $timeout) {\n  /** @type {$element} */\n  this.$element = $element;\n\n  /** @type {$attrs} */\n  this.$attrs = $attrs;\n\n  /** @type {Function} */\n  this.$timeout = $timeout;\n\n  /** @type {Object} */\n  this.selectedItem = null;\n\n  /** @type {string} */\n  this.searchText = '';\n\n  /**\n   * Collection of functions to call to un-register watchers\n   * @type {Array}\n   */\n  this.deRegister = [];\n\n  this.init();\n}\n\nMdContactChipsCtrl.prototype.init = function() {\n  var ctrl = this;\n  var deRegister = this.deRegister;\n  var element = this.$element;\n\n  // Setup a watcher which manages chips a11y messages and autocomplete aria.\n  // Timeout required to allow the child elements to be compiled.\n  this.$timeout(function() {\n    deRegister.push(\n      element.find('md-chips').controller('mdChips').$scope.$watchCollection('$mdChipsCtrl.items', function() {\n        // Make sure our input and wrapper have the correct ARIA attributes\n        ctrl.setupChipsAria();\n        ctrl.setupAutocompleteAria();\n      })\n    );\n  });\n};\n\nMdContactChipsCtrl.prototype.setupChipsAria = function() {\n  var chips = this.$element.find('md-chips');\n  var chipsCtrl = chips.controller('mdChips');\n\n  // Configure MdChipsCtrl\n  if (this.removedMessage) {\n    chipsCtrl.removedMessage = this.removedMessage;\n  }\n  if (this.containerHint) {\n    chipsCtrl.containerHint = this.containerHint;\n  }\n  if (this.containerEmptyHint) {\n    // Apply attribute to avoid the hint being overridden by MdChipsCtrl.configureAutocomplete()\n    chips.attr('container-empty-hint', this.containerEmptyHint);\n    chipsCtrl.containerEmptyHint = this.containerEmptyHint;\n  }\n  if (this.deleteHint) {\n    chipsCtrl.deleteHint = this.deleteHint;\n  }\n  if (this.inputAriaLabel) {\n    chipsCtrl.inputAriaLabel = this.inputAriaLabel;\n  }\n  if (this.inputClass) {\n    chipsCtrl.inputClass = this.inputClass;\n  }\n};\n\nMdContactChipsCtrl.prototype.setupAutocompleteAria = function() {\n  var autocompleteInput = this.$element.find('md-chips-wrap').find('md-autocomplete').find('input');\n\n  // Set attributes on the input of the md-autocomplete\n  if (this.inputAriaDescribedBy) {\n    autocompleteInput.attr('aria-describedby', this.inputAriaDescribedBy);\n  }\n  if (this.inputAriaLabelledBy) {\n    autocompleteInput.removeAttr('aria-label');\n    autocompleteInput.attr('aria-labelledby', this.inputAriaLabelledBy);\n  }\n};\n\nMdContactChipsCtrl.prototype.queryContact = function(searchText) {\n  return this.contactQuery({'$query': searchText});\n};\n\nMdContactChipsCtrl.prototype.inputKeydown = function(event) {\n  if (!this.separatorKeys || this.separatorKeys.indexOf(event.keyCode) < 0) {\n    return;\n  }\n\n  event.stopPropagation();\n  event.preventDefault();\n\n  var autocompleteCtrl = angular.element(event.target).controller('mdAutocomplete');\n  autocompleteCtrl.select(autocompleteCtrl.index);\n};\n\nMdContactChipsCtrl.prototype.itemName = function(item) {\n  return item[this.contactName];\n};\n\n/**\n * Destructor for cleanup\n */\nMdContactChipsCtrl.prototype.$onDestroy = function $onDestroy() {\n  var $destroyFn;\n  while (($destroyFn = this.deRegister.pop())) {\n    $destroyFn.call(this);\n  }\n};\n\n})();\n(function(){\n\"use strict\";\n\n\nMdContactChips.$inject = [\"$mdTheming\", \"$mdUtil\"];angular\n  .module('material.components.chips')\n  .directive('mdContactChips', MdContactChips);\n\n/**\n * @ngdoc directive\n * @name mdContactChips\n * @module material.components.chips\n *\n * @description\n * `<md-contact-chips>` is an input component based on `md-chips` and makes use of an\n * `md-autocomplete` element. The component allows the caller to supply a query expression which\n * returns  a list of possible contacts. The user can select one of these and add it to the list of\n * chips.\n *\n * You may also use the <a ng-href=\"api/directive/mdHighlightText\">md-highlight-flags</a> attribute\n * along with its parameters to control the appearance of the matched text inside of the contacts'\n * autocomplete popup.\n *\n * @param {expression} ng-model Assignable AngularJS expression to be data-bound to the list of\n *    contact chips. The expression should evaluate to an `Object` Array.\n * @param {expression=} ng-change AngularJS expression to be executed on chip addition, removal,\n *    or content change.\n * @param {string=} placeholder Placeholder text that will be forwarded to the input.\n * @param {string=} secondary-placeholder Placeholder text that will be forwarded to the input,\n *    displayed when there is at least on item in the list\n * @param {expression} md-contacts An expression expected to return contacts matching the search\n *    test, `$query`. If this expression involves a promise, a loading bar is displayed while\n *    waiting for it to resolve.\n * @param {string} md-contact-name The field name of the contact object representing the\n *    contact's name.\n * @param {string} md-contact-email The field name of the contact object representing the\n *    contact's email address.\n * @param {string} md-contact-image The field name of the contact object representing the\n *    contact's image.\n * @param {number=} md-max-chips The maximum number of chips allowed to add through user input.\n *    <br/><br/>The validation property `md-max-chips` can be used when the max chips\n *    amount is reached.\n * @param {number=} md-min-length Specifies the minimum length of text before autocomplete will\n *    make suggestions\n * @param {string=} md-input-class This class will be applied to the child `md-autocomplete` for\n *    custom styling.\n * @param {string=} input-aria-describedby A space-separated list of element IDs. This should\n *     contain the IDs of any elements that describe this autocomplete. Screen readers will read\n *     the content of these elements at the end of announcing that the chips input has been\n *     selected and describing its current state. The descriptive elements do not need to be\n *     visible on the page.\n * @param {string=} input-aria-labelledby A space-separated list of element IDs. The ideal use\n *    case is that this would contain the ID of a `<label>` element that is associated with these\n *    chips.<br><br>\n *    For `<label id=\"state\">US State</label>`, you would set this to\n *    `input-aria-labelledby=\"state\"`.\n * @param {string=} input-aria-label A string read by screen readers to identify the input.\n *    For static chips, this will be applied to the chips container.\n * @param {string=} container-hint A string read by screen readers informing users of how to\n *    navigate the chips when there are chips.\n * @param {string=} container-empty-hint A string read by screen readers informing users of how to\n *    add chips when there are no chips. You will want to use this to override the default when\n *    in a non-English locale.\n * @param {string=} delete-hint A string read by screen readers instructing users that pressing\n *    the delete key will remove the chip. You will want to use this to override the default when\n *    in a non-English locale.\n * @param {string=} md-removed-message Screen readers will announce this message following the\n *    chips contents. The default is `\"removed\"`. If a chip with the content of \"Apple\" was\n *    removed, the screen reader would read \"Apple removed\". You will want to use this to override\n *    the default when in a non-English locale.\n *\n *\n * @usage\n * <hljs lang=\"html\">\n *   <md-contact-chips\n *       ng-model=\"ctrl.contacts\"\n *       md-contacts=\"ctrl.querySearch($query)\"\n *       md-contact-name=\"name\"\n *       md-contact-image=\"image\"\n *       md-contact-email=\"email\"\n *       placeholder=\"To\">\n *   </md-contact-chips>\n * </hljs>\n *\n */\n\n\nvar MD_CONTACT_CHIPS_TEMPLATE = '\\\n      <md-chips class=\"md-contact-chips\"\\\n          ng-model=\"$mdContactChipsCtrl.contacts\"\\\n          ng-change=\"$mdContactChipsCtrl.ngChange($mdContactChipsCtrl.contacts)\"\\\n          md-require-match=\"$mdContactChipsCtrl.requireMatch\"\\\n          md-max-chips=\"{{$mdContactChipsCtrl.maxChips}}\"\\\n          md-chip-append-delay=\"{{$mdContactChipsCtrl.chipAppendDelay}}\"\\\n          md-separator-keys=\"$mdContactChipsCtrl.separatorKeys\"\\\n          md-autocomplete-snap>\\\n          <md-autocomplete\\\n              md-menu-class=\"md-contact-chips-suggestions\"\\\n              md-selected-item=\"$mdContactChipsCtrl.selectedItem\"\\\n              md-search-text=\"$mdContactChipsCtrl.searchText\"\\\n              md-items=\"item in $mdContactChipsCtrl.queryContact($mdContactChipsCtrl.searchText)\"\\\n              md-item-text=\"$mdContactChipsCtrl.itemName(item)\"\\\n              md-no-cache=\"true\"\\\n              md-min-length=\"$mdContactChipsCtrl.minLength\"\\\n              md-autoselect\\\n              ng-attr-md-input-class=\"{{$mdContactChipsCtrl.inputClass}}\"\\\n              ng-keydown=\"$mdContactChipsCtrl.inputKeydown($event)\"\\\n              placeholder=\"{{$mdContactChipsCtrl.contacts.length === 0 ?\\\n                  $mdContactChipsCtrl.placeholder : $mdContactChipsCtrl.secondaryPlaceholder}}\">\\\n            <div class=\"md-contact-suggestion\">\\\n              <img \\\n                  ng-src=\"{{item[$mdContactChipsCtrl.contactImage]}}\"\\\n                  alt=\"{{item[$mdContactChipsCtrl.contactName]}}\"\\\n                  ng-if=\"item[$mdContactChipsCtrl.contactImage]\" />\\\n              <span class=\"md-contact-name\" md-highlight-text=\"$mdContactChipsCtrl.searchText\"\\\n                    md-highlight-flags=\"{{$mdContactChipsCtrl.highlightFlags}}\">\\\n                {{item[$mdContactChipsCtrl.contactName]}}\\\n              </span>\\\n              <span class=\"md-contact-email\" >{{item[$mdContactChipsCtrl.contactEmail]}}</span>\\\n            </div>\\\n          </md-autocomplete>\\\n          <md-chip-template>\\\n            <div class=\"md-contact-avatar\">\\\n              <img \\\n                  ng-src=\"{{$chip[$mdContactChipsCtrl.contactImage]}}\"\\\n                  alt=\"{{$chip[$mdContactChipsCtrl.contactName]}}\"\\\n                  ng-if=\"$chip[$mdContactChipsCtrl.contactImage]\" />\\\n            </div>\\\n            <div class=\"md-contact-name\">\\\n              {{$chip[$mdContactChipsCtrl.contactName]}}\\\n            </div>\\\n          </md-chip-template>\\\n      </md-chips>';\n\n\n/**\n * MDContactChips Directive Definition\n *\n * @param $mdTheming\n * @param $mdUtil\n * @returns {*}\n * @ngInject\n */\nfunction MdContactChips($mdTheming, $mdUtil) {\n  return {\n    template: function(element, attrs) {\n      return MD_CONTACT_CHIPS_TEMPLATE;\n    },\n    restrict: 'E',\n    controller: 'MdContactChipsCtrl',\n    controllerAs: '$mdContactChipsCtrl',\n    bindToController: true,\n    compile: compile,\n    scope: {\n      contactQuery: '&mdContacts',\n      placeholder: '@?',\n      secondaryPlaceholder: '@?',\n      contactName: '@mdContactName',\n      contactImage: '@mdContactImage',\n      contactEmail: '@mdContactEmail',\n      contacts: '=ngModel',\n      ngChange: '&?',\n      requireMatch: '=?mdRequireMatch',\n      minLength: '=?mdMinLength',\n      maxChips: '=?mdMaxChips',\n      highlightFlags: '@?mdHighlightFlags',\n      chipAppendDelay: '@?mdChipAppendDelay',\n      separatorKeys: '=?mdSeparatorKeys',\n      removedMessage: '@?mdRemovedMessage',\n      inputClass: '@?mdInputClass',\n      inputAriaDescribedBy: '@?inputAriaDescribedby',\n      inputAriaLabelledBy: '@?inputAriaLabelledby',\n      inputAriaLabel: '@?',\n      containerHint: '@?',\n      containerEmptyHint: '@?',\n      deleteHint: '@?'\n    }\n  };\n\n  function compile(element, attr) {\n    return function postLink(scope, element, attrs, controllers) {\n      var contactChipsController = controllers;\n\n      $mdUtil.initOptionalProperties(scope, attr);\n      $mdTheming(element);\n\n      element.attr('tabindex', '-1');\n\n      attrs.$observe('mdChipAppendDelay', function(newValue) {\n        contactChipsController.chipAppendDelay = newValue;\n      });\n    };\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n(function () {\n  \"use strict\";\n\n  /**\n   *  Use a RegExp to check if the `md-colors=\"<expression>\"` is static string\n   *  or one that should be observed and dynamically interpolated.\n   */\n  MdColorsDirective.$inject = [\"$mdColors\", \"$mdUtil\", \"$log\", \"$parse\"];\n  MdColorsService.$inject = [\"$mdTheming\", \"$mdUtil\", \"$log\"];\n  var STATIC_COLOR_EXPRESSION = /^{((\\s|,)*?[\"'a-zA-Z-]+?\\s*?:\\s*?(['\"])[a-zA-Z0-9-.]*(['\"]))+\\s*}$/;\n  var colorPalettes = null;\n\n  /**\n   * @ngdoc module\n   * @name material.components.colors\n   *\n   * @description\n   * Define $mdColors service and a `md-colors=\"\"` attribute directive\n   */\n  angular\n    .module('material.components.colors', ['material.core'])\n    .directive('mdColors', MdColorsDirective)\n    .service('$mdColors', MdColorsService);\n\n  /**\n   * @ngdoc service\n   * @name $mdColors\n   * @module material.components.colors\n   *\n   * @description\n   * By default, defining a theme does not make its colors available for applying to non AngularJS\n   * Material elements. The `$mdColors` service is used by the `md-color` directive to convert a\n   * set of color expressions to RGBA values and then apply those values to the element as CSS\n   * property values.\n   *\n   * @usage\n   * Getting a color based on a theme\n   *\n   *  <hljs lang=\"js\">\n   *    angular.controller('myCtrl', function ($mdColors) {\n   *      var color = $mdColors.getThemeColor('myTheme-primary-900-0.5');\n   *      ...\n   *    });\n   *  </hljs>\n   *\n   * Applying a color from a palette to an element\n   * <hljs lang=\"js\">\n   *   app.directive('myDirective', function($mdColors) {\n   *     return {\n   *       ...\n   *       link: function (scope, elem) {\n   *         $mdColors.applyThemeColors(elem, {color: 'red-A200-0.2'});\n   *       }\n   *    }\n   *   });\n   * </hljs>\n   */\n  function MdColorsService($mdTheming, $mdUtil, $log) {\n    colorPalettes = colorPalettes || Object.keys($mdTheming.PALETTES);\n\n    // Publish service instance\n    return {\n      applyThemeColors: applyThemeColors,\n      getThemeColor: getThemeColor,\n      hasTheme: hasTheme\n    };\n\n    // ********************************************\n    // Internal Methods\n    // ********************************************\n\n    /**\n     * @ngdoc method\n     * @name $mdColors#applyThemeColors\n     *\n     * @description\n     * Lookup a set of colors by hue, theme, and palette, then apply those colors\n     * with the provided opacity (via `rgba()`) to the specified CSS property.\n     *\n     * @param {angular.element} element the element to apply the styles to\n     * @param {Object} colorExpression Keys are CSS properties and values are strings representing\n     * the `theme-palette-hue-opacity` of the desired color. For example:\n     * `{'color': 'red-A200-0.3', 'background-color': 'myTheme-primary-700-0.8'}`. Theme, hue, and\n     * opacity are optional.\n     */\n    function applyThemeColors(element, colorExpression) {\n      try {\n        if (colorExpression) {\n          // Assign the calculate RGBA color values directly as inline CSS\n          element.css(interpolateColors(colorExpression));\n        }\n      } catch (e) {\n        $log.error(e.message);\n      }\n    }\n\n    /**\n     * @ngdoc method\n     * @name $mdColors#getThemeColor\n     *\n     * @description\n     * Get a parsed RGBA color using a string representing the `theme-palette-hue-opacity` of the\n     * desired color.\n     *\n     * @param {string} expression color expression like `'red-A200-0.3'` or\n     *  `'myTheme-primary-700-0.8'`. Theme, hue, and opacity are optional.\n     * @returns {string} a CSS color value like `rgba(211, 47, 47, 0.8)`\n     */\n    function getThemeColor(expression) {\n      var color = extractColorOptions(expression);\n\n      return parseColor(color);\n    }\n\n    /**\n     * Return the parsed color\n     * @param {{hue: *, theme: any, palette: *, opacity: (*|string|number)}} color hash map of color\n     *  definitions\n     * @param {boolean=} contrast whether use contrast color for foreground. Defaults to false.\n     * @returns {string} rgba color string\n     */\n    function parseColor(color, contrast) {\n      contrast = contrast || false;\n      var rgbValues = $mdTheming.PALETTES[color.palette][color.hue];\n\n      rgbValues = contrast ? rgbValues.contrast : rgbValues.value;\n\n      return $mdUtil.supplant('rgba({0}, {1}, {2}, {3})',\n        [rgbValues[0], rgbValues[1], rgbValues[2], rgbValues[3] || color.opacity]\n      );\n    }\n\n    /**\n     * Convert the color expression into an object with scope-interpolated values\n     * Then calculate the rgba() values based on the theme color parts\n     * @param {Object} themeColors json object, keys are css properties and values are string of\n     * the wanted color, for example: `{color: 'red-A200-0.3'}`.\n     * @return {Object} Hashmap of CSS properties with associated `rgba()` string values\n     */\n    function interpolateColors(themeColors) {\n      var rgbColors = {};\n\n      var hasColorProperty = themeColors.hasOwnProperty('color');\n\n      angular.forEach(themeColors, function (value, key) {\n        var color = extractColorOptions(value);\n        var hasBackground = key.indexOf('background') > -1;\n\n        rgbColors[key] = parseColor(color);\n        if (hasBackground && !hasColorProperty) {\n          rgbColors.color = parseColor(color, true);\n        }\n      });\n\n      return rgbColors;\n    }\n\n    /**\n     * Check if expression has defined theme\n     * For instance:\n     *   'myTheme-primary' => true\n     *   'red-800' => false\n     * @param {string} expression color expression like 'red-800', 'red-A200-0.3',\n     *   'myTheme-primary', or 'myTheme-primary-400'\n     * @return {boolean} true if the expression has a theme part, false otherwise.\n     */\n    function hasTheme(expression) {\n      return angular.isDefined($mdTheming.THEMES[expression.split('-')[0]]);\n    }\n\n    /**\n     * For the evaluated expression, extract the color parts into a hash map\n     * @param {string} expression color expression like 'red-800', 'red-A200-0.3',\n     *   'myTheme-primary', or 'myTheme-primary-400'\n     * @returns {{hue: *, theme: any, palette: *, opacity: (*|string|number)}}\n     */\n    function extractColorOptions(expression) {\n      var parts = expression.split('-');\n      var hasTheme = angular.isDefined($mdTheming.THEMES[parts[0]]);\n      var theme = hasTheme ? parts.splice(0, 1)[0] : $mdTheming.defaultTheme();\n\n      return {\n        theme: theme,\n        palette: extractPalette(parts, theme),\n        hue: extractHue(parts, theme),\n        opacity: parts[2] || 1\n      };\n    }\n\n    /**\n     * Calculate the theme palette name\n     * @param {Array} parts\n     * @param {string} theme name\n     * @return {string}\n     */\n    function extractPalette(parts, theme) {\n      // If the next section is one of the palettes we assume it's a two word palette\n      // Two word palette can be also written in camelCase, forming camelCase to dash-case\n\n      var isTwoWord = parts.length > 1 && colorPalettes.indexOf(parts[1]) !== -1;\n      var palette = parts[0].replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\n\n      if (isTwoWord)  palette = parts[0] + '-' + parts.splice(1, 1);\n\n      if (colorPalettes.indexOf(palette) === -1) {\n        // If the palette is not in the palette list it's one of primary/accent/warn/background\n        var scheme = $mdTheming.THEMES[theme].colors[palette];\n        if (!scheme) {\n          throw new Error($mdUtil.supplant(\n            'mdColors: couldn\\'t find \\'{palette}\\' in the palettes.',\n            {palette: palette}));\n        }\n        palette = scheme.name;\n      }\n\n      return palette;\n    }\n\n    /**\n     * @param {Array} parts\n     * @param {string} theme name\n     * @return {*}\n     */\n    function extractHue(parts, theme) {\n      var themeColors = $mdTheming.THEMES[theme].colors;\n\n      if (parts[1] === 'hue') {\n        var hueNumber = parseInt(parts.splice(2, 1)[0], 10);\n\n        if (hueNumber < 1 || hueNumber > 3) {\n          throw new Error($mdUtil.supplant(\n            'mdColors: \\'hue-{hueNumber}\\' is not a valid hue, can be only \\'hue-1\\', \\'hue-2\\' and \\'hue-3\\'',\n            {hueNumber: hueNumber}));\n        }\n        parts[1] = 'hue-' + hueNumber;\n\n        if (!(parts[0] in themeColors)) {\n          throw new Error($mdUtil.supplant(\n            'mdColors: \\'hue-x\\' can only be used with [{availableThemes}], but was used with \\'{usedTheme}\\'',\n            {\n            availableThemes: Object.keys(themeColors).join(', '),\n            usedTheme: parts[0]\n          }));\n        }\n\n        return themeColors[parts[0]].hues[parts[1]];\n      }\n\n      return parts[1] || themeColors[parts[0] in themeColors ? parts[0] : 'primary'].hues['default'];\n    }\n  }\n\n  /**\n   * @ngdoc directive\n   * @name mdColors\n   * @module material.components.colors\n   *\n   * @restrict A\n   *\n   * @description\n   * `mdColors` directive will apply the theme-based color expression as RGBA CSS style values.\n   *\n   *   The format will be similar to the colors defined in the Sass files:\n   *\n   *   ## `[?theme]-[palette]-[?hue]-[?opacity]`\n   *   - [theme]    - default value is the default theme\n   *   - [palette]  - can be either palette name or primary/accent/warn/background\n   *   - [hue]      - default is 500 (hue-x can be used with primary/accent/warn/background)\n   *   - [opacity]  - default is 1\n   *\n   *\n   *   > `?` indicates optional parameter\n   *\n   * @usage\n   * <hljs lang=\"html\">\n   *   <div md-colors=\"{background: 'myTheme-accent-900-0.43'}\">\n   *     <div md-colors=\"{color: 'red-A100', 'border-color': 'primary-600'}\">\n   *       <span>Color demo</span>\n   *     </div>\n   *   </div>\n   * </hljs>\n   *\n   * The `mdColors` directive will automatically watch for changes in the expression if it recognizes\n   * an interpolation expression or a function. For performance options, you can use `::` prefix to\n   * the `md-colors` expression to indicate a one-time data binding.\n   *\n   * <hljs lang=\"html\">\n   *   <md-card md-colors=\"::{background: '{{theme}}-primary-700'}\">\n   *   </md-card>\n   * </hljs>\n   */\n  function MdColorsDirective($mdColors, $mdUtil, $log, $parse) {\n    return {\n      restrict: 'A',\n      require: ['^?mdTheme'],\n      compile: function (tElem, tAttrs) {\n        var shouldWatch = shouldColorsWatch();\n\n        return function (scope, element, attrs, ctrl) {\n          var mdThemeController = ctrl[0];\n\n          var lastColors = {};\n\n          /**\n           * @param {string=} theme\n           * @return {Object} colors found in the specified theme\n           */\n          var parseColors = function (theme) {\n            if (typeof theme !== 'string') {\n              theme = '';\n            }\n\n            if (!attrs.mdColors) {\n              attrs.mdColors = '{}';\n            }\n\n            /**\n             * Json.parse() does not work because the keys are not quoted;\n             * use $parse to convert to a hash map\n             */\n            var colors = $parse(attrs.mdColors)(scope);\n\n            /**\n             * If mdTheme is defined higher up the DOM tree,\n             * we add mdTheme's theme to the colors which don't specify a theme.\n             *\n             * @example\n             * <hljs lang=\"html\">\n             *   <div md-theme=\"myTheme\">\n             *     <div md-colors=\"{background: 'primary-600'}\">\n             *       <span md-colors=\"{background: 'mySecondTheme-accent-200'}\">Color demo</span>\n             *     </div>\n             *   </div>\n             * </hljs>\n             *\n             * 'primary-600' will be changed to 'myTheme-primary-600',\n             * but 'mySecondTheme-accent-200' will not be changed since it has a theme defined.\n             */\n            if (mdThemeController) {\n              Object.keys(colors).forEach(function (prop) {\n                var color = colors[prop];\n                if (!$mdColors.hasTheme(color)) {\n                  colors[prop] = (theme || mdThemeController.$mdTheme) + '-' + color;\n                }\n              });\n            }\n\n            cleanElement(colors);\n\n            return colors;\n          };\n\n          /**\n           * @param {Object} colors\n           */\n          var cleanElement = function (colors) {\n            if (!angular.equals(colors, lastColors)) {\n              var keys = Object.keys(lastColors);\n\n              if (lastColors.background && !keys.color) {\n                keys.push('color');\n              }\n\n              keys.forEach(function (key) {\n                element.css(key, '');\n              });\n            }\n\n            lastColors = colors;\n          };\n\n          /**\n           * Registering for mgTheme changes and asking mdTheme controller run our callback whenever\n           * a theme changes.\n           */\n          var unregisterChanges = angular.noop;\n\n          if (mdThemeController) {\n            unregisterChanges = mdThemeController.registerChanges(function (theme) {\n              $mdColors.applyThemeColors(element, parseColors(theme));\n            });\n          }\n\n          scope.$on('$destroy', function () {\n            unregisterChanges();\n          });\n\n          try {\n            if (shouldWatch) {\n              scope.$watch(parseColors, angular.bind(this,\n                $mdColors.applyThemeColors, element\n              ), true);\n            }\n            else {\n              $mdColors.applyThemeColors(element, parseColors());\n            }\n\n          }\n          catch (e) {\n            $log.error(e.message);\n          }\n\n        };\n\n        /**\n         * @return {boolean}\n         */\n        function shouldColorsWatch() {\n          // Simulate 1x binding and mark mdColorsWatch == false\n          var rawColorExpression = tAttrs.mdColors;\n          var bindOnce = rawColorExpression.indexOf('::') > -1;\n          var isStatic = bindOnce ? true : STATIC_COLOR_EXPRESSION.test(tAttrs.mdColors);\n\n          // Remove it for the postLink...\n          tAttrs.mdColors = rawColorExpression.replace('::', '');\n\n          var hasWatchAttr = angular.isDefined(tAttrs.mdColorsWatch);\n\n          return (bindOnce || isStatic) ? false :\n            hasWatchAttr ? $mdUtil.parseAttributeBoolean(tAttrs.mdColorsWatch) : true;\n        }\n      }\n    };\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.content\n *\n * @description\n * Scrollable content\n */\nmdContentDirective.$inject = [\"$mdTheming\"];\nangular.module('material.components.content', [\n  'material.core'\n])\n  .directive('mdContent', mdContentDirective);\n\n/**\n * @ngdoc directive\n * @name mdContent\n * @module material.components.content\n *\n * @restrict E\n *\n * @description\n *\n * The `<md-content>` directive is a container element useful for scrollable content. It achieves\n * this by setting the CSS `overflow` property to `auto` so that content can properly scroll.\n *\n * In general, `<md-content>` components are not designed to be nested inside one another. If\n * possible, it is better to make them siblings. This often results in a better user experience as\n * having nested scrollbars may confuse the user.\n *\n * ## Troubleshooting\n *\n * In some cases, you may wish to apply the `md-no-momentum` class to ensure that Safari's\n * momentum scrolling is disabled. Momentum scrolling can cause flickering issues while scrolling\n * SVG icons and some other components.\n *\n * Additionally, we now also offer the `md-no-flicker` class which can be applied to any element\n * and uses a Webkit-specific filter of `blur(0px)` that forces GPU rendering of all elements\n * inside (which eliminates the flicker on iOS devices).\n *\n * _<b>Note:</b> Forcing an element to render on the GPU can have unintended side-effects, especially\n * related to the z-index of elements. Please use with caution and only on the elements needed._\n *\n * @usage\n *\n * Add the `[layout-padding]` attribute to make the content padded.\n *\n * <hljs lang=\"html\">\n *  <md-content layout-padding>\n *      Lorem ipsum dolor sit amet, ne quod novum mei.\n *  </md-content>\n * </hljs>\n */\n\nfunction mdContentDirective($mdTheming) {\n  return {\n    restrict: 'E',\n    controller: ['$scope', '$element', ContentController],\n    link: function(scope, element) {\n      element.addClass('_md');     // private md component indicator for styling\n\n      $mdTheming(element);\n      scope.$broadcast('$mdContentLoaded', element);\n\n      iosScrollFix(element[0]);\n    }\n  };\n\n  function ContentController($scope, $element) {\n    this.$scope = $scope;\n    this.$element = $element;\n  }\n}\n\nfunction iosScrollFix(node) {\n  // IOS FIX:\n  // If we scroll where there is no more room for the webview to scroll,\n  // by default the webview itself will scroll up and down, this looks really\n  // bad.  So if we are scrolling to the very top or bottom, add/subtract one\n  angular.element(node).on('$md.pressdown', function(ev) {\n    // Only touch events\n    if (ev.pointer.type !== 't') return;\n    // Don't let a child content's touchstart ruin it for us.\n    if (ev.$materialScrollFixed) return;\n    ev.$materialScrollFixed = true;\n\n    if (node.scrollTop === 0) {\n      node.scrollTop = 1;\n    } else if (node.scrollHeight === node.scrollTop + node.offsetHeight) {\n      node.scrollTop -= 1;\n    }\n  });\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.datepicker\n * @description Module for the datepicker component.\n */\n\nangular.module('material.components.datepicker', [\n  'material.core',\n  'material.components.icon',\n  'material.components.virtualRepeat'\n]);\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  /**\n   * @ngdoc directive\n   * @name mdCalendar\n   * @module material.components.datepicker\n   *\n   * @param {Date} ng-model The component's model. Should be a Date object.\n   * @param {Object=} ng-model-options Allows tuning of the way in which `ng-model` is being\n   *  updated. Also allows for a timezone to be specified.\n   *  <a href=\"https://docs.angularjs.org/api/ng/directive/ngModelOptions#usage\">Read more at the\n   *  ngModelOptions docs.</a>\n   * @param {Date=} md-min-date Expression representing the minimum date.\n   * @param {Date=} md-max-date Expression representing the maximum date.\n   * @param {(function(Date): boolean)=} md-date-filter Function expecting a date and returning a\n   *  boolean whether it can be selected in \"day\" mode or not.\n   * @param {(function(Date): boolean)=} md-month-filter Function expecting a date and returning a\n   *  boolean whether it can be selected in \"month\" mode or not.\n   * @param {String=} md-current-view Current view of the calendar. Can be either \"month\" or \"year\".\n   * @param {String=} md-mode Restricts the user to only selecting a value from a particular view.\n   *  This option can be used if the user is only supposed to choose from a certain date type\n   *  (e.g. only selecting the month). Can be either \"month\" or \"day\". **Note** that this will\n   *  overwrite the `md-current-view` value.\n   *\n   * @description\n   * `<md-calendar>` is a component that renders a calendar that can be used to select a date.\n   * It is a part of the `<md-datepicker>` pane, however it can also be used on it's own.\n   *\n   * @usage\n   *\n   * <hljs lang=\"html\">\n   *   <md-calendar ng-model=\"birthday\"></md-calendar>\n   * </hljs>\n   */\n  CalendarCtrl.$inject = [\"$element\", \"$scope\", \"$$mdDateUtil\", \"$mdUtil\", \"$mdConstant\", \"$mdTheming\", \"$$rAF\", \"$attrs\", \"$mdDateLocale\", \"$filter\", \"$document\"];\n  calendarDirective.$inject = [\"inputDirective\"];\n  angular.module('material.components.datepicker')\n    .directive('mdCalendar', calendarDirective);\n\n  // TODO(jelbourn): Mac Cmd + left / right == Home / End\n  // TODO(jelbourn): Refactor month element creation to use cloneNode (performance).\n  // TODO(jelbourn): Define virtual scrolling constants (compactness) users can override.\n  // TODO(jelbourn): Animated month transition on ng-model change (virtual-repeat)\n  // TODO(jelbourn): Scroll snapping (virtual repeat)\n  // TODO(jelbourn): Remove superfluous row from short months (virtual-repeat)\n  // TODO(jelbourn): Month headers stick to top when scrolling.\n  // TODO(jelbourn): Previous month opacity is lowered when partially scrolled out of view.\n  // TODO(jelbourn): Support md-calendar standalone on a page (as a tabstop w/ aria-live\n  //     announcement and key handling).\n  // TODO Read-only calendar (not just date-picker).\n\n  function calendarDirective(inputDirective) {\n    return {\n      template: function(tElement, tAttr) {\n        // This allows the calendar to work, without a datepicker. This ensures that the virtual\n        // repeater scrolls to the proper place on load by deferring the execution until the next\n        // digest. It's necessary only if the calendar is used without a datepicker, otherwise it's\n        // already wrapped in an ngIf.\n        var extraAttrs = tAttr.hasOwnProperty('ngIf') ? '' : 'ng-if=\"calendarCtrl.isInitialized\"';\n        return '' +\n          '<div ng-switch=\"calendarCtrl.currentView\" ' + extraAttrs + '>' +\n            '<md-calendar-year ng-switch-when=\"year\"></md-calendar-year>' +\n            '<md-calendar-month ng-switch-default></md-calendar-month>' +\n          '</div>';\n      },\n      scope: {\n        minDate: '=mdMinDate',\n        maxDate: '=mdMaxDate',\n        dateFilter: '=mdDateFilter',\n        monthFilter: '=mdMonthFilter',\n\n        // These need to be prefixed, because Angular resets\n        // any changes to the value due to bindToController.\n        _mode: '@mdMode',\n        _currentView: '@mdCurrentView'\n      },\n      require: ['ngModel', 'mdCalendar'],\n      controller: CalendarCtrl,\n      controllerAs: 'calendarCtrl',\n      bindToController: true,\n      link: function(scope, element, attrs, controllers) {\n        var ngModelCtrl = controllers[0];\n        var mdCalendarCtrl = controllers[1];\n        mdCalendarCtrl.configureNgModel(ngModelCtrl, inputDirective);\n      }\n    };\n  }\n\n  /**\n   * Occasionally the hideVerticalScrollbar method might read an element's\n   * width as 0, because it hasn't been laid out yet. This value will be used\n   * as a fallback, in order to prevent scenarios where the element's width\n   * would otherwise have been set to 0. This value is the \"usual\" width of a\n   * calendar within a floating calendar pane.\n   */\n  var FALLBACK_WIDTH = 340;\n\n  /** Next identifier for calendar instance. */\n  var nextUniqueId = 0;\n\n  /** Maps the `md-mode` values to their corresponding calendar views. */\n  var MODE_MAP = {\n    day: 'month',\n    month: 'year'\n  };\n\n  /**\n   * Controller for the mdCalendar component.\n   * @ngInject @constructor\n   */\n  function CalendarCtrl($element, $scope, $$mdDateUtil, $mdUtil, $mdConstant, $mdTheming, $$rAF,\n                        $attrs, $mdDateLocale, $filter, $document) {\n    $mdTheming($element);\n\n    /**\n     * @final\n     * @type {!JQLite}\n     */\n    this.$element = $element;\n\n    /**\n     * @final\n     * @type {!angular.Scope}\n     */\n    this.$scope = $scope;\n\n    /**\n     * @final\n     * @type {!angular.$attrs} Current attributes object for the element\n     */\n    this.$attrs = $attrs;\n\n    /** @final */\n    this.dateUtil = $$mdDateUtil;\n\n    /** @final */\n    this.$mdUtil = $mdUtil;\n\n    /** @final */\n    this.keyCode = $mdConstant.KEY_CODE;\n\n    /** @final */\n    this.$$rAF = $$rAF;\n\n    /** @final */\n    this.$mdDateLocale = $mdDateLocale;\n\n    /** @final The built-in Angular date filter. */\n    this.ngDateFilter = $filter('date');\n\n    /**\n     * @final\n     * @type {Date}\n     */\n    this.today = this.dateUtil.createDateAtMidnight();\n\n    /** @type {!ngModel.NgModelController} */\n    this.ngModelCtrl = undefined;\n\n    /** @type {string} Class applied to the selected date cell. */\n    this.SELECTED_DATE_CLASS = 'md-calendar-selected-date';\n\n    /** @type {string} Class applied to the cell for today. */\n    this.TODAY_CLASS = 'md-calendar-date-today';\n\n    /** @type {string} Class applied to the focused cell. */\n    this.FOCUSED_DATE_CLASS = 'md-focus';\n\n    /**\n     * @final\n     * @type {number} Unique ID for this calendar instance.\n     */\n    this.id = nextUniqueId++;\n\n    /**\n     * The date that is currently focused or showing in the calendar. This will initially be set\n     * to the ng-model value if set, otherwise to today. It will be updated as the user navigates\n     * to other months. The cell corresponding to the displayDate does not necessarily always have\n     * focus in the document (such as for cases when the user is scrolling the calendar).\n     * @type {Date}\n     */\n    this.displayDate = null;\n\n    /**\n     * Allows restricting the calendar to only allow selecting a month or a day.\n     * @type {'month'|'day'|null}\n     */\n    this.mode = null;\n\n    /**\n     * The selected date. Keep track of this separately from the ng-model value so that we\n     * can know, when the ng-model value changes, what the previous value was before it's updated\n     * in the component's UI.\n     *\n     * @type {Date}\n     */\n    this.selectedDate = null;\n\n    /**\n     * The first date that can be rendered by the calendar. The default is taken\n     * from the mdDateLocale provider and is limited by the mdMinDate.\n     * @type {Date}\n     */\n    this.firstRenderableDate = null;\n\n    /**\n     * The last date that can be rendered by the calendar. The default comes\n     * from the mdDateLocale provider and is limited by the maxDate.\n     * @type {Date}\n     */\n    this.lastRenderableDate = null;\n\n    /**\n     * Used to toggle initialize the root element in the next digest.\n     * @type {boolean}\n     */\n    this.isInitialized = false;\n\n    /**\n     * Cache for the  width of the element without a scrollbar. Used to hide the scrollbar later on\n     * and to avoid extra reflows when switching between views.\n     * @type {number}\n     */\n    this.width = 0;\n\n    /**\n     * Caches the width of the scrollbar in order to be used when hiding it and to avoid extra reflows.\n     * @type {number}\n     */\n    this.scrollbarWidth = 0;\n\n    /**\n     * @type {boolean} set to true if the calendar is being used \"standalone\" (outside of a\n     *  md-datepicker).\n     */\n    this.standaloneMode = false;\n\n    // Unless the user specifies so, the calendar should not be a tab stop.\n    // This is necessary because ngAria might add a tabindex to anything with an ng-model\n    // (based on whether or not the user has turned that particular feature on/off).\n    if (!$attrs.tabindex) {\n      $element.attr('tabindex', '-1');\n    }\n\n    var boundKeyHandler = angular.bind(this, this.handleKeyEvent);\n\n    // If use the md-calendar directly in the body without datepicker,\n    // handleKeyEvent will disable other inputs on the page.\n    // So only apply the handleKeyEvent on the body when the md-calendar inside datepicker,\n    // otherwise apply on the calendar element only.\n\n    var handleKeyElement;\n    if ($element.parent().hasClass('md-datepicker-calendar')) {\n      handleKeyElement = angular.element($document[0].body);\n    } else {\n      this.standaloneMode = true;\n      handleKeyElement = $element;\n    }\n\n    // Bind the keydown handler to the body, in order to handle cases where the focused\n    // element gets removed from the DOM and stops propagating click events.\n    handleKeyElement.on('keydown', boundKeyHandler);\n\n    $scope.$on('$destroy', function() {\n      handleKeyElement.off('keydown', boundKeyHandler);\n    });\n\n    // For AngularJS 1.4 and older, where there are no lifecycle hooks but bindings are pre-assigned,\n    // manually call the $onInit hook.\n    if (angular.version.major === 1 && angular.version.minor <= 4) {\n      this.$onInit();\n    }\n  }\n\n  /**\n   * AngularJS Lifecycle hook for newer AngularJS versions.\n   * Bindings are not guaranteed to have been assigned in the controller, but they are in the\n   * $onInit hook.\n   */\n  CalendarCtrl.prototype.$onInit = function() {\n    /**\n     * The currently visible calendar view. Note the prefix on the scope value,\n     * which is necessary, because the datepicker seems to reset the real one value if the\n     * calendar is open, but the `currentView` on the datepicker's scope is empty.\n     * @type {String}\n     */\n    if (this._mode && MODE_MAP.hasOwnProperty(this._mode)) {\n      this.currentView = MODE_MAP[this._mode];\n      this.mode = this._mode;\n    } else {\n      this.currentView = this._currentView || 'month';\n      this.mode = null;\n    }\n\n    if (this.minDate && this.minDate > this.$mdDateLocale.firstRenderableDate) {\n      this.firstRenderableDate = this.minDate;\n    } else {\n      this.firstRenderableDate = this.$mdDateLocale.firstRenderableDate;\n    }\n\n    if (this.maxDate && this.maxDate < this.$mdDateLocale.lastRenderableDate) {\n      this.lastRenderableDate = this.maxDate;\n    } else {\n      this.lastRenderableDate = this.$mdDateLocale.lastRenderableDate;\n    }\n  };\n\n  /**\n   * Sets up the controller's reference to ngModelController.\n   * @param {!ngModel.NgModelController} ngModelCtrl Instance of the ngModel controller.\n   * @param {Object} inputDirective Config for AngularJS's `input` directive.\n   */\n  CalendarCtrl.prototype.configureNgModel = function(ngModelCtrl, inputDirective) {\n    var self = this;\n    self.ngModelCtrl = ngModelCtrl;\n\n    // The component needs to be [type=\"date\"] in order to be picked up by AngularJS.\n    this.$attrs.$set('type', 'date');\n\n    // Invoke the `input` directive link function, adding a stub for the element.\n    // This allows us to re-use AngularJS' logic for setting the timezone via ng-model-options.\n    // It works by calling the link function directly which then adds the proper `$parsers` and\n    // `$formatters` to the NgModelController.\n    inputDirective[0].link.pre(this.$scope, {\n      on: angular.noop,\n      val: angular.noop,\n      0: {}\n    }, this.$attrs, [ngModelCtrl]);\n\n    ngModelCtrl.$render = function() {\n      var value = this.$viewValue, convertedDate;\n\n      // In the case where a conversion is needed, the $viewValue here will be a string like\n      // \"2020-05-10\" instead of a Date object.\n      if (!self.dateUtil.isValidDate(value)) {\n        convertedDate = self.dateUtil.removeLocalTzAndReparseDate(new Date(value));\n        if (self.dateUtil.isValidDate(convertedDate)) {\n          value = convertedDate;\n        }\n      }\n\n      // Notify the child scopes of any changes.\n      self.$scope.$broadcast('md-calendar-parent-changed', value);\n\n      // Set up the selectedDate if it hasn't been already.\n      if (!self.selectedDate) {\n        self.selectedDate = value;\n      }\n\n      // Also set up the displayDate.\n      if (!self.displayDate) {\n        self.displayDate = self.selectedDate || self.today;\n      }\n    };\n\n    self.$mdUtil.nextTick(function() {\n      self.isInitialized = true;\n    });\n  };\n\n  /**\n   * Sets the ng-model value for the calendar and emits a change event.\n   * @param {Date} date new value for the calendar\n   */\n  CalendarCtrl.prototype.setNgModelValue = function(date) {\n    var timezone = this.$mdUtil.getModelOption(this.ngModelCtrl, 'timezone');\n    var value = this.dateUtil.createDateAtMidnight(date);\n    this.focusDate(value);\n    this.$scope.$emit('md-calendar-change', value);\n    // Using the timezone when the offset is negative (GMT+X) causes the previous day to be\n    // selected here. This check avoids that.\n    if (timezone == null || value.getTimezoneOffset() < 0) {\n      this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd'), 'default');\n    } else {\n      this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd', timezone), 'default');\n    }\n    this.ngModelCtrl.$render();\n    return value;\n  };\n\n  /**\n   * Sets the current view that should be visible in the calendar\n   * @param {string} newView View name to be set.\n   * @param {number|Date} time Date object or a timestamp for the new display date.\n   */\n  CalendarCtrl.prototype.setCurrentView = function(newView, time) {\n    var self = this;\n\n    self.$mdUtil.nextTick(function() {\n      self.currentView = newView;\n\n      if (time) {\n        self.displayDate = angular.isDate(time) ? time : new Date(time);\n      }\n    });\n  };\n\n  /**\n   * Focus the cell corresponding to the given date.\n   * @param {Date=} date The date to be focused.\n   */\n  CalendarCtrl.prototype.focusDate = function(date) {\n    if (this.dateUtil.isValidDate(date)) {\n      var previousFocus = this.$element[0].querySelector('.' + this.FOCUSED_DATE_CLASS);\n      if (previousFocus) {\n        previousFocus.classList.remove(this.FOCUSED_DATE_CLASS);\n      }\n\n      var cellId = this.getDateId(date, this.currentView);\n      var cell = document.getElementById(cellId);\n      if (cell) {\n        cell.classList.add(this.FOCUSED_DATE_CLASS);\n        cell.focus();\n        this.displayDate = date;\n      }\n    } else {\n      var rootElement = this.$element[0].querySelector('[ng-switch]');\n\n      if (rootElement) {\n        rootElement.focus();\n      }\n    }\n  };\n\n  /**\n   * Highlights a date cell on the calendar and changes the selected date.\n   * @param {Date=} date Date to be marked as selected.\n   */\n  CalendarCtrl.prototype.changeSelectedDate = function(date) {\n    var selectedDateClass = this.SELECTED_DATE_CLASS;\n    var prevDateCell = this.$element[0].querySelector('.' + selectedDateClass);\n\n    // Remove the selected class from the previously selected date, if any.\n    if (prevDateCell) {\n      prevDateCell.classList.remove(selectedDateClass);\n      prevDateCell.setAttribute('aria-selected', 'false');\n    }\n\n    // Apply the select class to the new selected date if it is set.\n    if (date) {\n      var dateCell = document.getElementById(this.getDateId(date, this.currentView));\n      if (dateCell) {\n        dateCell.classList.add(selectedDateClass);\n        dateCell.setAttribute('aria-selected', 'true');\n      }\n    }\n\n    this.selectedDate = date;\n  };\n\n  /**\n   * Normalizes the key event into an action name. The action will be broadcast\n   * to the child controllers.\n   * @param {KeyboardEvent} event\n   * @returns {string} The action that should be taken, or null if the key\n   *  does not match a calendar shortcut.\n   */\n  CalendarCtrl.prototype.getActionFromKeyEvent = function(event) {\n    var keyCode = this.keyCode;\n\n    switch (event.which) {\n      case keyCode.ENTER: return 'select';\n\n      case keyCode.RIGHT_ARROW: return 'move-right';\n      case keyCode.LEFT_ARROW: return 'move-left';\n\n      case keyCode.DOWN_ARROW: return event.metaKey ? 'move-page-down' : 'move-row-down';\n      case keyCode.UP_ARROW: return event.metaKey ? 'move-page-up' : 'move-row-up';\n\n      case keyCode.PAGE_DOWN: return 'move-page-down';\n      case keyCode.PAGE_UP: return 'move-page-up';\n\n      case keyCode.HOME: return 'start';\n      case keyCode.END: return 'end';\n\n      default: return null;\n    }\n  };\n\n  /**\n   * Handles a key event in the calendar with the appropriate action.\n   * The action will either\n   *  - select the focused date\n   *  - navigate to focus a new date\n   *  - emit a md-calendar-close event if in a md-datepicker panel\n   *  - emit a md-calendar-parent-action\n   *  - delegate to normal tab order if the TAB key is pressed in standalone mode\n   * @param {KeyboardEvent} event\n   */\n  CalendarCtrl.prototype.handleKeyEvent = function(event) {\n    var self = this;\n\n    this.$scope.$apply(function() {\n      // Capture escape and emit back up so that a wrapping component\n      // (such as a date-picker) can decide to close.\n      if (event.which === self.keyCode.ESCAPE ||\n          (event.which === self.keyCode.TAB && !self.standaloneMode)) {\n        self.$scope.$emit('md-calendar-close');\n\n        if (event.which === self.keyCode.TAB) {\n          event.preventDefault();\n        }\n\n        return;\n      } else if (event.which === self.keyCode.TAB && self.standaloneMode) {\n        // delegate to the normal tab order if the TAB key is pressed in standalone mode\n        return;\n      }\n\n      // Broadcast the action that any child controllers should take.\n      var action = self.getActionFromKeyEvent(event);\n      if (action) {\n        event.preventDefault();\n        event.stopPropagation();\n        self.$scope.$broadcast('md-calendar-parent-action', action);\n      }\n    });\n  };\n\n  /**\n   * Hides the vertical scrollbar on the calendar scroller of a child controller by\n   * setting the width on the calendar scroller and the `overflow: hidden` wrapper\n   * around the scroller, and then setting a padding-right on the scroller equal\n   * to the width of the browser's scrollbar.\n   *\n   * This will cause a reflow.\n   *\n   * @param {object} childCtrl The child controller whose scrollbar should be hidden.\n   */\n  CalendarCtrl.prototype.hideVerticalScrollbar = function(childCtrl) {\n    var self = this;\n    var element = childCtrl.$element[0];\n    var scrollMask = element.querySelector('.md-calendar-scroll-mask');\n\n    if (self.width > 0) {\n      setWidth();\n    } else {\n      self.$$rAF(function() {\n        var scroller = childCtrl.calendarScroller;\n\n        self.scrollbarWidth = scroller.offsetWidth - scroller.clientWidth;\n        self.width = element.querySelector('table').offsetWidth;\n        setWidth();\n      });\n    }\n\n    function setWidth() {\n      var width = self.width || FALLBACK_WIDTH;\n      var scrollbarWidth = self.scrollbarWidth;\n      var scroller = childCtrl.calendarScroller;\n\n      scrollMask.style.width = width + 'px';\n      scroller.style.width = (width + scrollbarWidth) + 'px';\n      scroller.style.paddingRight = scrollbarWidth + 'px';\n    }\n  };\n\n  /**\n   * Gets an identifier for a date unique to the calendar instance for internal\n   * purposes. Not to be displayed.\n   * @param {Date} date The date for which the id is being generated\n   * @param {string} namespace Namespace for the id. (month, year etc.)\n   * @returns {string}\n   */\n  CalendarCtrl.prototype.getDateId = function(date, namespace) {\n    if (!namespace) {\n      throw new Error('A namespace for the date id has to be specified.');\n    }\n\n    return [\n      'md',\n      this.id,\n      namespace,\n      date.getFullYear(),\n      date.getMonth(),\n      date.getDate()\n    ].join('-');\n  };\n\n  /**\n   * Util to trigger an extra digest on a parent scope, in order to to ensure that\n   * any child virtual repeaters have updated. This is necessary, because the virtual\n   * repeater doesn't update the $index the first time around since the content isn't\n   * in place yet. The case, in which this is an issue, is when the repeater has less\n   * than a page of content (e.g. a month or year view has a min or max date).\n   */\n  CalendarCtrl.prototype.updateVirtualRepeat = function() {\n    var scope = this.$scope;\n    var virtualRepeatResizeListener = scope.$on('$md-resize-enable', function() {\n      if (!scope.$$phase) {\n        scope.$apply();\n      }\n\n      virtualRepeatResizeListener();\n    });\n  };\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  CalendarMonthCtrl.$inject = [\"$element\", \"$scope\", \"$animate\", \"$q\", \"$$mdDateUtil\", \"$mdDateLocale\"];\n  angular.module('material.components.datepicker')\n    .directive('mdCalendarMonth', calendarDirective);\n\n  /**\n   * Height of one calendar month tbody. This must be made known to the virtual-repeat and is\n   * subsequently used for scrolling to specific months.\n   */\n  var TBODY_HEIGHT = 265;\n\n  /**\n   * Height of a calendar month with a single row. This is needed to calculate the offset for\n   * rendering an extra month in virtual-repeat that only contains one row.\n   */\n  var TBODY_SINGLE_ROW_HEIGHT = 45;\n\n  /** Private directive that represents a list of months inside the calendar. */\n  function calendarDirective() {\n    return {\n      template:\n        '<table aria-hidden=\"true\" class=\"md-calendar-day-header\"><thead></thead></table>' +\n        '<div class=\"md-calendar-scroll-mask\">' +\n        '<md-virtual-repeat-container class=\"md-calendar-scroll-container\" ' +\n              'md-offset-size=\"' + (TBODY_SINGLE_ROW_HEIGHT - TBODY_HEIGHT) + '\">' +\n            '<table role=\"grid\" tabindex=\"0\" class=\"md-calendar\" aria-readonly=\"true\">' +\n              '<tbody ' +\n                  'md-calendar-month-body ' +\n                  'role=\"rowgroup\" ' +\n                  'md-virtual-repeat=\"i in monthCtrl.items\" ' +\n                  'md-month-offset=\"$index\" ' +\n                  'class=\"md-calendar-month\" ' +\n                  'md-start-index=\"monthCtrl.getSelectedMonthIndex()\" ' +\n                  'md-item-size=\"' + TBODY_HEIGHT + '\">' +\n\n                // The <tr> ensures that the <tbody> will always have the\n                // proper height, even if it's empty. If it's content is\n                // compiled, the <tr> will be overwritten.\n                '<tr aria-hidden=\"true\" md-force-height=\"\\'' + TBODY_HEIGHT + 'px\\'\"></tr>' +\n              '</tbody>' +\n            '</table>' +\n          '</md-virtual-repeat-container>' +\n        '</div>',\n      require: ['^^mdCalendar', 'mdCalendarMonth'],\n      controller: CalendarMonthCtrl,\n      controllerAs: 'monthCtrl',\n      bindToController: true,\n      link: function(scope, element, attrs, controllers) {\n        var calendarCtrl = controllers[0];\n        var monthCtrl = controllers[1];\n        monthCtrl.initialize(calendarCtrl);\n      }\n    };\n  }\n\n  /**\n   * Controller for the calendar month component.\n   * @ngInject @constructor\n   */\n  function CalendarMonthCtrl($element, $scope, $animate, $q,\n    $$mdDateUtil, $mdDateLocale) {\n\n    /** @final {!angular.JQLite} */\n    this.$element = $element;\n\n    /** @final {!angular.Scope} */\n    this.$scope = $scope;\n\n    /** @final {!angular.$animate} */\n    this.$animate = $animate;\n\n    /** @final {!angular.$q} */\n    this.$q = $q;\n\n    /** @final */\n    this.dateUtil = $$mdDateUtil;\n\n    /** @final */\n    this.dateLocale = $mdDateLocale;\n\n    /** @final {HTMLElement} */\n    this.calendarScroller = $element[0].querySelector('.md-virtual-repeat-scroller');\n\n    /** @type {boolean} */\n    this.isInitialized = false;\n\n    /** @type {boolean} */\n    this.isMonthTransitionInProgress = false;\n\n    var self = this;\n\n    /**\n     * Handles a click event on a date cell.\n     * Created here so that every cell can use the same function instance.\n     * @this {HTMLTableCellElement} The cell that was clicked.\n     */\n    this.cellClickHandler = function() {\n      var timestamp = $$mdDateUtil.getTimestampFromNode(this);\n      self.$scope.$apply(function() {\n        // The timestamp has to be converted to a valid date.\n        self.calendarCtrl.setNgModelValue(new Date(timestamp));\n      });\n    };\n\n    /**\n     * Handles click events on the month headers. Switches\n     * the calendar to the year view.\n     * @this {HTMLTableCellElement} The cell that was clicked.\n     */\n    this.headerClickHandler = function() {\n      self.calendarCtrl.setCurrentView('year', $$mdDateUtil.getTimestampFromNode(this));\n    };\n  }\n\n  /** Initialization **/\n\n  /**\n   * Initialize the controller by saving a reference to the calendar and\n   * setting up the object that will be iterated by the virtual repeater.\n   */\n  CalendarMonthCtrl.prototype.initialize = function(calendarCtrl) {\n    /**\n     * Dummy array-like object for virtual-repeat to iterate over. The length is the total\n     * number of months that can be viewed. We add 2 months: one to include the current month\n     * and one for the last dummy month.\n     *\n     * This is shorter than ideal because of a (potential) Firefox bug\n     * https://bugzilla.mozilla.org/show_bug.cgi?id=1181658.\n     */\n\n    this.items = {\n      length: this.dateUtil.getMonthDistance(\n        calendarCtrl.firstRenderableDate,\n        calendarCtrl.lastRenderableDate\n      ) + 2\n    };\n\n    this.calendarCtrl = calendarCtrl;\n    this.attachScopeListeners();\n    calendarCtrl.updateVirtualRepeat();\n\n    // Fire the initial render, since we might have missed it the first time it fired.\n    calendarCtrl.ngModelCtrl && calendarCtrl.ngModelCtrl.$render();\n  };\n\n  /**\n   * Gets the \"index\" of the currently selected date as it would be in the virtual-repeat.\n   * @returns {number} the \"index\" of the currently selected date\n   */\n  CalendarMonthCtrl.prototype.getSelectedMonthIndex = function() {\n    var calendarCtrl = this.calendarCtrl;\n\n    return this.dateUtil.getMonthDistance(\n      calendarCtrl.firstRenderableDate,\n      calendarCtrl.displayDate || calendarCtrl.selectedDate || calendarCtrl.today\n    );\n  };\n\n  /**\n   * Change the date that is being shown in the calendar. If the given date is in a different\n   * month, the displayed month will be transitioned.\n   * @param {Date} date\n   */\n  CalendarMonthCtrl.prototype.changeDisplayDate = function(date) {\n    // Initialization is deferred until this function is called because we want to reflect\n    // the starting value of ngModel.\n    if (!this.isInitialized) {\n      this.buildWeekHeader();\n      this.calendarCtrl.hideVerticalScrollbar(this);\n      this.isInitialized = true;\n      return this.$q.when();\n    }\n\n    // If trying to show an invalid date or a transition is in progress, do nothing.\n    if (!this.dateUtil.isValidDate(date) || this.isMonthTransitionInProgress) {\n      return this.$q.when();\n    }\n\n    this.isMonthTransitionInProgress = true;\n    var animationPromise = this.animateDateChange(date);\n\n    this.calendarCtrl.displayDate = date;\n\n    var self = this;\n    animationPromise.then(function() {\n      self.isMonthTransitionInProgress = false;\n    });\n\n    return animationPromise;\n  };\n\n  /**\n   * Animates the transition from the calendar's current month to the given month.\n   * @param {Date} date\n   * @returns {angular.$q.Promise} The animation promise.\n   */\n  CalendarMonthCtrl.prototype.animateDateChange = function(date) {\n    if (this.dateUtil.isValidDate(date)) {\n      var monthDistance = this.dateUtil.getMonthDistance(this.calendarCtrl.firstRenderableDate, date);\n      this.calendarScroller.scrollTop = monthDistance * TBODY_HEIGHT;\n    }\n\n    return this.$q.when();\n  };\n\n  /**\n   * Builds and appends a day-of-the-week header to the calendar.\n   * This should only need to be called once during initialization.\n   */\n  CalendarMonthCtrl.prototype.buildWeekHeader = function() {\n    var firstDayOfWeek = this.dateLocale.firstDayOfWeek;\n    var shortDays = this.dateLocale.shortDays;\n\n    var row = document.createElement('tr');\n    for (var i = 0; i < 7; i++) {\n      var th = document.createElement('th');\n      th.textContent = shortDays[(i + firstDayOfWeek) % 7];\n      row.appendChild(th);\n    }\n\n    this.$element.find('thead').append(row);\n  };\n\n  /**\n   * Attaches listeners for the scope events that are broadcast by the calendar.\n   */\n  CalendarMonthCtrl.prototype.attachScopeListeners = function() {\n    var self = this;\n\n    self.$scope.$on('md-calendar-parent-changed', function(event, value) {\n      self.calendarCtrl.changeSelectedDate(value);\n      self.changeDisplayDate(value);\n    });\n\n    self.$scope.$on('md-calendar-parent-action', angular.bind(this, this.handleKeyEvent));\n  };\n\n  /**\n   * Handles the month-specific keyboard interactions.\n   * @param {Object} event Scope event object passed by the calendar.\n   * @param {String} action Action, corresponding to the key that was pressed.\n   */\n  CalendarMonthCtrl.prototype.handleKeyEvent = function(event, action) {\n    var calendarCtrl = this.calendarCtrl;\n    var displayDate = calendarCtrl.displayDate;\n\n    if (action === 'select') {\n      calendarCtrl.setNgModelValue(displayDate);\n    } else {\n      var date = null;\n      var dateUtil = this.dateUtil;\n\n      switch (action) {\n        case 'move-right': date = dateUtil.incrementDays(displayDate, 1); break;\n        case 'move-left': date = dateUtil.incrementDays(displayDate, -1); break;\n\n        case 'move-page-down': date = dateUtil.incrementMonths(displayDate, 1); break;\n        case 'move-page-up': date = dateUtil.incrementMonths(displayDate, -1); break;\n\n        case 'move-row-down': date = dateUtil.incrementDays(displayDate, 7); break;\n        case 'move-row-up': date = dateUtil.incrementDays(displayDate, -7); break;\n\n        case 'start': date = dateUtil.getFirstDateOfMonth(displayDate); break;\n        case 'end': date = dateUtil.getLastDateOfMonth(displayDate); break;\n      }\n\n      if (date) {\n        date = this.dateUtil.clampDate(date, calendarCtrl.minDate, calendarCtrl.maxDate);\n\n        this.changeDisplayDate(date).then(function() {\n          calendarCtrl.focusDate(date);\n        });\n      }\n    }\n  };\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  mdCalendarMonthBodyDirective.$inject = [\"$compile\", \"$$mdSvgRegistry\"];\n  CalendarMonthBodyCtrl.$inject = [\"$element\", \"$$mdDateUtil\", \"$mdDateLocale\"];\n  angular.module('material.components.datepicker')\n      .directive('mdCalendarMonthBody', mdCalendarMonthBodyDirective);\n\n  /**\n   * Private directive consumed by md-calendar-month. Having this directive lets the calender use\n   * md-virtual-repeat and also cleanly separates the month DOM construction functions from\n   * the rest of the calendar controller logic.\n   * @ngInject\n   */\n  function mdCalendarMonthBodyDirective($compile, $$mdSvgRegistry) {\n    var ARROW_ICON = $compile('<md-icon md-svg-src=\"' +\n      $$mdSvgRegistry.mdTabsArrow + '\"></md-icon>')({})[0];\n\n    return {\n      require: ['^^mdCalendar', '^^mdCalendarMonth', 'mdCalendarMonthBody'],\n      scope: { offset: '=mdMonthOffset' },\n      controller: CalendarMonthBodyCtrl,\n      controllerAs: 'mdMonthBodyCtrl',\n      bindToController: true,\n      link: function(scope, element, attrs, controllers) {\n        var calendarCtrl = controllers[0];\n        var monthCtrl = controllers[1];\n        var monthBodyCtrl = controllers[2];\n\n        monthBodyCtrl.calendarCtrl = calendarCtrl;\n        monthBodyCtrl.monthCtrl = monthCtrl;\n        monthBodyCtrl.arrowIcon = ARROW_ICON.cloneNode(true);\n\n        // The virtual-repeat re-uses the same DOM elements, so there are only a limited number\n        // of repeated items that are linked, and then those elements have their bindings updated.\n        // Since the months are not generated by bindings, we simply regenerate the entire thing\n        // when the binding (offset) changes.\n        scope.$watch(function() { return monthBodyCtrl.offset; }, function(offset) {\n          if (angular.isNumber(offset)) {\n            monthBodyCtrl.generateContent();\n          }\n        });\n      }\n    };\n  }\n\n  /**\n   * Controller for a single calendar month.\n   * @ngInject @constructor\n   */\n  function CalendarMonthBodyCtrl($element, $$mdDateUtil, $mdDateLocale) {\n    /**\n     * @final\n     * @type {!JQLite}\n     */\n    this.$element = $element;\n\n    /** @final */\n    this.dateUtil = $$mdDateUtil;\n\n    /** @final */\n    this.dateLocale = $mdDateLocale;\n\n    /** @type {Object} Reference to the month view. */\n    this.monthCtrl = null;\n\n    /** @type {Object} Reference to the calendar. */\n    this.calendarCtrl = null;\n\n    /**\n     * Number of months from the start of the month \"items\" that the currently rendered month\n     * occurs. Set via angular data binding.\n     * @type {number|null}\n     */\n    this.offset = null;\n\n    /**\n     * Date cell to focus after appending the month to the document.\n     * @type {HTMLElement}\n     */\n    this.focusAfterAppend = null;\n  }\n\n  /** Generate and append the content for this month to the directive element. */\n  CalendarMonthBodyCtrl.prototype.generateContent = function() {\n    var date = this.dateUtil.incrementMonths(this.calendarCtrl.firstRenderableDate, this.offset);\n\n    this.$element\n      .empty()\n      .append(this.buildCalendarForMonth(date));\n\n    if (this.focusAfterAppend) {\n      this.focusAfterAppend.classList.add(this.calendarCtrl.FOCUSED_DATE_CLASS);\n      this.focusAfterAppend = null;\n    }\n  };\n\n  /**\n   * Creates a single cell to contain a date in the calendar with all appropriate\n   * attributes and classes added. If a date is given, the cell content will be set\n   * based on the date.\n   * @param {Date=} opt_date\n   * @returns {HTMLElement}\n   */\n  CalendarMonthBodyCtrl.prototype.buildDateCell = function(opt_date) {\n    var monthCtrl = this.monthCtrl;\n    var calendarCtrl = this.calendarCtrl;\n\n    // TODO(jelbourn): cloneNode is likely a faster way of doing this.\n    var cell = document.createElement('td');\n    cell.tabIndex = -1;\n    cell.classList.add('md-calendar-date');\n    cell.setAttribute('role', 'gridcell');\n\n    if (opt_date) {\n      cell.setAttribute('tabindex', '-1');\n      cell.setAttribute('aria-label', this.dateLocale.longDateFormatter(opt_date));\n      cell.id = calendarCtrl.getDateId(opt_date, 'month');\n\n      // Use `data-timestamp` attribute because IE10 does not support the `dataset` property.\n      cell.setAttribute('data-timestamp', opt_date.getTime());\n\n      // TODO(jelourn): Doing these comparisons for class addition during generation might be slow.\n      // It may be better to finish the construction and then query the node and add the class.\n      if (this.dateUtil.isSameDay(opt_date, calendarCtrl.today)) {\n        cell.classList.add(calendarCtrl.TODAY_CLASS);\n      }\n\n      if (this.dateUtil.isValidDate(calendarCtrl.selectedDate) &&\n          this.dateUtil.isSameDay(opt_date, calendarCtrl.selectedDate)) {\n        cell.classList.add(calendarCtrl.SELECTED_DATE_CLASS);\n        cell.setAttribute('aria-selected', 'true');\n      }\n\n      var cellText = this.dateLocale.dates[opt_date.getDate()];\n\n      if (this.isDateEnabled(opt_date)) {\n        // Add a indicator for select, hover, and focus states.\n        var selectionIndicator = document.createElement('span');\n        selectionIndicator.classList.add('md-calendar-date-selection-indicator');\n        selectionIndicator.textContent = cellText;\n        cell.appendChild(selectionIndicator);\n        cell.addEventListener('click', monthCtrl.cellClickHandler);\n\n        if (calendarCtrl.displayDate && this.dateUtil.isSameDay(opt_date, calendarCtrl.displayDate)) {\n          this.focusAfterAppend = cell;\n        }\n      } else {\n        cell.classList.add('md-calendar-date-disabled');\n        cell.textContent = cellText;\n      }\n    }\n\n    return cell;\n  };\n\n  /**\n   * Check whether date is in range and enabled\n   * @param {Date=} opt_date\n   * @return {boolean} Whether the date is enabled.\n   */\n  CalendarMonthBodyCtrl.prototype.isDateEnabled = function(opt_date) {\n    return this.dateUtil.isDateWithinRange(opt_date,\n          this.calendarCtrl.minDate, this.calendarCtrl.maxDate) &&\n          (!angular.isFunction(this.calendarCtrl.dateFilter)\n           || this.calendarCtrl.dateFilter(opt_date));\n  };\n\n  /**\n   * Builds a `tr` element for the calendar grid.\n   * @param rowNumber The week number within the month.\n   * @returns {HTMLElement}\n   */\n  CalendarMonthBodyCtrl.prototype.buildDateRow = function(rowNumber) {\n    var row = document.createElement('tr');\n    row.setAttribute('role', 'row');\n\n    // Because of an NVDA bug (with Firefox), the row needs an aria-label in order\n    // to prevent the entire row being read aloud when the user moves between rows.\n    // See http://community.nvda-project.org/ticket/4643.\n    row.setAttribute('aria-label', this.dateLocale.weekNumberFormatter(rowNumber));\n\n    return row;\n  };\n\n  /**\n   * Builds the <tbody> content for the given date's month.\n   * @param {Date=} opt_dateInMonth\n   * @returns {DocumentFragment} A document fragment containing the <tr> elements.\n   */\n  CalendarMonthBodyCtrl.prototype.buildCalendarForMonth = function(opt_dateInMonth) {\n    var date = this.dateUtil.isValidDate(opt_dateInMonth) ? opt_dateInMonth : new Date();\n\n    var firstDayOfMonth = this.dateUtil.getFirstDateOfMonth(date);\n    var firstDayOfTheWeek = this.getLocaleDay_(firstDayOfMonth);\n    var numberOfDaysInMonth = this.dateUtil.getNumberOfDaysInMonth(date);\n\n    // Store rows for the month in a document fragment so that we can append them all at once.\n    var monthBody = document.createDocumentFragment();\n\n    var rowNumber = 1;\n    var row = this.buildDateRow(rowNumber);\n    monthBody.appendChild(row);\n\n    // If this is the final month in the list of items, only the first week should render,\n    // so we should return immediately after the first row is complete and has been\n    // attached to the body.\n    var isFinalMonth = this.offset === this.monthCtrl.items.length - 1;\n\n    // Add a label for the month. If the month starts on a Sun/Mon/Tues, the month label\n    // goes on a row above the first of the month. Otherwise, the month label takes up the first\n    // two cells of the first row.\n    var blankCellOffset = 0;\n    var monthLabelCell = document.createElement('td');\n    var monthLabelCellContent = document.createElement('span');\n    var calendarCtrl = this.calendarCtrl;\n\n    monthLabelCellContent.textContent = this.dateLocale.monthHeaderFormatter(date);\n    monthLabelCell.appendChild(monthLabelCellContent);\n    monthLabelCell.classList.add('md-calendar-month-label');\n    // If the entire month is after the max date, render the label as a disabled state.\n    if (calendarCtrl.maxDate && firstDayOfMonth > calendarCtrl.maxDate) {\n      monthLabelCell.classList.add('md-calendar-month-label-disabled');\n    // If the user isn't supposed to be able to change views, render the\n    // label as usual, but disable the clicking functionality.\n    } else if (!calendarCtrl.mode) {\n      monthLabelCell.addEventListener('click', this.monthCtrl.headerClickHandler);\n      monthLabelCell.setAttribute('data-timestamp', firstDayOfMonth.getTime());\n      monthLabelCell.setAttribute('aria-label', this.dateLocale.monthFormatter(date));\n      monthLabelCell.classList.add('md-calendar-label-clickable');\n      monthLabelCell.appendChild(this.arrowIcon.cloneNode(true));\n    }\n\n    if (firstDayOfTheWeek <= 2) {\n      monthLabelCell.setAttribute('colspan', '7');\n\n      var monthLabelRow = this.buildDateRow();\n      monthLabelRow.appendChild(monthLabelCell);\n      monthBody.insertBefore(monthLabelRow, row);\n\n      if (isFinalMonth) {\n        return monthBody;\n      }\n    } else {\n      blankCellOffset = 3;\n      monthLabelCell.setAttribute('colspan', '3');\n      row.appendChild(monthLabelCell);\n    }\n\n    // Add a blank cell for each day of the week that occurs before the first of the month.\n    // For example, if the first day of the month is a Tuesday, add blank cells for Sun and Mon.\n    // The blankCellOffset is needed in cases where the first N cells are used by the month label.\n    for (var i = blankCellOffset; i < firstDayOfTheWeek; i++) {\n      row.appendChild(this.buildDateCell());\n    }\n\n    // Add a cell for each day of the month, keeping track of the day of the week so that\n    // we know when to start a new row.\n    var dayOfWeek = firstDayOfTheWeek;\n    var iterationDate = firstDayOfMonth;\n    for (var d = 1; d <= numberOfDaysInMonth; d++) {\n      // If we've reached the end of the week, start a new row.\n      if (dayOfWeek === 7) {\n        // We've finished the first row, so we're done if this is the final month.\n        if (isFinalMonth) {\n          return monthBody;\n        }\n        dayOfWeek = 0;\n        rowNumber++;\n        row = this.buildDateRow(rowNumber);\n        monthBody.appendChild(row);\n      }\n\n      iterationDate.setDate(d);\n      var cell = this.buildDateCell(iterationDate);\n      row.appendChild(cell);\n\n      dayOfWeek++;\n    }\n\n    // Ensure that the last row of the month has 7 cells.\n    while (row.childNodes.length < 7) {\n      row.appendChild(this.buildDateCell());\n    }\n\n    // Ensure that all months have 6 rows. This is necessary for now because the virtual-repeat\n    // requires that all items have exactly the same height.\n    while (monthBody.childNodes.length < 6) {\n      var whitespaceRow = this.buildDateRow();\n      for (var j = 0; j < 7; j++) {\n        whitespaceRow.appendChild(this.buildDateCell());\n      }\n      monthBody.appendChild(whitespaceRow);\n    }\n\n    return monthBody;\n  };\n\n  /**\n   * Gets the day-of-the-week index for a date for the current locale.\n   * @private\n   * @param {Date} date\n   * @returns {number} The column index of the date in the calendar.\n   */\n  CalendarMonthBodyCtrl.prototype.getLocaleDay_ = function(date) {\n    return (date.getDay() + (7 - this.dateLocale.firstDayOfWeek)) % 7;\n  };\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  CalendarYearCtrl.$inject = [\"$element\", \"$scope\", \"$animate\", \"$q\", \"$$mdDateUtil\", \"$mdUtil\"];\n  angular.module('material.components.datepicker')\n    .directive('mdCalendarYear', calendarDirective);\n\n  /**\n   * Height of one calendar year tbody. This must be made known to the virtual-repeat and is\n   * subsequently used for scrolling to specific years.\n   */\n  var TBODY_HEIGHT = 88;\n\n  /** Private component, representing a list of years in the calendar. */\n  function calendarDirective() {\n    return {\n      template:\n        '<div class=\"md-calendar-scroll-mask\">' +\n          '<md-virtual-repeat-container class=\"md-calendar-scroll-container\">' +\n            '<table role=\"grid\" tabindex=\"0\" class=\"md-calendar\" aria-readonly=\"true\">' +\n              '<tbody ' +\n                  'md-calendar-year-body ' +\n                  'role=\"rowgroup\" ' +\n                  'md-virtual-repeat=\"i in yearCtrl.items\" ' +\n                  'md-year-offset=\"$index\" class=\"md-calendar-year\" ' +\n                  'md-start-index=\"yearCtrl.getFocusedYearIndex()\" ' +\n                  'md-item-size=\"' + TBODY_HEIGHT + '\">' +\n                // The <tr> ensures that the <tbody> will have the proper\n                // height, even though it may be empty.\n                '<tr aria-hidden=\"true\" md-force-height=\"\\'' + TBODY_HEIGHT + 'px\\'\"></tr>' +\n              '</tbody>' +\n            '</table>' +\n          '</md-virtual-repeat-container>' +\n        '</div>',\n      require: ['^^mdCalendar', 'mdCalendarYear'],\n      controller: CalendarYearCtrl,\n      controllerAs: 'yearCtrl',\n      bindToController: true,\n      link: function(scope, element, attrs, controllers) {\n        var calendarCtrl = controllers[0];\n        var yearCtrl = controllers[1];\n        yearCtrl.initialize(calendarCtrl);\n      }\n    };\n  }\n\n  /**\n   * Controller for the mdCalendar component.\n   * @ngInject @constructor\n   */\n  function CalendarYearCtrl($element, $scope, $animate, $q, $$mdDateUtil, $mdUtil) {\n\n    /** @final {!angular.JQLite} */\n    this.$element = $element;\n\n    /** @final {!angular.Scope} */\n    this.$scope = $scope;\n\n    /** @final {!angular.$animate} */\n    this.$animate = $animate;\n\n    /** @final {!angular.$q} */\n    this.$q = $q;\n\n    /** @final */\n    this.dateUtil = $$mdDateUtil;\n\n    /** @final {HTMLElement} */\n    this.calendarScroller = $element[0].querySelector('.md-virtual-repeat-scroller');\n\n    /** @type {boolean} */\n    this.isInitialized = false;\n\n    /** @type {boolean} */\n    this.isMonthTransitionInProgress = false;\n\n    /** @final */\n    this.$mdUtil = $mdUtil;\n\n    var self = this;\n\n    /**\n     * Handles a click event on a date cell.\n     * Created here so that every cell can use the same function instance.\n     * @this {HTMLTableCellElement} The cell that was clicked.\n     */\n    this.cellClickHandler = function() {\n      self.onTimestampSelected($$mdDateUtil.getTimestampFromNode(this));\n    };\n  }\n\n  /**\n   * Initialize the controller by saving a reference to the calendar and\n   * setting up the object that will be iterated by the virtual repeater.\n   */\n  CalendarYearCtrl.prototype.initialize = function(calendarCtrl) {\n    /**\n     * Dummy array-like object for virtual-repeat to iterate over. The length is the total\n     * number of years that can be viewed. We add 1 extra in order to include the current year.\n     */\n\n    this.items = {\n      length: this.dateUtil.getYearDistance(\n        calendarCtrl.firstRenderableDate,\n        calendarCtrl.lastRenderableDate\n      ) + 1\n    };\n\n    this.calendarCtrl = calendarCtrl;\n    this.attachScopeListeners();\n    calendarCtrl.updateVirtualRepeat();\n\n    // Fire the initial render, since we might have missed it the first time it fired.\n    calendarCtrl.ngModelCtrl && calendarCtrl.ngModelCtrl.$render();\n  };\n\n  /**\n   * Gets the \"index\" of the currently selected date as it would be in the virtual-repeat.\n   * @returns {number}\n   */\n  CalendarYearCtrl.prototype.getFocusedYearIndex = function() {\n    var calendarCtrl = this.calendarCtrl;\n\n    return this.dateUtil.getYearDistance(\n      calendarCtrl.firstRenderableDate,\n      calendarCtrl.displayDate || calendarCtrl.selectedDate || calendarCtrl.today\n    );\n  };\n\n  /**\n   * Change the date that is highlighted in the calendar.\n   * @param {Date} date\n   */\n  CalendarYearCtrl.prototype.changeDate = function(date) {\n    // Initialization is deferred until this function is called because we want to reflect\n    // the starting value of ngModel.\n    if (!this.isInitialized) {\n      this.calendarCtrl.hideVerticalScrollbar(this);\n      this.isInitialized = true;\n      return this.$q.when();\n    } else if (this.dateUtil.isValidDate(date) && !this.isMonthTransitionInProgress) {\n      var self = this;\n      var animationPromise = this.animateDateChange(date);\n\n      self.isMonthTransitionInProgress = true;\n      self.calendarCtrl.displayDate = date;\n\n      return animationPromise.then(function() {\n        self.isMonthTransitionInProgress = false;\n      });\n    }\n  };\n\n  /**\n   * Animates the transition from the calendar's current month to the given month.\n   * @param {Date} date\n   * @returns {angular.$q.Promise} The animation promise.\n   */\n  CalendarYearCtrl.prototype.animateDateChange = function(date) {\n    if (this.dateUtil.isValidDate(date)) {\n      var monthDistance = this.dateUtil.getYearDistance(this.calendarCtrl.firstRenderableDate, date);\n      this.calendarScroller.scrollTop = monthDistance * TBODY_HEIGHT;\n    }\n\n    return this.$q.when();\n  };\n\n  /**\n   * Handles the year-view-specific keyboard interactions.\n   * @param {Object} event Scope event object passed by the calendar.\n   * @param {String} action Action, corresponding to the key that was pressed.\n   */\n  CalendarYearCtrl.prototype.handleKeyEvent = function(event, action) {\n    var self = this;\n    var calendarCtrl = self.calendarCtrl;\n    var displayDate = calendarCtrl.displayDate;\n\n    if (action === 'select') {\n      self.changeDate(displayDate).then(function() {\n        self.onTimestampSelected(displayDate);\n      });\n    } else {\n      var date = null;\n      var dateUtil = self.dateUtil;\n\n      switch (action) {\n        case 'move-right': date = dateUtil.incrementMonths(displayDate, 1); break;\n        case 'move-left': date = dateUtil.incrementMonths(displayDate, -1); break;\n\n        case 'move-row-down': date = dateUtil.incrementMonths(displayDate, 6); break;\n        case 'move-row-up': date = dateUtil.incrementMonths(displayDate, -6); break;\n      }\n\n      if (date) {\n        var min = calendarCtrl.minDate ? dateUtil.getFirstDateOfMonth(calendarCtrl.minDate) : null;\n        var max = calendarCtrl.maxDate ? dateUtil.getFirstDateOfMonth(calendarCtrl.maxDate) : null;\n        date = dateUtil.getFirstDateOfMonth(self.dateUtil.clampDate(date, min, max));\n\n        self.changeDate(date).then(function() {\n          calendarCtrl.focusDate(date);\n        });\n      }\n    }\n  };\n\n  /**\n   * Attaches listeners for the scope events that are broadcast by the calendar.\n   */\n  CalendarYearCtrl.prototype.attachScopeListeners = function() {\n    var self = this;\n\n    self.$scope.$on('md-calendar-parent-changed', function(event, value) {\n      self.calendarCtrl.changeSelectedDate(value ? self.dateUtil.getFirstDateOfMonth(value) : value);\n      self.changeDate(value);\n    });\n\n    self.$scope.$on('md-calendar-parent-action', angular.bind(self, self.handleKeyEvent));\n  };\n\n  /**\n   * Handles the behavior when a date is selected. Depending on the `mode`\n   * of the calendar, this can either switch back to the calendar view or\n   * set the model value.\n   * @param {number} timestamp The selected timestamp.\n   */\n  CalendarYearCtrl.prototype.onTimestampSelected = function(timestamp) {\n    var calendarCtrl = this.calendarCtrl;\n\n    if (calendarCtrl.mode) {\n      this.$mdUtil.nextTick(function() {\n        // The timestamp has to be converted to a valid date.\n        calendarCtrl.setNgModelValue(new Date(timestamp));\n      });\n    } else {\n      calendarCtrl.setCurrentView('month', timestamp);\n    }\n  };\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  CalendarYearBodyCtrl.$inject = [\"$element\", \"$$mdDateUtil\", \"$mdDateLocale\"];\n  angular.module('material.components.datepicker')\n      .directive('mdCalendarYearBody', mdCalendarYearDirective);\n\n  /**\n   * Private component, consumed by the md-calendar-year, which separates the DOM construction logic\n   * and allows for the year view to use md-virtual-repeat.\n   */\n  function mdCalendarYearDirective() {\n    return {\n      require: ['^^mdCalendar', '^^mdCalendarYear', 'mdCalendarYearBody'],\n      scope: { offset: '=mdYearOffset' },\n      controller: CalendarYearBodyCtrl,\n      controllerAs: 'mdYearBodyCtrl',\n      bindToController: true,\n      link: function(scope, element, attrs, controllers) {\n        var calendarCtrl = controllers[0];\n        var yearCtrl = controllers[1];\n        var yearBodyCtrl = controllers[2];\n\n        yearBodyCtrl.calendarCtrl = calendarCtrl;\n        yearBodyCtrl.yearCtrl = yearCtrl;\n\n        scope.$watch(function() { return yearBodyCtrl.offset; }, function(offset) {\n          if (angular.isNumber(offset)) {\n            yearBodyCtrl.generateContent();\n          }\n        });\n      }\n    };\n  }\n\n  /**\n   * Controller for a single year.\n   * @ngInject @constructor\n   */\n  function CalendarYearBodyCtrl($element, $$mdDateUtil, $mdDateLocale) {\n    /**\n     * @final\n     * @type {!JQLite}\n     */\n    this.$element = $element;\n\n    /** @final */\n    this.dateUtil = $$mdDateUtil;\n\n    /** @final */\n    this.dateLocale = $mdDateLocale;\n\n    /** @type {Object} Reference to the calendar. */\n    this.calendarCtrl = null;\n\n    /** @type {Object} Reference to the year view. */\n    this.yearCtrl = null;\n\n    /**\n     * Number of months from the start of the month \"items\" that the currently rendered month\n     * occurs. Set via angular data binding.\n     * @type {number|null}\n     */\n    this.offset = null;\n\n    /**\n     * Date cell to focus after appending the month to the document.\n     * @type {HTMLElement}\n     */\n    this.focusAfterAppend = null;\n  }\n\n  /** Generate and append the content for this year to the directive element. */\n  CalendarYearBodyCtrl.prototype.generateContent = function() {\n    var date = this.dateUtil.incrementYears(this.calendarCtrl.firstRenderableDate, this.offset);\n\n    this.$element\n      .empty()\n      .append(this.buildCalendarForYear(date));\n\n    if (this.focusAfterAppend) {\n      this.focusAfterAppend.classList.add(this.calendarCtrl.FOCUSED_DATE_CLASS);\n      this.focusAfterAppend = null;\n    }\n  };\n\n  /**\n   * Creates a single cell to contain a year in the calendar.\n   * @param {number} year Four-digit year.\n   * @param {number} month Zero-indexed month.\n   * @returns {HTMLElement}\n   */\n  CalendarYearBodyCtrl.prototype.buildMonthCell = function(year, month) {\n    var calendarCtrl = this.calendarCtrl;\n    var yearCtrl = this.yearCtrl;\n    var cell = this.buildBlankCell();\n\n    // Represent this month/year as a date.\n    var firstOfMonth = new Date(year, month, 1);\n    cell.setAttribute('aria-label', this.dateLocale.monthFormatter(firstOfMonth));\n    cell.id = calendarCtrl.getDateId(firstOfMonth, 'year');\n\n    // Use `data-timestamp` attribute because IE10 does not support the `dataset` property.\n    cell.setAttribute('data-timestamp', String(firstOfMonth.getTime()));\n\n    if (this.dateUtil.isSameMonthAndYear(firstOfMonth, calendarCtrl.today)) {\n      cell.classList.add(calendarCtrl.TODAY_CLASS);\n    }\n\n    if (this.dateUtil.isValidDate(calendarCtrl.selectedDate) &&\n        this.dateUtil.isSameMonthAndYear(firstOfMonth, calendarCtrl.selectedDate)) {\n      cell.classList.add(calendarCtrl.SELECTED_DATE_CLASS);\n      cell.setAttribute('aria-selected', 'true');\n    }\n\n    var cellText = this.dateLocale.shortMonths[month];\n\n    if (this.dateUtil.isMonthWithinRange(\n          firstOfMonth, calendarCtrl.minDate, calendarCtrl.maxDate) &&\n      (!angular.isFunction(calendarCtrl.monthFilter) ||\n        calendarCtrl.monthFilter(firstOfMonth))) {\n      var selectionIndicator = document.createElement('span');\n      selectionIndicator.classList.add('md-calendar-date-selection-indicator');\n      selectionIndicator.textContent = cellText;\n      cell.appendChild(selectionIndicator);\n      cell.addEventListener('click', yearCtrl.cellClickHandler);\n\n      if (calendarCtrl.displayDate &&\n          this.dateUtil.isSameMonthAndYear(firstOfMonth, calendarCtrl.displayDate)) {\n        this.focusAfterAppend = cell;\n      }\n    } else {\n      cell.classList.add('md-calendar-date-disabled');\n      cell.textContent = cellText;\n    }\n\n    return cell;\n  };\n\n  /**\n   * Builds a blank cell.\n   * @return {HTMLElement}\n   */\n  CalendarYearBodyCtrl.prototype.buildBlankCell = function() {\n    var cell = document.createElement('td');\n    cell.tabIndex = -1;\n    cell.classList.add('md-calendar-date');\n    cell.setAttribute('role', 'gridcell');\n\n    cell.setAttribute('tabindex', '-1');\n    return cell;\n  };\n\n  /**\n   * Builds the <tbody> content for the given year.\n   * @param {Date} date Date for which the content should be built.\n   * @returns {DocumentFragment} A document fragment containing the months within the year.\n   */\n  CalendarYearBodyCtrl.prototype.buildCalendarForYear = function(date) {\n    // Store rows for the month in a document fragment so that we can append them all at once.\n    var year = date.getFullYear();\n    var yearBody = document.createDocumentFragment();\n\n    var monthCell, i;\n    // First row contains label and Jan-Jun.\n    var firstRow = document.createElement('tr');\n    var labelCell = document.createElement('td');\n    labelCell.className = 'md-calendar-month-label';\n    labelCell.textContent = String(year);\n    firstRow.appendChild(labelCell);\n\n    for (i = 0; i < 6; i++) {\n      firstRow.appendChild(this.buildMonthCell(year, i));\n    }\n    yearBody.appendChild(firstRow);\n\n    // Second row contains a blank cell and Jul-Dec.\n    var secondRow = document.createElement('tr');\n    secondRow.appendChild(this.buildBlankCell());\n    for (i = 6; i < 12; i++) {\n      secondRow.appendChild(this.buildMonthCell(year, i));\n    }\n    yearBody.appendChild(secondRow);\n\n    return yearBody;\n  };\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  /**\n   * @ngdoc service\n   * @name $mdDateLocaleProvider\n   * @module material.components.datepicker\n   *\n   * @description\n   * The `$mdDateLocaleProvider` is the provider that creates the `$mdDateLocale` service.\n   * This provider that allows the user to specify messages, formatters, and parsers for date\n   * internationalization. The `$mdDateLocale` service itself is consumed by AngularJS Material\n   * components that deal with dates\n   * (i.e. <a ng-href=\"api/directive/mdDatepicker\">mdDatepicker</a>).\n   *\n   * @property {Array<string>} months Array of month names (in order).\n   * @property {Array<string>} shortMonths Array of abbreviated month names.\n   * @property {Array<string>} days Array of the days of the week (in order).\n   * @property {Array<string>} shortDays Array of abbreviated days of the week.\n   * @property {Array<string>} dates Array of dates of the month. Only necessary for locales\n   *  using a numeral system other than [1, 2, 3...].\n   * @property {Array<string>} firstDayOfWeek The first day of the week. Sunday = 0, Monday = 1,\n   *  etc.\n   * @property {function(string): Date} parseDate Function that converts a date string to a Date\n   *  object (the date portion).\n   * @property {function(Date, string): string} formatDate Function to format a date object to a\n   *  string. The datepicker directive also provides the time zone, if it was specified.\n   * @property {function(Date): string} monthHeaderFormatter Function that returns the label for\n   *  a month given a date.\n   * @property {function(Date): string} monthFormatter Function that returns the full name of a month\n   *  for a given date.\n   * @property {function(number): string} weekNumberFormatter Function that returns a label for\n   *  a week given the week number.\n   * @property {function(Date): string} longDateFormatter Function that formats a date into a long\n   *  `aria-label` that is read by the screen reader when the focused date changes.\n   * @property {string} msgCalendar Translation of the label \"Calendar\" for the current locale.\n   * @property {string} msgOpenCalendar Translation of the button label \"Open calendar\" for the\n   *  current locale.\n   * @property {Date} firstRenderableDate The date from which the datepicker calendar will begin\n   *  rendering. Note that this will be ignored if a minimum date is set.\n   *  Defaults to January 1st 1880.\n   * @property {Date} lastRenderableDate The last date that will be rendered by the datepicker\n   *  calendar. Note that this will be ignored if a maximum date is set.\n   *  Defaults to January 1st 2130.\n   * @property {function(string): boolean} isDateComplete Function to determine whether a string\n   *  makes sense to be parsed to a `Date` object. Returns `true` if the date appears to be complete\n   *  and parsing should occur. By default, this checks for 3 groups of text or numbers separated\n   *  by delimiters. This means that by default, date strings must include a month, day, and year\n   *  to be parsed and for the model to be updated.\n   *\n   * @usage\n   * <hljs lang=\"js\">\n   * myAppModule.config(function($mdDateLocaleProvider) {\n   *\n   *     // Example of a French localization.\n   *     $mdDateLocaleProvider.months = ['janvier', 'février', 'mars', ...];\n   *     $mdDateLocaleProvider.shortMonths = ['janv', 'févr', 'mars', ...];\n   *     $mdDateLocaleProvider.days = ['dimanche', 'lundi', 'mardi', ...];\n   *     $mdDateLocaleProvider.shortDays = ['Di', 'Lu', 'Ma', ...];\n   *\n   *     // Can change week display to start on Monday.\n   *     $mdDateLocaleProvider.firstDayOfWeek = 1;\n   *\n   *     // Optional.\n   *     $mdDateLocaleProvider.dates = [1, 2, 3, 4, 5, 6, ...];\n   *\n   *     // Example uses moment.js to parse and format dates.\n   *     $mdDateLocaleProvider.parseDate = function(dateString) {\n   *       var m = moment(dateString, 'L', true);\n   *       return m.isValid() ? m.toDate() : new Date(NaN);\n   *     };\n   *\n   *     $mdDateLocaleProvider.formatDate = function(date) {\n   *       var m = moment(date);\n   *       return m.isValid() ? m.format('L') : '';\n   *     };\n   *\n   *     // Allow only a day and month to be specified.\n   *     // This is required if using the 'M/D' format with moment.js.\n   *     $mdDateLocaleProvider.isDateComplete = function(dateString) {\n   *       dateString = dateString.trim();\n   *\n   *       // Look for two chunks of content (either numbers or text) separated by delimiters.\n   *       var re = /^(([a-zA-Z]{3,}|[0-9]{1,4})([ .,]+|[/-]))([a-zA-Z]{3,}|[0-9]{1,4})/;\n   *       return re.test(dateString);\n   *     };\n   *\n   *     $mdDateLocaleProvider.monthHeaderFormatter = function(date) {\n   *       return myShortMonths[date.getMonth()] + ' ' + date.getFullYear();\n   *     };\n   *\n   *     // In addition to date display, date components also need localized messages\n   *     // for aria-labels for screen-reader users.\n   *\n   *     $mdDateLocaleProvider.weekNumberFormatter = function(weekNumber) {\n   *       return 'Semaine ' + weekNumber;\n   *     };\n   *\n   *     $mdDateLocaleProvider.msgCalendar = 'Calendrier';\n   *     $mdDateLocaleProvider.msgOpenCalendar = 'Ouvrir le calendrier';\n   *\n   *     // You can also set when your calendar begins and ends.\n   *     $mdDateLocaleProvider.firstRenderableDate = new Date(1776, 6, 4);\n   *     $mdDateLocaleProvider.lastRenderableDate = new Date(2012, 11, 21);\n   * });\n   * </hljs>\n   *\n   */\n  angular.module('material.components.datepicker').config([\"$provide\", function($provide) {\n    // TODO(jelbourn): Assert provided values are correctly formatted. Need assertions.\n\n    /** @constructor */\n    function DateLocaleProvider() {\n      /** Array of full month names. E.g., ['January', 'February', ...] */\n      this.months = null;\n\n      /** Array of abbreviated month names. E.g., ['Jan', 'Feb', ...] */\n      this.shortMonths = null;\n\n      /** Array of full day of the week names. E.g., ['Monday', 'Tuesday', ...] */\n      this.days = null;\n\n      /** Array of abbreviated dat of the week names. E.g., ['M', 'T', ...] */\n      this.shortDays = null;\n\n      /** Array of dates of a month (1 - 31). Characters might be different in some locales. */\n      this.dates = null;\n\n      /** Index of the first day of the week. 0 = Sunday, 1 = Monday, etc. */\n      this.firstDayOfWeek = 0;\n\n      /**\n       * Function that converts the date portion of a Date to a string.\n       * @type {(function(Date): string)}\n       */\n      this.formatDate = null;\n\n      /**\n       * Function that converts a date string to a Date object (the date portion)\n       * @type {function(string): Date}\n       */\n      this.parseDate = null;\n\n      /**\n       * Function that formats a Date into a month header string.\n       * @type {function(Date): string}\n       */\n      this.monthHeaderFormatter = null;\n\n      /**\n       * Function that formats a week number into a label for the week.\n       * @type {function(number): string}\n       */\n      this.weekNumberFormatter = null;\n\n      /**\n       * Function that formats a date into a long aria-label that is read\n       * when the focused date changes.\n       * @type {function(Date): string}\n       */\n      this.longDateFormatter = null;\n\n      /**\n       * Function to determine whether a string makes sense to be\n       * parsed to a Date object.\n       * @type {function(string): boolean}\n       */\n      this.isDateComplete = null;\n\n      /**\n       * ARIA label for the calendar \"dialog\" used in the datepicker.\n       * @type {string}\n       */\n      this.msgCalendar = '';\n\n      /**\n       * ARIA label for the datepicker's \"Open calendar\" buttons.\n       * @type {string}\n       */\n      this.msgOpenCalendar = '';\n    }\n\n    /**\n     * Factory function that returns an instance of the dateLocale service.\n     * @ngInject\n     * @param $locale\n     * @param $filter\n     * @returns {DateLocale}\n     */\n    DateLocaleProvider.prototype.$get = function($locale, $filter) {\n      /**\n       * Default date-to-string formatting function.\n       * @param {!Date} date\n       * @param {string=} timezone\n       * @returns {string}\n       */\n      function defaultFormatDate(date, timezone) {\n        if (!date) {\n          return '';\n        }\n\n        // All of the dates created through ng-material *should* be set to midnight.\n        // If we encounter a date where the localeTime shows at 11pm instead of midnight,\n        // we have run into an issue with DST where we need to increment the hour by one:\n        // var d = new Date(1992, 9, 8, 0, 0, 0);\n        // d.toLocaleString(); // == \"10/7/1992, 11:00:00 PM\"\n        var localeTime = date.toLocaleTimeString();\n        var formatDate = date;\n        if (date.getHours() === 0 &&\n            (localeTime.indexOf('11:') !== -1 || localeTime.indexOf('23:') !== -1)) {\n          formatDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 1, 0, 0);\n        }\n\n        return $filter('date')(formatDate, 'M/d/yyyy', timezone);\n      }\n\n      /**\n       * Default string-to-date parsing function.\n       * @param {string|number} dateString\n       * @returns {!Date}\n       */\n      function defaultParseDate(dateString) {\n        return new Date(dateString);\n      }\n\n      /**\n       * Default function to determine whether a string makes sense to be\n       * parsed to a Date object.\n       *\n       * This is very permissive and is just a basic check to ensure that\n       * things like single integers aren't able to be parsed into dates.\n       * @param {string} dateString\n       * @returns {boolean}\n       */\n      function defaultIsDateComplete(dateString) {\n        dateString = dateString.trim();\n\n        // Looks for three chunks of content (either numbers or text) separated\n        // by delimiters.\n        var re = /^(([a-zA-Z]{3,}|[0-9]{1,4})([ .,]+|[/-])){2}([a-zA-Z]{3,}|[0-9]{1,4})$/;\n        return re.test(dateString);\n      }\n\n      /**\n       * Default date-to-string formatter to get a month header.\n       * @param {!Date} date\n       * @returns {string}\n       */\n      function defaultMonthHeaderFormatter(date) {\n        return service.shortMonths[date.getMonth()] + ' ' + date.getFullYear();\n      }\n\n      /**\n       * Default formatter for a month.\n       * @param {!Date} date\n       * @returns {string}\n       */\n      function defaultMonthFormatter(date) {\n        return service.months[date.getMonth()] + ' ' + date.getFullYear();\n      }\n\n      /**\n       * Default week number formatter.\n       * @param number\n       * @returns {string}\n       */\n      function defaultWeekNumberFormatter(number) {\n        return 'Week ' + number;\n      }\n\n      /**\n       * Default formatter for date cell aria-labels.\n       * @param {!Date} date\n       * @returns {string}\n       */\n      function defaultLongDateFormatter(date) {\n        // Example: 'Thursday June 18 2015'\n        return [\n          service.days[date.getDay()],\n          service.months[date.getMonth()],\n          service.dates[date.getDate()],\n          date.getFullYear()\n        ].join(' ');\n      }\n\n      // The default \"short\" day strings are the first character of each day,\n      // e.g., \"Monday\" => \"M\".\n      var defaultShortDays = $locale.DATETIME_FORMATS.SHORTDAY.map(function(day) {\n        return day.substring(0, 1);\n      });\n\n      // The default dates are simply the numbers 1 through 31.\n      var defaultDates = Array(32);\n      for (var i = 1; i <= 31; i++) {\n        defaultDates[i] = i;\n      }\n\n      // Default ARIA messages are in English (US).\n      var defaultMsgCalendar = 'Calendar';\n      var defaultMsgOpenCalendar = 'Open calendar';\n\n      // Default start/end dates that are rendered in the calendar.\n      var defaultFirstRenderableDate = new Date(1880, 0, 1);\n      var defaultLastRendereableDate = new Date(defaultFirstRenderableDate.getFullYear() + 250, 0, 1);\n\n      var service = {\n        months: this.months || $locale.DATETIME_FORMATS.MONTH,\n        shortMonths: this.shortMonths || $locale.DATETIME_FORMATS.SHORTMONTH,\n        days: this.days || $locale.DATETIME_FORMATS.DAY,\n        shortDays: this.shortDays || defaultShortDays,\n        dates: this.dates || defaultDates,\n        firstDayOfWeek: this.firstDayOfWeek || 0,\n        formatDate: this.formatDate || defaultFormatDate,\n        parseDate: this.parseDate || defaultParseDate,\n        isDateComplete: this.isDateComplete || defaultIsDateComplete,\n        monthHeaderFormatter: this.monthHeaderFormatter || defaultMonthHeaderFormatter,\n        monthFormatter: this.monthFormatter || defaultMonthFormatter,\n        weekNumberFormatter: this.weekNumberFormatter || defaultWeekNumberFormatter,\n        longDateFormatter: this.longDateFormatter || defaultLongDateFormatter,\n        msgCalendar: this.msgCalendar || defaultMsgCalendar,\n        msgOpenCalendar: this.msgOpenCalendar || defaultMsgOpenCalendar,\n        firstRenderableDate: this.firstRenderableDate || defaultFirstRenderableDate,\n        lastRenderableDate: this.lastRenderableDate || defaultLastRendereableDate\n      };\n\n      return service;\n    };\n    DateLocaleProvider.prototype.$get.$inject = [\"$locale\", \"$filter\"];\n\n    $provide.provider('$mdDateLocale', new DateLocaleProvider());\n  }]);\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  /**\n   * Utility for performing date calculations to facilitate operation of the calendar and\n   * datepicker.\n   */\n  angular.module('material.components.datepicker').factory('$$mdDateUtil', [\"$mdDateLocale\", function($mdDateLocale) {\n    return {\n      getFirstDateOfMonth: getFirstDateOfMonth,\n      getNumberOfDaysInMonth: getNumberOfDaysInMonth,\n      getDateInNextMonth: getDateInNextMonth,\n      getDateInPreviousMonth: getDateInPreviousMonth,\n      isInNextMonth: isInNextMonth,\n      isInPreviousMonth: isInPreviousMonth,\n      getDateMidpoint: getDateMidpoint,\n      isSameMonthAndYear: isSameMonthAndYear,\n      getWeekOfMonth: getWeekOfMonth,\n      incrementDays: incrementDays,\n      incrementMonths: incrementMonths,\n      getLastDateOfMonth: getLastDateOfMonth,\n      isSameDay: isSameDay,\n      getMonthDistance: getMonthDistance,\n      isValidDate: isValidDate,\n      setDateTimeToMidnight: setDateTimeToMidnight,\n      createDateAtMidnight: createDateAtMidnight,\n      isDateWithinRange: isDateWithinRange,\n      incrementYears: incrementYears,\n      getYearDistance: getYearDistance,\n      clampDate: clampDate,\n      getTimestampFromNode: getTimestampFromNode,\n      isMonthWithinRange: isMonthWithinRange,\n      removeLocalTzAndReparseDate: removeLocalTzAndReparseDate\n    };\n\n    /**\n     * Gets the first day of the month for the given date's month.\n     * @param {Date} date\n     * @returns {Date}\n     */\n    function getFirstDateOfMonth(date) {\n      return new Date(date.getFullYear(), date.getMonth(), 1);\n    }\n\n    /**\n     * Gets the number of days in the month for the given date's month.\n     * @param date\n     * @returns {number}\n     */\n    function getNumberOfDaysInMonth(date) {\n      return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();\n    }\n\n    /**\n     * Get an arbitrary date in the month after the given date's month.\n     * @param date\n     * @returns {Date}\n     */\n    function getDateInNextMonth(date) {\n      return new Date(date.getFullYear(), date.getMonth() + 1, 1);\n    }\n\n    /**\n     * Get an arbitrary date in the month before the given date's month.\n     * @param date\n     * @returns {Date}\n     */\n    function getDateInPreviousMonth(date) {\n      return new Date(date.getFullYear(), date.getMonth() - 1, 1);\n    }\n\n    /**\n     * Gets whether two dates have the same month and year.\n     * @param {Date} d1\n     * @param {Date} d2\n     * @returns {boolean}\n     */\n    function isSameMonthAndYear(d1, d2) {\n      return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth();\n    }\n\n    /**\n     * Gets whether two dates are the same day (not not necessarily the same time).\n     * @param {Date} d1\n     * @param {Date} d2\n     * @returns {boolean}\n     */\n    function isSameDay(d1, d2) {\n      return d1.getDate() == d2.getDate() && isSameMonthAndYear(d1, d2);\n    }\n\n    /**\n     * Gets whether a date is in the month immediately after some date.\n     * @param {Date} startDate The date from which to compare.\n     * @param {Date} endDate The date to check.\n     * @returns {boolean}\n     */\n    function isInNextMonth(startDate, endDate) {\n      var nextMonth = getDateInNextMonth(startDate);\n      return isSameMonthAndYear(nextMonth, endDate);\n    }\n\n    /**\n     * Gets whether a date is in the month immediately before some date.\n     * @param {Date} startDate The date from which to compare.\n     * @param {Date} endDate The date to check.\n     * @returns {boolean}\n     */\n    function isInPreviousMonth(startDate, endDate) {\n      var previousMonth = getDateInPreviousMonth(startDate);\n      return isSameMonthAndYear(endDate, previousMonth);\n    }\n\n    /**\n     * Gets the midpoint between two dates.\n     * @param {Date} d1\n     * @param {Date} d2\n     * @returns {Date}\n     */\n    function getDateMidpoint(d1, d2) {\n      return createDateAtMidnight((d1.getTime() + d2.getTime()) / 2);\n    }\n\n    /**\n     * Gets the week of the month that a given date occurs in.\n     * @param {Date} date\n     * @returns {number} Index of the week of the month (zero-based).\n     */\n    function getWeekOfMonth(date) {\n      var firstDayOfMonth = getFirstDateOfMonth(date);\n      return Math.floor((firstDayOfMonth.getDay() + date.getDate() - 1) / 7);\n    }\n\n    /**\n     * Gets a new date incremented by the given number of days. Number of days can be negative.\n     * @param {Date} date\n     * @param {number} numberOfDays\n     * @returns {Date}\n     */\n    function incrementDays(date, numberOfDays) {\n      return new Date(date.getFullYear(), date.getMonth(), date.getDate() + numberOfDays);\n    }\n\n    /**\n     * Gets a new date incremented by the given number of months. Number of months can be negative.\n     * If the date of the given month does not match the target month, the date will be set to the\n     * last day of the month.\n     * @param {Date} date\n     * @param {number} numberOfMonths\n     * @returns {Date}\n     */\n    function incrementMonths(date, numberOfMonths) {\n      // If the same date in the target month does not actually exist, the Date object will\n      // automatically advance *another* month by the number of missing days.\n      // For example, if you try to go from Jan. 30 to Feb. 30, you'll end up on March 2.\n      // So, we check if the month overflowed and go to the last day of the target month instead.\n      var dateInTargetMonth = new Date(date.getFullYear(), date.getMonth() + numberOfMonths, 1);\n      var numberOfDaysInMonth = getNumberOfDaysInMonth(dateInTargetMonth);\n      if (numberOfDaysInMonth < date.getDate()) {\n        dateInTargetMonth.setDate(numberOfDaysInMonth);\n      } else {\n        dateInTargetMonth.setDate(date.getDate());\n      }\n\n      return dateInTargetMonth;\n    }\n\n    /**\n     * Get the integer distance between two months. This *only* considers the month and year\n     * portion of the Date instances.\n     *\n     * @param {Date} start\n     * @param {Date} end\n     * @returns {number} Number of months between `start` and `end`. If `end` is before `start`\n     *     chronologically, this number will be negative.\n     */\n    function getMonthDistance(start, end) {\n      return (12 * (end.getFullYear() - start.getFullYear())) + (end.getMonth() - start.getMonth());\n    }\n\n    /**\n     * Gets the last day of the month for the given date.\n     * @param {Date} date\n     * @returns {Date}\n     */\n    function getLastDateOfMonth(date) {\n      return new Date(date.getFullYear(), date.getMonth(), getNumberOfDaysInMonth(date));\n    }\n\n    /**\n     * Checks whether a date is valid.\n     * @param {Date} date\n     * @return {boolean} Whether the date is a valid Date.\n     */\n    function isValidDate(date) {\n      return date && date.getTime && !isNaN(date.getTime());\n    }\n\n    /**\n     * Sets a date's time to midnight.\n     * @param {Date} date\n     */\n    function setDateTimeToMidnight(date) {\n      if (isValidDate(date)) {\n        date.setHours(0, 0, 0, 0);\n      }\n    }\n\n    /**\n     * Creates a date with the time set to midnight.\n     * Drop-in replacement for two forms of the Date constructor via opt_value.\n     * @param {number|Date=} opt_value Leave undefined for a Date representing now. Or use a\n     *  single value representing the number of seconds since the Unix Epoch or a Date object.\n     * @return {Date} New date with time set to midnight.\n     */\n    function createDateAtMidnight(opt_value) {\n      var date;\n      if (angular.isDate(opt_value)) {\n        date = opt_value;\n      } else if (angular.isNumber(opt_value)) {\n        date = new Date(opt_value);\n      } else {\n        date = new Date();\n      }\n      setDateTimeToMidnight(date);\n      return date;\n    }\n\n     /**\n      * Checks if a date is within a min and max range, ignoring the time component.\n      * If minDate or maxDate are not dates, they are ignored.\n      * @param {Date} date\n      * @param {Date} minDate\n      * @param {Date} maxDate\n      */\n     function isDateWithinRange(date, minDate, maxDate) {\n       var dateAtMidnight = createDateAtMidnight(date);\n       var minDateAtMidnight = isValidDate(minDate) ? createDateAtMidnight(minDate) : null;\n       var maxDateAtMidnight = isValidDate(maxDate) ? createDateAtMidnight(maxDate) : null;\n       return (!minDateAtMidnight || minDateAtMidnight <= dateAtMidnight) &&\n           (!maxDateAtMidnight || maxDateAtMidnight >= dateAtMidnight);\n     }\n\n    /**\n     * Gets a new date incremented by the given number of years. Number of years can be negative.\n     * See `incrementMonths` for notes on overflow for specific dates.\n     * @param {Date} date\n     * @param {number} numberOfYears\n     * @returns {Date}\n     */\n     function incrementYears(date, numberOfYears) {\n       return incrementMonths(date, numberOfYears * 12);\n     }\n\n     /**\n      * Get the integer distance between two years. This *only* considers the year portion of the\n      * Date instances.\n      *\n      * @param {Date} start\n      * @param {Date} end\n      * @returns {number} Number of months between `start` and `end`. If `end` is before `start`\n      *     chronologically, this number will be negative.\n      */\n     function getYearDistance(start, end) {\n       return end.getFullYear() - start.getFullYear();\n     }\n\n     /**\n      * Clamps a date between a minimum and a maximum date.\n      * @param {Date} date Date to be clamped\n      * @param {Date=} minDate Minimum date\n      * @param {Date=} maxDate Maximum date\n      * @return {Date}\n      */\n     function clampDate(date, minDate, maxDate) {\n       var boundDate = date;\n       if (minDate && date < minDate) {\n         boundDate = new Date(minDate.getTime());\n       }\n       if (maxDate && date > maxDate) {\n         boundDate = new Date(maxDate.getTime());\n       }\n       return boundDate;\n     }\n\n     /**\n      * Extracts and parses the timestamp from a DOM node.\n      * @param  {HTMLElement} node Node from which the timestamp will be extracted.\n      * @return {number} Time since epoch.\n      */\n     function getTimestampFromNode(node) {\n       if (node && node.hasAttribute('data-timestamp')) {\n         return Number(node.getAttribute('data-timestamp'));\n       }\n     }\n\n     /**\n      * Checks if a month is within a min and max range, ignoring the date and time components.\n      * If minDate or maxDate are not dates, they are ignored.\n      * @param {Date} date\n      * @param {Date} minDate\n      * @param {Date} maxDate\n      */\n     function isMonthWithinRange(date, minDate, maxDate) {\n       var month = date.getMonth();\n       var year = date.getFullYear();\n\n       return (!minDate || minDate.getFullYear() < year || minDate.getMonth() <= month) &&\n        (!maxDate || maxDate.getFullYear() > year || maxDate.getMonth() >= month);\n     }\n\n    /**\n     * @param {Date} value date in local timezone\n     * @return {Date} date with local timezone offset removed\n     */\n    function removeLocalTzAndReparseDate(value) {\n      var dateValue, formattedDate;\n      // Remove the local timezone offset before calling formatDate.\n      dateValue = new Date(value.getTime() + 60000 * value.getTimezoneOffset());\n      formattedDate = $mdDateLocale.formatDate(dateValue);\n      // parseDate only works with a date formatted by formatDate when using Moment validation.\n      return $mdDateLocale.parseDate(formattedDate);\n    }\n  }]);\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  // TODO(jelbourn): forward more attributes to the internal input (required, autofocus, etc.)\n  // TODO(jelbourn): something better for mobile (calendar panel takes up entire screen?)\n  // TODO(jelbourn): input behavior (masking? auto-complete?)\n\n  DatePickerCtrl.$inject = [\"$scope\", \"$element\", \"$attrs\", \"$window\", \"$mdConstant\", \"$mdTheming\", \"$mdUtil\", \"$mdDateLocale\", \"$$mdDateUtil\", \"$$rAF\", \"$filter\", \"$timeout\"];\n  datePickerDirective.$inject = [\"$$mdSvgRegistry\", \"$mdUtil\", \"$mdAria\", \"inputDirective\"];\n  angular.module('material.components.datepicker')\n      .directive('mdDatepicker', datePickerDirective);\n\n  /**\n   * @ngdoc directive\n   * @name mdDatepicker\n   * @module material.components.datepicker\n   *\n   * @param {Date} ng-model The component's model. Expects either a JavaScript Date object or a\n   *  value that can be parsed into one (e.g. a ISO 8601 string).\n   * @param {Object=} ng-model-options Allows tuning of the way in which `ng-model` is being\n   *  updated. Also allows for a timezone to be specified.\n   *  <a href=\"https://docs.angularjs.org/api/ng/directive/ngModelOptions#usage\">\n   *    Read more at the ngModelOptions docs.</a>\n   * @param {expression=} ng-change Expression evaluated when the model value changes.\n   * @param {expression=} ng-focus Expression evaluated when the input is focused or the calendar\n   *  is opened.\n   * @param {expression=} ng-blur Expression evaluated when focus is removed from the input or the\n   *  calendar is closed.\n   * @param {boolean=} ng-disabled Whether the datepicker is disabled.\n   * @param {boolean=} ng-required Whether a value is required for the datepicker.\n   * @param {Date=} md-min-date Expression representing a min date (inclusive).\n   * @param {Date=} md-max-date Expression representing a max date (inclusive).\n   * @param {(function(Date): boolean)=} md-date-filter Function expecting a date and returning a\n   *  boolean whether it can be selected in \"day\" mode or not. Returning false will also trigger a\n   *  `filtered` model validation error.\n   * @param {(function(Date): boolean)=} md-month-filter Function expecting a date and returning a\n   *  boolean whether it can be selected in \"month\" mode or not. Returning false will also trigger a\n   *  `filtered` model validation error.\n   * @param {string=} md-placeholder The date input placeholder value.\n   * @param {string=} md-open-on-focus When present, the calendar will be opened when the input\n   *  is focused.\n   * @param {Boolean=} md-is-open Expression that can be used to open the datepicker's calendar\n   *  on-demand.\n   * @param {string=} md-current-view Default open view of the calendar pane. Can be either\n   *  \"month\" or \"year\".\n   * @param {string=} md-mode Restricts the user to only selecting a value from a particular view.\n   *  This option can be used if the user is only supposed to choose from a certain date type\n   *  (e.g. only selecting the month).\n   * Can be either \"month\" or \"day\". **Note** that this will overwrite the `md-current-view` value.\n   * @param {string=} md-hide-icons Determines which datepicker icons should be hidden. Note that\n   *  this may cause the datepicker to not align properly with other components.\n   *  **Use at your own risk.** Possible values are:\n   * * `\"all\"` - Hides all icons.\n   * * `\"calendar\"` - Only hides the calendar icon.\n   * * `\"triangle\"` - Only hides the triangle icon.\n   * @param {Object=} md-date-locale Allows for the values from the `$mdDateLocaleProvider` to be\n   * overwritten on a per-element basis (e.g. `msgOpenCalendar` can be overwritten with\n   * `md-date-locale=\"{ msgOpenCalendar: 'Open a special calendar' }\"`).\n   * @param {string=} input-aria-describedby A space-separated list of element IDs. This should\n   *  contain the IDs of any elements that describe this datepicker. Screen readers will read the\n   *  content of these elements at the end of announcing that the datepicker has been selected\n   *  and describing its current state. The descriptive elements do not need to be visible on the\n   *  page.\n   * @param {string=} input-aria-labelledby A space-separated list of element IDs. The ideal use\n   *  case is that this would contain the ID of a `<label>` element should be associated with this\n   *  datepicker. This is necessary when using `md-datepicker` inside of an `md-input-container`\n   *  with a `<label>`.<br><br>\n   *  For `<label id=\"start-date\">Start Date</label>`, you would set this to\n   *  `input-aria-labelledby=\"start-date\"`.\n   *\n   * @description\n   * `<md-datepicker>` is a component used to select a single date.\n   * For information on how to configure internationalization for the date picker,\n   * see <a ng-href=\"api/service/$mdDateLocaleProvider\">$mdDateLocaleProvider</a>.\n   *\n   * This component supports\n   * [ngMessages](https://docs.angularjs.org/api/ngMessages/directive/ngMessages).\n   * Supported attributes are:\n   * * `required`: whether a required date is not set.\n   * * `mindate`: whether the selected date is before the minimum allowed date.\n   * * `maxdate`: whether the selected date is after the maximum allowed date.\n   * * `debounceInterval`: ms to delay input processing (since last debounce reset);\n   *    default value 500ms\n   *\n   * @usage\n   * <hljs lang=\"html\">\n   *   <md-datepicker ng-model=\"birthday\"></md-datepicker>\n   * </hljs>\n   *\n   */\n\n  function datePickerDirective($$mdSvgRegistry, $mdUtil, $mdAria, inputDirective) {\n    return {\n      template: function(tElement, tAttrs) {\n        // Buttons are not in the tab order because users can open the calendar via keyboard\n        // interaction on the text input, and multiple tab stops for one component (picker)\n        // may be confusing.\n        var hiddenIcons = tAttrs.mdHideIcons;\n        var inputAriaDescribedby = tAttrs.inputAriaDescribedby;\n        var inputAriaLabelledby = tAttrs.inputAriaLabelledby;\n        var ariaLabelValue = tAttrs.ariaLabel || tAttrs.mdPlaceholder;\n        var ngModelOptions = tAttrs.ngModelOptions;\n\n        var calendarButton = (hiddenIcons === 'all' || hiddenIcons === 'calendar') ? '' :\n          '<md-button class=\"md-datepicker-button md-icon-button\" type=\"button\" ' +\n              'tabindex=\"-1\" aria-hidden=\"true\" ' +\n              'ng-click=\"ctrl.openCalendarPane($event)\">' +\n            '<md-icon class=\"md-datepicker-calendar-icon\" aria-label=\"md-calendar\" ' +\n                     'md-svg-src=\"' + $$mdSvgRegistry.mdCalendar + '\"></md-icon>' +\n          '</md-button>';\n\n        var triangleButton = '';\n\n        if (hiddenIcons !== 'all' && hiddenIcons !== 'triangle') {\n          triangleButton = '' +\n            '<md-button type=\"button\" md-no-ink ' +\n              'class=\"md-datepicker-triangle-button md-icon-button\" ' +\n              'ng-click=\"ctrl.openCalendarPane($event)\" ' +\n              'aria-label=\"{{::ctrl.locale.msgOpenCalendar}}\">' +\n            '<div class=\"md-datepicker-expand-triangle\"></div>' +\n          '</md-button>';\n\n          tElement.addClass(HAS_TRIANGLE_ICON_CLASS);\n        }\n\n        return calendarButton +\n        '<div class=\"md-datepicker-input-container\" ng-class=\"{\\'md-datepicker-focused\\': ctrl.isFocused}\">' +\n          '<input ' +\n            (ariaLabelValue ? 'aria-label=\"' + ariaLabelValue + '\" ' : '') +\n            (inputAriaDescribedby ? 'aria-describedby=\"' + inputAriaDescribedby + '\" ' : '') +\n            (inputAriaLabelledby ? 'aria-labelledby=\"' + inputAriaLabelledby + '\" ' : '') +\n            'class=\"md-datepicker-input\" ' +\n            'aria-haspopup=\"dialog\" ' +\n            'ng-focus=\"ctrl.setFocused(true)\" ' +\n            'ng-blur=\"ctrl.setFocused(false)\"> ' +\n            triangleButton +\n        '</div>' +\n\n        // This pane will be detached from here and re-attached to the document body.\n        '<div class=\"md-datepicker-calendar-pane md-whiteframe-z1\" id=\"{{::ctrl.calendarPaneId}}\">' +\n          '<div class=\"md-datepicker-input-mask\">' +\n            '<div class=\"md-datepicker-input-mask-opaque\"></div>' +\n          '</div>' +\n          '<div class=\"md-datepicker-calendar\">' +\n            '<md-calendar role=\"dialog\" aria-label=\"{{::ctrl.locale.msgCalendar}}\" ' +\n                'md-current-view=\"{{::ctrl.currentView}}\" ' +\n                'md-mode=\"{{::ctrl.mode}}\" ' +\n                'md-min-date=\"ctrl.minDate\" ' +\n                'md-max-date=\"ctrl.maxDate\" ' +\n                'md-date-filter=\"ctrl.dateFilter\" ' +\n                'md-month-filter=\"ctrl.monthFilter\" ' +\n                (ngModelOptions ? 'ng-model-options=\"' + ngModelOptions + '\" ' : '') +\n                'ng-model=\"ctrl.date\" ng-if=\"ctrl.isCalendarOpen\">' +\n            '</md-calendar>' +\n          '</div>' +\n        '</div>';\n      },\n      require: ['ngModel', 'mdDatepicker', '?^mdInputContainer', '?^form'],\n      scope: {\n        minDate: '=mdMinDate',\n        maxDate: '=mdMaxDate',\n        placeholder: '@mdPlaceholder',\n        currentView: '@mdCurrentView',\n        mode: '@mdMode',\n        dateFilter: '=mdDateFilter',\n        monthFilter: '=mdMonthFilter',\n        isOpen: '=?mdIsOpen',\n        debounceInterval: '=mdDebounceInterval',\n        dateLocale: '=mdDateLocale'\n      },\n      controller: DatePickerCtrl,\n      controllerAs: 'ctrl',\n      bindToController: true,\n      link: function(scope, element, attr, controllers) {\n        var ngModelCtrl = controllers[0];\n        var mdDatePickerCtrl = controllers[1];\n        var mdInputContainer = controllers[2];\n        var parentForm = controllers[3];\n        var mdNoAsterisk = $mdUtil.parseAttributeBoolean(attr.mdNoAsterisk);\n\n        mdDatePickerCtrl.configureNgModel(ngModelCtrl, mdInputContainer, inputDirective);\n\n        if (mdInputContainer) {\n          // We need to move the spacer after the datepicker itself,\n          // because md-input-container adds it after the\n          // md-datepicker-input by default. The spacer gets wrapped in a\n          // div, because it floats and gets aligned next to the datepicker.\n          // There are easier ways of working around this with CSS (making the\n          // datepicker 100% wide, change the `display` etc.), however they\n          // break the alignment with any other form controls.\n          var spacer = element[0].querySelector('.md-errors-spacer');\n\n          if (spacer) {\n            element.after(angular.element('<div>').append(spacer));\n          }\n\n          mdInputContainer.setHasPlaceholder(attr.mdPlaceholder);\n          mdInputContainer.input = element;\n          mdInputContainer.element\n            .addClass(INPUT_CONTAINER_CLASS)\n            .toggleClass(HAS_CALENDAR_ICON_CLASS,\n              attr.mdHideIcons !== 'calendar' && attr.mdHideIcons !== 'all');\n\n          if (!mdInputContainer.label) {\n            $mdAria.expect(element, 'aria-label', attr.mdPlaceholder);\n          } else if (!mdNoAsterisk) {\n            attr.$observe('required', function(value) {\n              mdInputContainer.label.toggleClass('md-required', !!value);\n            });\n          }\n\n          scope.$watch(mdInputContainer.isErrorGetter || function() {\n            return ngModelCtrl.$invalid && (ngModelCtrl.$touched ||\n              (parentForm && parentForm.$submitted));\n          }, mdInputContainer.setInvalid);\n        } else if (parentForm) {\n          // If invalid, highlights the input when the parent form is submitted.\n          var parentSubmittedWatcher = scope.$watch(function() {\n            return parentForm.$submitted;\n          }, function(isSubmitted) {\n            if (isSubmitted) {\n              mdDatePickerCtrl.updateErrorState();\n              parentSubmittedWatcher();\n            }\n          });\n        }\n      }\n    };\n  }\n\n  /** Additional offset for the input's `size` attribute, which is updated based on its content. */\n  var EXTRA_INPUT_SIZE = 3;\n\n  /** Class applied to the container if the date is invalid. */\n  var INVALID_CLASS = 'md-datepicker-invalid';\n\n  /** Class applied to the datepicker when it's open. */\n  var OPEN_CLASS = 'md-datepicker-open';\n\n  /** Class applied to the md-input-container, if a datepicker is placed inside it */\n  var INPUT_CONTAINER_CLASS = '_md-datepicker-floating-label';\n\n  /** Class to be applied when the calendar icon is enabled. */\n  var HAS_CALENDAR_ICON_CLASS = '_md-datepicker-has-calendar-icon';\n\n  /** Class to be applied when the triangle icon is enabled. */\n  var HAS_TRIANGLE_ICON_CLASS = '_md-datepicker-has-triangle-icon';\n\n  /** Default time in ms to debounce input event by. */\n  var DEFAULT_DEBOUNCE_INTERVAL = 500;\n\n  /**\n   * Height of the calendar pane used to check if the pane is going outside the boundary of\n   * the viewport. See calendar.scss for how $md-calendar-height is computed; an extra 20px is\n   * also added to space the pane away from the exact edge of the screen.\n   *\n   *  This is computed statically now, but can be changed to be measured if the circumstances\n   *  of calendar sizing are changed.\n   */\n  var CALENDAR_PANE_HEIGHT = 368;\n\n  /**\n   * Width of the calendar pane used to check if the pane is going outside the boundary of\n   * the viewport. See calendar.scss for how $md-calendar-width is computed; an extra 20px is\n   * also added to space the pane away from the exact edge of the screen.\n   *\n   *  This is computed statically now, but can be changed to be measured if the circumstances\n   *  of calendar sizing are changed.\n   */\n  var CALENDAR_PANE_WIDTH = 360;\n\n  /** Used for checking whether the current user agent is on iOS or Android. */\n  var IS_MOBILE_REGEX = /ipad|iphone|ipod|android/i;\n\n  /**\n   * Controller for md-datepicker.\n   *\n   * @ngInject @constructor\n   */\n  function DatePickerCtrl($scope, $element, $attrs, $window, $mdConstant, $mdTheming, $mdUtil,\n                          $mdDateLocale, $$mdDateUtil, $$rAF, $filter, $timeout) {\n\n    /** @final */\n    this.$window = $window;\n\n    /** @final */\n    this.dateUtil = $$mdDateUtil;\n\n    /** @final */\n    this.$mdConstant = $mdConstant;\n\n    /** @final */\n    this.$mdUtil = $mdUtil;\n\n    /** @final */\n    this.$$rAF = $$rAF;\n\n    /** @final */\n    this.$mdDateLocale = $mdDateLocale;\n\n    /** @final */\n    this.$timeout = $timeout;\n\n    /**\n     * The root document element. This is used for attaching a top-level click handler to\n     * close the calendar panel when a click outside said panel occurs. We use `documentElement`\n     * instead of body because, when scrolling is disabled, some browsers consider the body element\n     * to be completely off the screen and propagate events directly to the html element.\n     * @type {!JQLite}\n     */\n    this.documentElement = angular.element(document.documentElement);\n\n    /** @type {!ngModel.NgModelController} */\n    this.ngModelCtrl = null;\n\n    /** @type {HTMLInputElement} */\n    this.inputElement = $element[0].querySelector('input');\n\n    /**\n     * @final\n     * @type {!JQLite}\n     */\n    this.ngInputElement = angular.element(this.inputElement);\n\n    /** @type {HTMLElement} */\n    this.inputContainer = $element[0].querySelector('.md-datepicker-input-container');\n\n    /** @type {HTMLElement} Floating calendar pane. */\n    this.calendarPane = $element[0].querySelector('.md-datepicker-calendar-pane');\n\n    /** @type {HTMLElement} Calendar icon button. */\n    this.calendarButton = $element[0].querySelector('.md-datepicker-button');\n\n    /**\n     * Element covering everything but the input in the top of the floating calendar pane.\n     * @type {!JQLite}\n     */\n    this.inputMask = angular.element($element[0].querySelector('.md-datepicker-input-mask-opaque'));\n\n    /**\n     * @final\n     * @type {!JQLite}\n     */\n    this.$element = $element;\n\n    /**\n     * @final\n     * @type {!angular.Attributes}\n     */\n    this.$attrs = $attrs;\n\n    /**\n     * @final\n     * @type {!angular.Scope}\n     */\n    this.$scope = $scope;\n\n    /**\n     * This holds the model that will be used by the calendar.\n     * @type {Date|null|undefined}\n     */\n    this.date = null;\n\n    /** @type {boolean} */\n    this.isFocused = false;\n\n    /** @type {boolean} */\n    this.isDisabled = undefined;\n    this.setDisabled($element[0].disabled || angular.isString($attrs.disabled));\n\n    /** @type {boolean} Whether the date-picker's calendar pane is open. */\n    this.isCalendarOpen = false;\n\n    /** @type {boolean} Whether the calendar should open when the input is focused. */\n    this.openOnFocus = $attrs.hasOwnProperty('mdOpenOnFocus');\n\n    /** @type {Object} Instance of the mdInputContainer controller */\n    this.mdInputContainer = null;\n\n    /**\n     * Element from which the calendar pane was opened. Keep track of this so that we can return\n     * focus to it when the pane is closed.\n     * @type {HTMLElement}\n     */\n    this.calendarPaneOpenedFrom = null;\n\n    /** @type {String} Unique id for the calendar pane. */\n    this.calendarPaneId = 'md-date-pane-' + $mdUtil.nextUid();\n\n    /** Pre-bound click handler is saved so that the event listener can be removed. */\n    this.bodyClickHandler = angular.bind(this, this.handleBodyClick);\n\n    /**\n     * Name of the event that will trigger a close. Necessary to sniff the browser, because\n     * the resize event doesn't make sense on mobile and can have a negative impact since it\n     * triggers whenever the browser zooms in on a focused input.\n     */\n    this.windowEventName = IS_MOBILE_REGEX.test(\n      navigator.userAgent || navigator.vendor || window.opera\n    ) ? 'orientationchange' : 'resize';\n\n    /** Pre-bound close handler so that the event listener can be removed. */\n    this.windowEventHandler = $mdUtil.debounce(angular.bind(this, this.closeCalendarPane), 100);\n\n    /** Pre-bound handler for the window blur event. Allows for it to be removed later. */\n    this.windowBlurHandler = angular.bind(this, this.handleWindowBlur);\n\n    /** The built-in AngularJS date filter. */\n    this.ngDateFilter = $filter('date');\n\n    /** @type {Number} Extra margin for the left side of the floating calendar pane. */\n    this.leftMargin = 20;\n\n    /** @type {Number} Extra margin for the top of the floating calendar. Gets determined on the first open. */\n    this.topMargin = null;\n\n    // Unless the user specifies so, the datepicker should not be a tab stop.\n    // This is necessary because ngAria might add a tabindex to anything with an ng-model\n    // (based on whether or not the user has turned that particular feature on/off).\n    if ($attrs.tabindex) {\n      this.ngInputElement.attr('tabindex', $attrs.tabindex);\n      $attrs.$set('tabindex', null);\n    } else {\n      $attrs.$set('tabindex', '-1');\n    }\n\n    $attrs.$set('aria-owns', this.calendarPaneId);\n\n    $mdTheming($element);\n    $mdTheming(angular.element(this.calendarPane));\n\n    var self = this;\n\n    $scope.$on('$destroy', function() {\n      self.detachCalendarPane();\n    });\n\n    if ($attrs.mdIsOpen) {\n      $scope.$watch('ctrl.isOpen', function(shouldBeOpen) {\n        if (shouldBeOpen) {\n          self.openCalendarPane({\n            target: self.inputElement\n          });\n        } else {\n          self.closeCalendarPane();\n        }\n      });\n    }\n\n    // For AngularJS 1.4 and older, where there are no lifecycle hooks but bindings are\n    // pre-assigned, manually call the $onInit hook.\n    if (angular.version.major === 1 && angular.version.minor <= 4) {\n      this.$onInit();\n    }\n  }\n\n  /**\n   * AngularJS Lifecycle hook for newer AngularJS versions.\n   * Bindings are not guaranteed to have been assigned in the controller, but they are in the\n   * $onInit hook.\n   */\n  DatePickerCtrl.prototype.$onInit = function() {\n\n    /**\n     * Holds locale-specific formatters, parsers, labels etc. Allows\n     * the user to override specific ones from the $mdDateLocale provider.\n     * @type {!Object}\n     */\n    this.locale = this.dateLocale ? angular.extend({}, this.$mdDateLocale, this.dateLocale)\n      : this.$mdDateLocale;\n\n    this.installPropertyInterceptors();\n    this.attachChangeListeners();\n    this.attachInteractionListeners();\n  };\n\n  /**\n   * Sets up the controller's reference to ngModelController and\n   * applies AngularJS's `input[type=\"date\"]` directive.\n   * @param {!angular.NgModelController} ngModelCtrl Instance of the ngModel controller.\n   * @param {Object} mdInputContainer Instance of the mdInputContainer controller.\n   * @param {Object} inputDirective Config for AngularJS's `input` directive.\n   */\n  DatePickerCtrl.prototype.configureNgModel = function(ngModelCtrl, mdInputContainer, inputDirective) {\n    this.ngModelCtrl = ngModelCtrl;\n    this.mdInputContainer = mdInputContainer;\n\n    // The input needs to be [type=\"date\"] in order to be picked up by AngularJS.\n    this.$attrs.$set('type', 'date');\n\n    // Invoke the `input` directive link function, adding a stub for the element.\n    // This allows us to re-use AngularJS's logic for setting the timezone via ng-model-options.\n    // It works by calling the link function directly which then adds the proper `$parsers` and\n    // `$formatters` to the ngModel controller.\n    inputDirective[0].link.pre(this.$scope, {\n      on: angular.noop,\n      val: angular.noop,\n      0: {}\n    }, this.$attrs, [ngModelCtrl]);\n\n    var self = this;\n\n    // Responds to external changes to the model value.\n    self.ngModelCtrl.$formatters.push(function(value) {\n      var parsedValue = angular.isDefined(value) ? value : null;\n\n      if (!(value instanceof Date)) {\n        parsedValue = Date.parse(value);\n\n        // `parsedValue` is the time since epoch if valid or `NaN` if invalid.\n        if (!isNaN(parsedValue) && angular.isNumber(parsedValue)) {\n          value = new Date(parsedValue);\n        }\n\n        if (value && !(value instanceof Date)) {\n          throw Error(\n            'The ng-model for md-datepicker must be a Date instance or a value ' +\n              'that can be parsed into a date. Currently the model is of type: ' + typeof value\n          );\n        }\n      }\n\n      self.onExternalChange(value);\n\n      return value;\n    });\n\n    // Responds to external error state changes (e.g. ng-required based on another input).\n    ngModelCtrl.$viewChangeListeners.unshift(angular.bind(this, this.updateErrorState));\n\n    // Forwards any events from the input to the root element. This is necessary to get `updateOn`\n    // working for events that don't bubble (e.g. 'blur') since AngularJS binds the handlers to\n    // the `<md-datepicker>`.\n    var updateOn = self.$mdUtil.getModelOption(ngModelCtrl, 'updateOn');\n\n    if (updateOn) {\n      this.ngInputElement.on(\n        updateOn,\n        angular.bind(this.$element, this.$element.triggerHandler, updateOn)\n      );\n    }\n  };\n\n  /**\n   * Attach event listeners for both the text input and the md-calendar.\n   * Events are used instead of ng-model so that updates don't infinitely update the other\n   * on a change. This should also be more performant than using a $watch.\n   */\n  DatePickerCtrl.prototype.attachChangeListeners = function() {\n    var self = this;\n\n    self.$scope.$on('md-calendar-change', function(event, date) {\n      self.setModelValue(date);\n      self.onExternalChange(date);\n      self.closeCalendarPane();\n    });\n\n    self.ngInputElement.on('input', angular.bind(self, self.resizeInputElement));\n\n    var debounceInterval = angular.isDefined(this.debounceInterval) ?\n        this.debounceInterval : DEFAULT_DEBOUNCE_INTERVAL;\n    self.ngInputElement.on('input', self.$mdUtil.debounce(self.handleInputEvent,\n        debounceInterval, self));\n  };\n\n  /** Attach event listeners for user interaction. */\n  DatePickerCtrl.prototype.attachInteractionListeners = function() {\n    var self = this;\n    var $scope = this.$scope;\n    var keyCodes = this.$mdConstant.KEY_CODE;\n\n    // Add event listener through angular so that we can triggerHandler in unit tests.\n    self.ngInputElement.on('keydown', function(event) {\n      if (event.altKey && event.keyCode === keyCodes.DOWN_ARROW) {\n        self.openCalendarPane(event);\n        $scope.$digest();\n      }\n    });\n\n    if (self.openOnFocus) {\n      self.ngInputElement.on('focus', angular.bind(self, self.openCalendarPane));\n      self.ngInputElement.on('click', function(event) {\n        event.stopPropagation();\n      });\n      self.ngInputElement.on('pointerdown',function(event) {\n        if (event.target && event.target.setPointerCapture) {\n          event.target.setPointerCapture(event.pointerId);\n        }\n      });\n\n      angular.element(self.$window).on('blur', self.windowBlurHandler);\n\n      $scope.$on('$destroy', function() {\n        angular.element(self.$window).off('blur', self.windowBlurHandler);\n      });\n    }\n\n    $scope.$on('md-calendar-close', function() {\n      self.closeCalendarPane();\n    });\n  };\n\n  /**\n   * Capture properties set to the date-picker and imperatively handle internal changes.\n   * This is done to avoid setting up additional $watches.\n   */\n  DatePickerCtrl.prototype.installPropertyInterceptors = function() {\n    var self = this;\n\n    if (this.$attrs.ngDisabled) {\n      // The expression is to be evaluated against the directive element's scope and not\n      // the directive's isolate scope.\n      var scope = this.$scope.$parent;\n\n      if (scope) {\n        scope.$watch(this.$attrs.ngDisabled, function(isDisabled) {\n          self.setDisabled(isDisabled);\n        });\n      }\n    }\n\n    Object.defineProperty(this, 'placeholder', {\n      get: function() { return self.inputElement.placeholder; },\n      set: function(value) { self.inputElement.placeholder = value || ''; }\n    });\n  };\n\n  /**\n   * Sets whether the date-picker is disabled.\n   * @param {boolean} isDisabled\n   */\n  DatePickerCtrl.prototype.setDisabled = function(isDisabled) {\n    this.isDisabled = isDisabled;\n    this.inputElement.disabled = isDisabled;\n\n    if (this.calendarButton) {\n      this.calendarButton.disabled = isDisabled;\n    }\n  };\n\n  /**\n   * Sets the custom ngModel.$error flags to be consumed by ngMessages. Flags are:\n   *   - mindate: whether the selected date is before the minimum date.\n   *   - maxdate: whether the selected flag is after the maximum date.\n   *   - filtered: whether the selected date is allowed by the custom filtering function.\n   *   - valid: whether the entered text input is a valid date\n   *\n   * The 'required' flag is handled automatically by ngModel.\n   *\n   * @param {Date=} opt_date Date to check. If not given, defaults to the datepicker's model value.\n   */\n  DatePickerCtrl.prototype.updateErrorState = function(opt_date) {\n    var date;\n    if (opt_date) {\n      date = new Date(opt_date.valueOf());\n    } else {\n      date = angular.copy(this.ngModelCtrl.$modelValue);\n    }\n\n    // Clear any existing errors to get rid of anything that's no longer relevant.\n    this.clearErrorState();\n\n    if (this.dateUtil.isValidDate(date)) {\n      // Force all dates to midnight in order to ignore the time portion.\n      date = this.dateUtil.createDateAtMidnight(date);\n\n      if (this.dateUtil.isValidDate(this.minDate)) {\n        var minDate = this.dateUtil.createDateAtMidnight(this.minDate);\n        this.ngModelCtrl.$setValidity('mindate', date >= minDate);\n      }\n\n      if (this.dateUtil.isValidDate(this.maxDate)) {\n        var maxDate = this.dateUtil.createDateAtMidnight(this.maxDate);\n        this.ngModelCtrl.$setValidity('maxdate', date <= maxDate);\n      }\n\n      if (angular.isFunction(this.dateFilter)) {\n        this.ngModelCtrl.$setValidity('filtered', this.dateFilter(date));\n      }\n\n      if (angular.isFunction(this.monthFilter)) {\n        this.ngModelCtrl.$setValidity('filtered', this.monthFilter(date));\n      }\n    } else {\n      // The date is seen as \"not a valid date\" if there is *something* set\n      // (i.e.., not null or undefined), but that something isn't a valid date.\n      this.ngModelCtrl.$setValidity('valid', date == null);\n    }\n\n    var input = this.inputElement.value;\n    var parsedDate = this.locale.parseDate(input);\n\n    if (!this.isInputValid(input, parsedDate) && this.ngModelCtrl.$valid) {\n      this.ngModelCtrl.$setValidity('valid', date == null);\n    }\n\n    angular.element(this.inputContainer).toggleClass(INVALID_CLASS,\n      this.ngModelCtrl.$invalid && (this.ngModelCtrl.$touched || this.ngModelCtrl.$submitted));\n  };\n\n  /**\n   * Check to see if the input is valid, as the validation should fail if the model is invalid.\n   *\n   * @param {string} inputString\n   * @param {Date} parsedDate\n   * @return {boolean} Whether the input is valid\n   */\n  DatePickerCtrl.prototype.isInputValid = function (inputString, parsedDate) {\n    return inputString === '' || (\n      this.dateUtil.isValidDate(parsedDate) &&\n      this.locale.isDateComplete(inputString) &&\n      this.isDateEnabled(parsedDate)\n    );\n  };\n\n  /** Clears any error flags set by `updateErrorState`. */\n  DatePickerCtrl.prototype.clearErrorState = function() {\n    this.inputContainer.classList.remove(INVALID_CLASS);\n    ['mindate', 'maxdate', 'filtered', 'valid'].forEach(function(field) {\n      this.ngModelCtrl.$setValidity(field, true);\n    }, this);\n  };\n\n  /** Resizes the input element based on the size of its content. */\n  DatePickerCtrl.prototype.resizeInputElement = function() {\n    this.inputElement.size = this.inputElement.value.length + EXTRA_INPUT_SIZE;\n  };\n\n  /**\n   * Sets the model value if the user input is a valid date.\n   * Adds an invalid class to the input element if not.\n   */\n  DatePickerCtrl.prototype.handleInputEvent = function() {\n    var inputString = this.inputElement.value;\n    var parsedDate = inputString ? this.locale.parseDate(inputString) : null;\n    this.dateUtil.setDateTimeToMidnight(parsedDate);\n\n    // An input string is valid if it is either empty (representing no date)\n    // or if it parses to a valid date that the user is allowed to select.\n    var isValidInput = this.isInputValid(inputString, parsedDate);\n\n    // The datepicker's model is only updated when there is a valid input.\n    if (isValidInput) {\n      this.setModelValue(parsedDate);\n      this.date = parsedDate;\n    }\n\n    this.updateErrorState(parsedDate);\n  };\n\n  /**\n   * Check whether date is in range and enabled\n   * @param {Date=} opt_date\n   * @return {boolean} Whether the date is enabled.\n   */\n  DatePickerCtrl.prototype.isDateEnabled = function(opt_date) {\n    return this.dateUtil.isDateWithinRange(opt_date, this.minDate, this.maxDate) &&\n          (!angular.isFunction(this.dateFilter) || this.dateFilter(opt_date)) &&\n          (!angular.isFunction(this.monthFilter) || this.monthFilter(opt_date));\n  };\n\n  /** Position and attach the floating calendar to the document. */\n  DatePickerCtrl.prototype.attachCalendarPane = function() {\n    var calendarPane = this.calendarPane;\n    var body = document.body;\n\n    calendarPane.style.transform = '';\n    this.$element.addClass(OPEN_CLASS);\n    this.mdInputContainer && this.mdInputContainer.element.addClass(OPEN_CLASS);\n    angular.element(body).addClass('md-datepicker-is-showing');\n\n    var elementRect = this.inputContainer.getBoundingClientRect();\n    var bodyRect = body.getBoundingClientRect();\n\n    if (!this.topMargin || this.topMargin < 0) {\n      this.topMargin =\n        (this.inputMask.parent().prop('clientHeight')\n          - this.ngInputElement.prop('clientHeight')) / 2;\n    }\n\n    // Check to see if the calendar pane would go off the screen. If so, adjust position\n    // accordingly to keep it within the viewport.\n    var paneTop = elementRect.top - bodyRect.top - this.topMargin;\n    var paneLeft = elementRect.left - bodyRect.left - this.leftMargin;\n\n    // If ng-material has disabled body scrolling (for example, if a dialog is open),\n    // then it's possible that the already-scrolled body has a negative top/left. In this case,\n    // we want to treat the \"real\" top as (0 - bodyRect.top). In a normal scrolling situation,\n    // though, the top of the viewport should just be the body's scroll position.\n    var viewportTop = (bodyRect.top < 0 && document.body.scrollTop === 0) ?\n        -bodyRect.top :\n        document.body.scrollTop;\n\n    var viewportLeft = (bodyRect.left < 0 && document.body.scrollLeft === 0) ?\n        -bodyRect.left :\n        document.body.scrollLeft;\n\n    var viewportBottom = viewportTop + this.$window.innerHeight;\n    var viewportRight = viewportLeft + this.$window.innerWidth;\n\n    // Creates an overlay with a hole the same size as element. We remove a pixel or two\n    // on each end to make it overlap slightly. The overlay's background is added in\n    // the theme in the form of a box-shadow with a huge spread.\n    this.inputMask.css({\n      position: 'absolute',\n      left: this.leftMargin + 'px',\n      top: this.topMargin + 'px',\n      width: (elementRect.width - 1) + 'px',\n      height: (elementRect.height - 2) + 'px'\n    });\n\n    // If the right edge of the pane would be off the screen and shifting it left by the\n    // difference would not go past the left edge of the screen. If the calendar pane is too\n    // big to fit on the screen at all, move it to the left of the screen and scale the entire\n    // element down to fit.\n    if (paneLeft + CALENDAR_PANE_WIDTH > viewportRight) {\n      if (viewportRight - CALENDAR_PANE_WIDTH > 0) {\n        paneLeft = viewportRight - CALENDAR_PANE_WIDTH;\n      } else {\n        paneLeft = viewportLeft;\n        var scale = this.$window.innerWidth / CALENDAR_PANE_WIDTH;\n        calendarPane.style.transform = 'scale(' + scale + ')';\n      }\n\n      calendarPane.classList.add('md-datepicker-pos-adjusted');\n    }\n\n    // If the bottom edge of the pane would be off the screen and shifting it up by the\n    // difference would not go past the top edge of the screen.\n    if (paneTop + CALENDAR_PANE_HEIGHT > viewportBottom &&\n        viewportBottom - CALENDAR_PANE_HEIGHT > viewportTop) {\n      paneTop = viewportBottom - CALENDAR_PANE_HEIGHT;\n      calendarPane.classList.add('md-datepicker-pos-adjusted');\n    }\n\n    calendarPane.style.left = paneLeft + 'px';\n    calendarPane.style.top = paneTop + 'px';\n    document.body.appendChild(calendarPane);\n\n    // Add CSS class after one frame to trigger open animation.\n    this.$$rAF(function() {\n      calendarPane.classList.add('md-pane-open');\n    });\n  };\n\n  /** Detach the floating calendar pane from the document. */\n  DatePickerCtrl.prototype.detachCalendarPane = function() {\n    this.$element.removeClass(OPEN_CLASS);\n    this.mdInputContainer && this.mdInputContainer.element.removeClass(OPEN_CLASS);\n    angular.element(document.body).removeClass('md-datepicker-is-showing');\n    this.calendarPane.classList.remove('md-pane-open');\n    this.calendarPane.classList.remove('md-datepicker-pos-adjusted');\n\n    if (this.isCalendarOpen) {\n      this.$mdUtil.enableScrolling();\n    }\n\n    if (this.calendarPane.parentNode) {\n      // Use native DOM removal because we do not want any of the\n      // angular state of this element to be disposed.\n      this.calendarPane.parentNode.removeChild(this.calendarPane);\n    }\n  };\n\n  /**\n   * Open the floating calendar pane.\n   * @param {MouseEvent|KeyboardEvent|{target: HTMLInputElement}} event\n   */\n  DatePickerCtrl.prototype.openCalendarPane = function(event) {\n    if (!this.isCalendarOpen && !this.isDisabled && !this.inputFocusedOnWindowBlur) {\n      this.isCalendarOpen = this.isOpen = true;\n      this.calendarPaneOpenedFrom = event.target;\n\n      // Because the calendar pane is attached directly to the body, it is possible that the\n      // rest of the component (input, etc) is in a different scrolling container, such as\n      // an md-content. This means that, if the container is scrolled, the pane would remain\n      // stationary. To remedy this, we disable scrolling while the calendar pane is open, which\n      // also matches the native behavior for things like `<select>` on Mac and Windows.\n      this.$mdUtil.disableScrollAround(this.calendarPane);\n\n      this.attachCalendarPane();\n      this.focusCalendar();\n      this.evalAttr('ngFocus');\n\n      // Attach click listener inside of a timeout because, if this open call was triggered by a\n      // click, we don't want it to be immediately propagated up to the body and handled.\n      var self = this;\n      this.$mdUtil.nextTick(function() {\n        // Use 'touchstart` in addition to click in order to work on iOS Safari, where click\n        // events aren't propagated under most circumstances.\n        // See http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n        self.documentElement.on('click touchstart', self.bodyClickHandler);\n      }, false);\n\n      window.addEventListener(this.windowEventName, this.windowEventHandler);\n    } else if (this.inputFocusedOnWindowBlur) {\n      this.resetInputFocused();\n    }\n  };\n\n  /** Close the floating calendar pane. */\n  DatePickerCtrl.prototype.closeCalendarPane = function() {\n    if (this.isCalendarOpen) {\n      var self = this;\n\n      self.detachCalendarPane();\n      self.ngModelCtrl.$setTouched();\n      self.evalAttr('ngBlur');\n\n      self.documentElement.off('click touchstart', self.bodyClickHandler);\n      window.removeEventListener(self.windowEventName, self.windowEventHandler);\n\n      self.calendarPaneOpenedFrom.focus();\n      self.calendarPaneOpenedFrom = null;\n\n      if (self.openOnFocus) {\n        // Ensures that all focus events have fired before resetting\n        // the calendar. Prevents the calendar from reopening immediately\n        // in IE when md-open-on-focus is set. Also it needs to trigger\n        // a digest, in order to prevent issues where the calendar wasn't\n        // showing up on the next open.\n        self.$timeout(reset);\n      } else {\n        reset();\n      }\n    }\n\n    function reset() {\n      self.isCalendarOpen = self.isOpen = false;\n    }\n  };\n\n  /** Gets the controller instance for the calendar in the floating pane. */\n  DatePickerCtrl.prototype.getCalendarCtrl = function() {\n    return angular.element(this.calendarPane.querySelector('md-calendar')).controller('mdCalendar');\n  };\n\n  /** Focus the calendar in the floating pane. */\n  DatePickerCtrl.prototype.focusCalendar = function() {\n    // Use a timeout in order to allow the calendar to be rendered, as it is gated behind an ng-if.\n    var self = this;\n    this.$mdUtil.nextTick(function() {\n      self.getCalendarCtrl().focusDate(self.date);\n    }, false);\n  };\n\n  /**\n   * Sets whether the input is currently focused.\n   * @param {boolean} isFocused\n   */\n  DatePickerCtrl.prototype.setFocused = function(isFocused) {\n    if (!isFocused) {\n      this.ngModelCtrl.$setTouched();\n    }\n\n    // The ng* expressions shouldn't be evaluated when mdOpenOnFocus is on,\n    // because they also get called when the calendar is opened/closed.\n    if (!this.openOnFocus) {\n      this.evalAttr(isFocused ? 'ngFocus' : 'ngBlur');\n    }\n\n    this.isFocused = isFocused;\n  };\n\n  /**\n   * Handles a click on the document body when the floating calendar pane is open.\n   * Closes the floating calendar pane if the click is not inside of it.\n   * @param {MouseEvent} event\n   */\n  DatePickerCtrl.prototype.handleBodyClick = function(event) {\n    if (this.isCalendarOpen) {\n      var isInCalendar = this.$mdUtil.getClosest(event.target, 'md-calendar');\n\n      if (!isInCalendar) {\n        this.closeCalendarPane();\n      }\n\n      this.$scope.$digest();\n    }\n  };\n\n  /**\n   * Handles the event when the user navigates away from the current tab. Keeps track of\n   * whether the input was focused when the event happened, in order to prevent the calendar\n   * from re-opening.\n   */\n  DatePickerCtrl.prototype.handleWindowBlur = function() {\n    this.inputFocusedOnWindowBlur = document.activeElement === this.inputElement;\n  };\n\n  /**\n   * Reset the flag inputFocusedOnWindowBlur to default state, to permit user to open calendar\n   * again when he back to tab with calendar focused.\n   */\n  DatePickerCtrl.prototype.resetInputFocused = function() {\n    this.inputFocusedOnWindowBlur = false;\n  };\n\n  /**\n   * Evaluates an attribute expression against the parent scope.\n   * @param {String} attr Name of the attribute to be evaluated.\n   */\n  DatePickerCtrl.prototype.evalAttr = function(attr) {\n    if (this.$attrs[attr]) {\n      this.$scope.$parent.$eval(this.$attrs[attr]);\n    }\n  };\n\n  /**\n   * Sets the ng-model value by first converting the date object into a string. Converting it\n   * is necessary, in order to pass AngularJS's `input[type=\"date\"]` validations. AngularJS turns\n   * the value into a Date object afterwards, before setting it on the model.\n   * @param {Date=} value Date to be set as the model value.\n   */\n  DatePickerCtrl.prototype.setModelValue = function(value) {\n    var timezone = this.$mdUtil.getModelOption(this.ngModelCtrl, 'timezone');\n    // Using the timezone when the offset is negative (GMT+X) causes the previous day to be\n    // set as the model value here. This check avoids that.\n    if (timezone == null || value == null || value.getTimezoneOffset() < 0) {\n      this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd'), 'default');\n    } else {\n      this.ngModelCtrl.$setViewValue(this.ngDateFilter(value, 'yyyy-MM-dd', timezone), 'default');\n    }\n  };\n\n  /**\n   * Updates the datepicker when a model change occurred externally.\n   * @param {Date=} value Value that was set to the model.\n   */\n  DatePickerCtrl.prototype.onExternalChange = function(value) {\n    var self = this;\n    var timezone = this.$mdUtil.getModelOption(this.ngModelCtrl, 'timezone');\n\n    // Update the model used by the calendar.\n    if (this.dateUtil.isValidDate(value) && timezone != null && value.getTimezoneOffset() >= 0) {\n      this.date = this.dateUtil.removeLocalTzAndReparseDate(value);\n    } else {\n      this.date = value;\n    }\n    // Using the timezone when the offset is negative (GMT+X) causes the previous day to be\n    // used here. This check avoids that.\n    if (timezone == null || value == null || value.getTimezoneOffset() < 0) {\n      this.inputElement.value = this.locale.formatDate(value);\n    } else {\n      this.inputElement.value = this.locale.formatDate(value, timezone);\n    }\n    this.mdInputContainer && this.mdInputContainer.setHasValue(!!value);\n    this.resizeInputElement();\n    // This is often called from the $formatters section of the $validators pipeline.\n    // In that case, we need to delay to let $render and $validate run, so that the checks for\n    // error state are accurate.\n    this.$mdUtil.nextTick(function() {self.updateErrorState();}, false, self.$scope);\n  };\n})();\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.dialog\n */\nMdDialogDirective.$inject = [\"$$rAF\", \"$mdTheming\", \"$mdDialog\"];\nMdDialogProvider.$inject = [\"$$interimElementProvider\"];\nangular\n  .module('material.components.dialog', [\n    'material.core',\n    'material.components.backdrop'\n  ])\n  .directive('mdDialog', MdDialogDirective)\n  .provider('$mdDialog', MdDialogProvider);\n\n/**\n * @ngdoc directive\n * @name mdDialog\n * @module material.components.dialog\n *\n * @restrict E\n *\n * @description\n * `<md-dialog>` - The dialog's template must be inside this element.\n *\n * Inside, use an `<md-dialog-content>` element for the dialog's content, and use\n * an `<md-dialog-actions>` element for the dialog's actions.\n *\n * ## CSS\n * - `.md-dialog-content` - class that sets the padding on the content as the spec file\n *\n * ## Notes\n * - If you specify an `id` for the `<md-dialog>`, the `<md-dialog-content>` will have the same `id`\n * prefixed with `dialogContent_`.\n *\n * @usage\n * ### Dialog template\n * <hljs lang=\"html\">\n * <md-dialog aria-label=\"List dialog\">\n *   <md-dialog-content>\n *     <md-list>\n *       <md-list-item ng-repeat=\"item in items\">\n *         <p>Number {{item}}</p>\n *       </md-list-item>\n *     </md-list>\n *   </md-dialog-content>\n *   <md-dialog-actions>\n *     <md-button ng-click=\"closeDialog()\" class=\"md-primary\">Close Dialog</md-button>\n *   </md-dialog-actions>\n * </md-dialog>\n * </hljs>\n */\nfunction MdDialogDirective($$rAF, $mdTheming, $mdDialog) {\n  return {\n    restrict: 'E',\n    link: function(scope, element) {\n      element.addClass('_md');     // private md component indicator for styling\n\n      $mdTheming(element);\n      $$rAF(function() {\n        var images;\n        var content = element[0].querySelector('md-dialog-content');\n\n        if (content) {\n          images = content.getElementsByTagName('img');\n          addOverflowClass();\n          // delayed image loading may impact scroll height, check after images are loaded\n          angular.element(images).on('load', addOverflowClass);\n        }\n\n        scope.$on('$destroy', function() {\n          $mdDialog.destroy(element);\n        });\n\n        /**\n         *\n         */\n        function addOverflowClass() {\n          element.toggleClass('md-content-overflow', content.scrollHeight > content.clientHeight);\n        }\n\n\n      });\n    }\n  };\n}\n\n/**\n * @ngdoc service\n * @name $mdDialog\n * @module material.components.dialog\n *\n * @description\n * `$mdDialog` opens a dialog over the app to inform users about critical information or require\n *  them to make decisions. There are two approaches for setup: a simple promise API\n *  and regular object syntax.\n *\n * ## Restrictions\n *\n * - The dialog is always given an isolate scope.\n * - The dialog's template must have an outer `<md-dialog>` element.\n *   Inside, use an `<md-dialog-content>` element for the dialog's content, and use\n *   an `<md-dialog-actions>` element for the dialog's actions.\n * - Dialogs must cover the entire application to keep interactions inside of them.\n * Use the `parent` option to change where dialogs are appended.\n *\n * ## Sizing\n * - Complex dialogs can be sized with `flex=\"percentage\"`, i.e. `flex=\"66\"`.\n * - Default max-width is 80% of the `rootElement` or `parent`.\n *\n * ## CSS\n * - `.md-dialog-content` - class that sets the padding on the content as the spec file\n *\n * @usage\n * <hljs lang=\"html\">\n * <div ng-app=\"demoApp\" ng-controller=\"AppController as ctrl\">\n *   <div>\n *     <md-button ng-click=\"ctrl.showAlert()\" class=\"md-raised md-warn\">\n *       Basic Alert!\n *       </md-button>\n *   </div>\n *   <div>\n *     <md-button ng-click=\"ctrl.showDialog($event)\" class=\"md-raised\">\n *       Custom Dialog\n *       </md-button>\n *   </div>\n * </div>\n * </hljs>\n *\n * ### JavaScript: object syntax\n * <hljs lang=\"js\">\n * (function(angular, undefined) {\n *   \"use strict\";\n *\n *   angular\n *    .module('demoApp', ['ngMaterial'])\n *    .controller('AppCtrl', AppController);\n *\n *   function AppController($mdDialog) {\n *     var alert;\n *     var ctrl = this;\n *     ctrl.showAlert = showAlert;\n *     ctrl.showDialog = showDialog;\n *     ctrl.items = [1, 2, 3];\n *\n *     // Internal method\n *     function showAlert() {\n *       alert = $mdDialog.alert({\n *         title: 'Attention',\n *         textContent: 'This is an example of how simple dialogs can be!',\n *         ok: 'Close'\n *       });\n *\n *       $mdDialog\n *         .show( alert )\n *         .finally(function() {\n *           alert = undefined;\n *         });\n *     }\n *\n *     function showDialog($event) {\n *        var parentEl = angular.element(document.body);\n *        $mdDialog.show({\n *          parent: parentEl,\n *          targetEvent: $event,\n *          template:\n *            '<md-dialog aria-label=\"List dialog\">' +\n *            '  <md-dialog-content>'+\n *            '    <md-list>'+\n *            '      <md-list-item ng-repeat=\"item in ctrl.items\">'+\n *            '       <p>Number {{item}}</p>' +\n *            '      </md-item>'+\n *            '    </md-list>'+\n *            '  </md-dialog-content>' +\n *            '  <md-dialog-actions>' +\n *            '    <md-button ng-click=\"ctrl.closeDialog()\" class=\"md-primary\">' +\n *            '      Close Dialog' +\n *            '    </md-button>' +\n *            '  </md-dialog-actions>' +\n *            '</md-dialog>',\n *          locals: {\n *            items: ctrl.items\n *          },\n *          controller: DialogController\n *          controllerAs: 'ctrl'\n *       });\n *       function DialogController($mdDialog) {\n *         this.closeDialog = function() {\n *           $mdDialog.hide();\n *         }\n *       }\n *     }\n *   }\n * })(angular);\n * </hljs>\n *\n * ### Multiple Dialogs\n * Using the `multiple` option for the `$mdDialog` service allows developers to show multiple\n * dialogs at the same time.\n *\n * <hljs lang=\"js\">\n *   // From plain options\n *   $mdDialog.show({\n *     multiple: true\n *   });\n *\n *   // From a dialog preset\n *   $mdDialog.show(\n *     $mdDialog\n *       .alert()\n *       .multiple(true)\n *   );\n *\n * </hljs>\n *\n * ### Pre-Rendered Dialogs\n * By using the `contentElement` option, it is possible to use an already existing element in the\n * DOM.\n *\n * > Pre-rendered dialogs will be not linked to any scope and will not instantiate any new\n * > controller.<br/>\n * > You can manually link the elements to a scope or instantiate a controller from the template\n * > (using `ng-controller`).\n *\n * <hljs lang=\"js\">\n *   function showPrerenderedDialog() {\n *     $mdDialog.show({\n *       contentElement: '#myStaticDialog',\n *       parent: angular.element(document.body)\n *     });\n *   }\n * </hljs>\n *\n * When using a string as value, `$mdDialog` will automatically query the DOM for the specified CSS\n * selector.\n *\n * <hljs lang=\"html\">\n *   <div style=\"visibility: hidden\">\n *     <div class=\"md-dialog-container\" id=\"myStaticDialog\">\n *       <md-dialog>\n *         This is a pre-rendered dialog.\n *       </md-dialog>\n *     </div>\n *   </div>\n * </hljs>\n *\n * **Notice**: It is important, to use the `.md-dialog-container` as the content element, otherwise\n * the dialog will not show up.\n *\n * It also possible to use a DOM element for the `contentElement` option.\n * - `contentElement: document.querySelector('#myStaticDialog')`\n * - `contentElement: angular.element(TEMPLATE)`\n *\n * When using a `template` as content element, it will be not compiled upon open.\n * This allows you to compile the element yourself and use it each time the dialog opens.\n *\n * ### Custom Presets\n * Developers are also able to create their own preset, which can be used without repeating\n * their options each time.\n *\n * <hljs lang=\"js\">\n *   $mdDialogProvider.addPreset('testPreset', {\n *     options: function() {\n *       return {\n *         template:\n *           '<md-dialog>' +\n *             'This is a custom preset' +\n *           '</md-dialog>',\n *         controllerAs: 'dialog',\n *         bindToController: true,\n *         clickOutsideToClose: true,\n *         escapeToClose: true\n *       };\n *     }\n *   });\n * </hljs>\n *\n * After creating your preset in the `config` phase, you can access it.\n *\n * <hljs lang=\"js\">\n *   $mdDialog.show(\n *     $mdDialog.testPreset()\n *   );\n * </hljs>\n *\n * ### JavaScript: promise API syntax, custom dialog template\n *\n * <hljs lang=\"js\">\n * (function(angular, undefined) {\n *   \"use strict\";\n *\n *   angular\n *     .module('demoApp', ['ngMaterial'])\n *     .controller('EmployeeController', EmployeeController)\n *     .controller('GreetingController', GreetingController);\n *\n *   // Fictitious Employee Editor to show how to use simple and complex dialogs.\n *\n *   function EmployeeController($mdDialog) {\n *     var alert;\n *     var ctrl = this;\n *\n *     ctrl.showAlert = showAlert;\n *     ctrl.showGreeting = showCustomGreeting;\n *\n *     ctrl.hasAlert = function() { return !!alert };\n *     ctrl.userName = ctrl.userName || 'Bobby';\n *\n *     // Dialog #1 - Show simple alert dialog and cache reference to dialog instance\n *\n *     function showAlert() {\n *       alert = $mdDialog.alert()\n *         .title('Attention, ' + ctrl.userName)\n *         .textContent('This is an example of how simple dialogs can be!')\n *         .ok('Close');\n *\n *       $mdDialog\n *         .show(alert)\n *         .finally(function() {\n *           alert = undefined;\n *         });\n *     }\n *\n *     // Dialog #2 - Demonstrate more complex dialogs construction and popup.\n *\n *     function showCustomGreeting($event) {\n *       $mdDialog.show({\n *         targetEvent: $event,\n *         template:\n *           '<md-dialog>' +\n *           '  <md-dialog-content>Hello {{ ctrl.employee }}!</md-dialog-content>' +\n *           '  <md-dialog-actions>' +\n *           '    <md-button ng-click=\"ctrl.closeDialog()\" class=\"md-primary\">' +\n *           '      Close Greeting' +\n *           '    </md-button>' +\n *           '  </md-dialog-actions>' +\n *           '</md-dialog>',\n *         controller: GreetingController,\n *         controllerAs: 'ctrl',\n *         onComplete: afterShowAnimation,\n *         locals: { employee: ctrl.userName }\n *       });\n *\n *       // When the 'enter' animation finishes...\n *       function afterShowAnimation(scope, element, options) {\n *         // post-show code here: DOM element focus, etc.\n *       }\n *     }\n *   }\n *\n *   // Greeting controller used with the 'showCustomGreeting()' custom dialog\n *   function GreetingController($mdDialog, $log) {\n *     var ctrl = this;\n *     this.$log = $log;\n *\n *     ctrl.closeDialog = function() {\n *       // Hides the most recent dialog shown.\n *       // No specific dialog instance reference is needed.\n *       $mdDialog.hide();\n *     };\n *   }\n *\n *   GreetingController.prototype.$onInit = function() {\n *     // Assigned from the locals options passed to $mdDialog.show.\n *     this.$log.log('Employee Name: ', ctrl.employee);\n *   };\n *\n * })(angular);\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdDialog#alert\n *\n * @description\n * Builds a preconfigured dialog with the specified message.\n *\n * @returns {Object} a dialog preset with the chainable configuration methods:\n *\n * - `title(string)` - Sets the alert title.\n * - `textContent(string)` - Sets the alert message.\n * - `htmlContent(string)` - Sets the alert message as HTML. Requires the `ngSanitize`\n *     module to be loaded. HTML is not run through AngularJS' compiler.\n * - `ok(string)` - Sets the alert \"Okay\" button text.\n * - `theme(string)` - Sets the theme of the alert dialog.\n * - `targetEvent(DOMClickEvent=)` - A click's event object. When passed in as an\n *     option, the location of the click will be used as the starting point for the opening\n *     animation of the the dialog.\n */\n\n/**\n * @ngdoc method\n * @name $mdDialog#confirm\n *\n * @description\n * Builds a preconfigured dialog with the specified message. You can call show and the promise\n * returned will be resolved if the user clicks the confirm action on the dialog. The promise will\n * be rejected if the user clicks the cancel action or dismisses the dialog.\n *\n * @returns {Object} a dialog preset with the chainable configuration methods:\n *\n * Additionally, it supports the following methods:\n *\n * - `title(string)` - Sets the confirm title.\n * - `textContent(string)` - Sets the confirm message.\n * - `htmlContent(string)` - Sets the confirm message as HTML. Requires the `ngSanitize`\n *     module to be loaded. HTML is not run through AngularJS' compiler.\n * - `ok(string)` - Sets the confirm \"Okay\" button text.\n * - `cancel(string)` - Sets the confirm \"Cancel\" button text.\n * - `theme(string)` - Sets the theme of the confirm dialog.\n * - `targetEvent(DOMClickEvent=)` - A click's event object. When passed in as an\n *     option, the location of the click will be used as the starting point for the opening\n *     animation of the the dialog.\n */\n\n/**\n * @ngdoc method\n * @name $mdDialog#prompt\n *\n * @description\n * Builds a preconfigured dialog with the specified message and input box. You can call show and the\n * promise returned will be resolved, if the user clicks the prompt action on the dialog, passing\n * the input value as the first argument. The promise will be rejected if the user clicks the cancel\n * action or dismisses the dialog.\n *\n * @returns {Object} a dialog preset with the chainable configuration methods:\n *\n * Additionally, it supports the following methods:\n *\n * - `title(string)` - Sets the prompt title.\n * - `textContent(string)` - Sets the prompt message.\n * - `htmlContent(string)` - Sets the prompt message as HTML. Requires the `ngSanitize`\n *     module to be loaded. HTML is not run through AngularJS' compiler.\n * - `placeholder(string)` - Sets the placeholder text for the input.\n * - `required(boolean)` - Sets the input required value.\n * - `initialValue(string)` - Sets the initial value for the prompt input.\n * - `ok(string)` - Sets the prompt \"Okay\" button text.\n * - `cancel(string)` - Sets the prompt \"Cancel\" button text.\n * - `theme(string)` - Sets the theme of the prompt dialog.\n * - `targetEvent(DOMClickEvent=)` - A click's event object. When passed in as an\n *     option, the location of the click will be used as the starting point for the opening\n *     animation of the the dialog.\n */\n\n/**\n * @ngdoc method\n * @name $mdDialog#show\n *\n * @description\n * Show a dialog with the specified options.\n *\n * @param {Object} optionsOrPreset Either provide a dialog preset returned from `alert()`,\n * `prompt()`, or `confirm()`; or an options object with the following properties:\n *   - `templateUrl` - `{string=}`: The url of a template that will be used as the content\n *      of the dialog.\n *   - `template` - `{string=}`: HTML template to show in the dialog. This **must** be trusted HTML\n *      with respect to AngularJS' [$sce service](https://docs.angularjs.org/api/ng/service/$sce).\n *      This template should **never** be constructed with any kind of user input or user data.\n *   - `contentElement` - `{string|Element}`: Instead of using a template, which will be compiled\n *      each time a dialog opens, you can also use a DOM element.<br/>\n *     * When specifying an element, which is present on the DOM, `$mdDialog` will temporary fetch\n *     the element into the dialog and restores it at the old DOM position upon close.\n *     * When specifying a string, the string be used as a CSS selector, to lookup for the element\n *     in the DOM.\n *   - `autoWrap` - `{boolean=}`: Whether or not to automatically wrap the template with a\n *     `<md-dialog>` tag if one is not provided. Defaults to true. Can be disabled if you provide a\n *     custom dialog directive.\n *   - `targetEvent` - `{DOMClickEvent=}`: A click's event object. When passed in as an option,\n *     the location of the click will be used as the starting point for the opening animation\n *     of the the dialog.\n *   - `openFrom` - `{string|Element|Object}`: The query selector, DOM element or the Rect object\n *     that is used to determine the bounds (top, left, height, width) from which the Dialog will\n *     originate.\n *   - `closeTo` - `{string|Element|Object}`: The query selector, DOM element or the Rect object\n *     that is used to determine the bounds (top, left, height, width) to which the Dialog will\n *     target.\n *   - `scope` - `{Object=}`: the scope to link the template / controller to. If none is specified,\n *     it will create a new isolate scope.\n *     This scope will be destroyed when the dialog is removed unless `preserveScope` is set to\n *     true.\n *   - `preserveScope` - `{boolean=}`: whether to preserve the scope when the element is removed.\n *     Default is false\n *   - `disableParentScroll` - `{boolean=}`: Whether to disable scrolling while the dialog is open.\n *     Default true.\n *   - `hasBackdrop` - `{boolean=}`: Whether there should be an opaque backdrop behind the dialog.\n *     Default true.\n *   - `clickOutsideToClose` - `{boolean=}`: Whether the user can click outside the dialog to\n *     close it. Default false.\n *   - `escapeToClose` - `{boolean=}`: Whether the user can press escape to close the dialog.\n *     Default true.\n *   - `focusOnOpen` - `{boolean=}`: An option to override focus behavior on open. Only disable if\n *     focusing some other way, as focus management is required for dialogs to be accessible.\n *     Defaults to true.\n *   - `controller` - `{Function|string=}`: The controller to associate with the dialog. The\n *     controller will be injected with the local `$mdDialog`, which passes along a scope for the\n *     dialog.\n *   - `locals` - `{Object=}`: An object containing key/value pairs. The keys will be used as names\n *     of values to inject into the controller. For example, `locals: {three: 3}` would inject\n *     `three` into the controller, with the value 3. If `bindToController` is true, they will be\n *     copied to the controller instead.\n *   - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in.\n *   - `resolve` - `{Function=}`: Similar to locals, except it takes as values functions that return\n *     promises, and the dialog will not open until all of the promises resolve.\n *   - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.\n *   - `parent` - `{element=}`: The element to append the dialog to. Defaults to appending\n *     to the root element of the application.\n *   - `onShowing` - `Function(scope, element, options: Object=, controller: Object)=`: Callback\n *     function used to notify the show() animation is starting.\n *   - `onComplete` - `Function(scope, element, options: Object=)=`: Callback function used to\n *     notify when the show() animation is finished.\n *   - `onRemoving` - `Function(element, removePromise)`: Callback function used to announce the\n *      close/hide() action is starting. This allows developers to run custom animations\n *      in parallel with the close animations.\n *   - `fullscreen` `{boolean=}`: An option to toggle whether the dialog should show in fullscreen\n *      or not. Defaults to `false`.\n *   - `multiple` `{boolean=}`: An option to allow this dialog to display over one that's currently\n *     open.\n * @returns {Promise} A promise that can be resolved with `$mdDialog.hide()` or\n * rejected with `$mdDialog.cancel()`.\n */\n\n/**\n * @ngdoc method\n * @name $mdDialog#hide\n *\n * @description\n * Hide an existing dialog and resolve the promise returned from `$mdDialog.show()`.\n *\n * @param {*=} response An argument for the resolved promise.\n *\n * @returns {promise} A promise that is resolved when the dialog has been closed.\n */\n\n/**\n * @ngdoc method\n * @name $mdDialog#cancel\n *\n * @description\n * Hide an existing dialog and reject the promise returned from `$mdDialog.show()`.\n *\n * @param {*=} response An argument for the rejected promise.\n *\n * @returns {promise} A promise that is resolved when the dialog has been closed.\n */\n\nfunction MdDialogProvider($$interimElementProvider) {\n  // Elements to capture and redirect focus when the user presses tab at the dialog boundary.\n  MdDialogController.$inject = [\"$mdDialog\", \"$mdConstant\"];\n  dialogDefaultOptions.$inject = [\"$mdDialog\", \"$mdAria\", \"$mdUtil\", \"$mdConstant\", \"$animate\", \"$document\", \"$window\", \"$rootElement\", \"$log\", \"$injector\", \"$mdTheming\", \"$interpolate\", \"$mdInteraction\"];\n  var topFocusTrap, bottomFocusTrap;\n  var removeFocusTrap;\n\n  return $$interimElementProvider('$mdDialog')\n    .setDefaults({\n      methods: ['disableParentScroll', 'hasBackdrop', 'clickOutsideToClose', 'escapeToClose',\n          'targetEvent', 'closeTo', 'openFrom', 'parent', 'fullscreen', 'multiple'],\n      options: dialogDefaultOptions\n    })\n    .addPreset('alert', {\n      methods: ['title', 'htmlContent', 'textContent', 'ariaLabel', 'ok', 'theme',\n          'css'],\n      options: advancedDialogOptions\n    })\n    .addPreset('confirm', {\n      methods: ['title', 'htmlContent', 'textContent', 'ariaLabel', 'ok', 'cancel',\n          'theme', 'css'],\n      options: advancedDialogOptions\n    })\n    .addPreset('prompt', {\n      methods: ['title', 'htmlContent', 'textContent', 'initialValue', 'placeholder', 'ariaLabel',\n          'ok', 'cancel', 'theme', 'css', 'required'],\n      options: advancedDialogOptions\n    });\n\n  /* @ngInject */\n  function advancedDialogOptions() {\n    return {\n      template: [\n        '<md-dialog md-theme=\"{{ dialog.theme || dialog.defaultTheme }}\" aria-label=\"{{ dialog.ariaLabel }}\" ng-class=\"dialog.css\">',\n        '  <md-dialog-content class=\"md-dialog-content\" role=\"document\" tabIndex=\"-1\">',\n        '    <h2 class=\"md-title\">{{ dialog.title }}</h2>',\n        '    <div ng-if=\"::dialog.mdHtmlContent\" class=\"md-dialog-content-body\" ',\n        '        ng-bind-html=\"::dialog.mdHtmlContent\"></div>',\n        '    <div ng-if=\"::!dialog.mdHtmlContent\" class=\"md-dialog-content-body\">',\n        '      <p>{{::dialog.mdTextContent}}</p>',\n        '    </div>',\n        '    <md-input-container md-no-float ng-if=\"::dialog.$type == \\'prompt\\'\" class=\"md-prompt-input-container\">',\n        '      <input ng-keypress=\"dialog.keypress($event)\" md-autofocus ng-model=\"dialog.result\" ' +\n        '             placeholder=\"{{::dialog.placeholder}}\" ng-required=\"dialog.required\">',\n        '    </md-input-container>',\n        '  </md-dialog-content>',\n        '  <md-dialog-actions>',\n        '    <md-button ng-if=\"dialog.$type === \\'confirm\\' || dialog.$type === \\'prompt\\'\"' +\n        '               ng-click=\"dialog.abort()\" class=\"md-primary md-cancel-button\">',\n        '      {{ dialog.cancel }}',\n        '    </md-button>',\n        '    <md-button ng-click=\"dialog.hide()\" class=\"md-primary md-confirm-button\" md-autofocus=\"dialog.$type===\\'alert\\'\"' +\n        '               ng-disabled=\"dialog.required && !dialog.result\">',\n        '      {{ dialog.ok }}',\n        '    </md-button>',\n        '  </md-dialog-actions>',\n        '</md-dialog>'\n      ].join('').replace(/\\s\\s+/g, ''),\n      controller: MdDialogController,\n      controllerAs: 'dialog',\n      bindToController: true,\n    };\n  }\n\n  /**\n   * Controller for the md-dialog interim elements\n   * @ngInject\n   */\n  function MdDialogController($mdDialog, $mdConstant) {\n    // For compatibility with AngularJS 1.6+, we should always use the $onInit hook in\n    // interimElements. The $mdCompiler simulates the $onInit hook for all versions.\n    this.$onInit = function() {\n      var isPrompt = this.$type === 'prompt';\n\n      if (isPrompt && this.initialValue) {\n        this.result = this.initialValue;\n      }\n\n      this.hide = function() {\n        $mdDialog.hide(isPrompt ? this.result : true);\n      };\n      this.abort = function() {\n        $mdDialog.cancel();\n      };\n      this.keypress = function($event) {\n        var invalidPrompt = isPrompt && this.required && !angular.isDefined(this.result);\n\n        if ($event.keyCode === $mdConstant.KEY_CODE.ENTER && !invalidPrompt) {\n          $mdDialog.hide(this.result);\n        }\n      };\n    };\n  }\n\n  /* @ngInject */\n  function dialogDefaultOptions($mdDialog, $mdAria, $mdUtil, $mdConstant, $animate, $document,\n                                $window, $rootElement, $log, $injector, $mdTheming, $interpolate,\n                                $mdInteraction) {\n    return {\n      hasBackdrop: true,\n      isolateScope: true,\n      onCompiling: beforeCompile,\n      onShow: onShow,\n      onShowing: beforeShow,\n      onRemove: onRemove,\n      clickOutsideToClose: false,\n      escapeToClose: true,\n      targetEvent: null,\n      closeTo: null,\n      openFrom: null,\n      focusOnOpen: true,\n      disableParentScroll: true,\n      autoWrap: true,\n      fullscreen: false,\n      transformTemplate: function(template, options) {\n        // Make the dialog container focusable, because otherwise the focus will be always\n        // redirected to an element outside of the container, and the focus trap won't work.\n        // Also the tabindex is needed for the `escapeToClose` functionality, because\n        // the keyDown event can't be triggered when the focus is outside of the container.\n        var startSymbol = $interpolate.startSymbol();\n        var endSymbol = $interpolate.endSymbol();\n        var theme = startSymbol + (options.themeWatch ? '' : '::') + 'theme' + endSymbol;\n        var themeAttr = (options.hasTheme) ? 'md-theme=\"'+theme+'\"': '';\n        return '<div class=\"md-dialog-container\" tabindex=\"-1\" ' + themeAttr + '>' + validatedTemplate(template) + '</div>';\n\n        /**\n         * The specified template should contain a <md-dialog> wrapper element....\n         */\n        function validatedTemplate(template) {\n          if (options.autoWrap && !/<\\/md-dialog>/g.test(template)) {\n            return '<md-dialog>' + (template || '') + '</md-dialog>';\n          } else {\n            return template || '';\n          }\n        }\n      }\n    };\n\n    function beforeCompile(options) {\n      // Automatically apply the theme, if the user didn't specify a theme explicitly.\n      // Those option changes need to be done, before the compilation has started, because otherwise\n      // the option changes will be not available in the $mdCompilers locales.\n      options.defaultTheme = $mdTheming.defaultTheme();\n\n      detectTheming(options);\n    }\n\n    function beforeShow(scope, element, options, controller) {\n\n      if (controller) {\n        var mdHtmlContent = controller.htmlContent || options.htmlContent || '';\n        var mdTextContent = controller.textContent || options.textContent || '';\n\n        if (mdHtmlContent && !$injector.has('$sanitize')) {\n          throw Error('The ngSanitize module must be loaded in order to use htmlContent.');\n        }\n\n        if (mdHtmlContent && mdTextContent) {\n          throw Error('md-dialog cannot have both `htmlContent` and `textContent`');\n        }\n\n        // Only assign the content if nothing throws, otherwise it'll still be compiled.\n        controller.mdHtmlContent = mdHtmlContent;\n        controller.mdTextContent = mdTextContent;\n      }\n    }\n\n    /** Show method for dialogs */\n    function onShow(scope, element, options) {\n      angular.element($document[0].body).addClass('md-dialog-is-showing');\n\n      var dialogElement = element.find('md-dialog');\n\n      // Once a dialog has `ng-cloak` applied on his template the dialog animation will not work\n      // properly. This is a very common problem, so we have to notify the developer about this.\n      if (dialogElement.hasClass('ng-cloak')) {\n        var message =\n          '$mdDialog: using `<md-dialog ng-cloak>` will affect the dialog opening animations.';\n        $log.warn(message, element[0]);\n      }\n\n      captureParentAndFromToElements(options);\n      configureAria(dialogElement, options);\n      showBackdrop(scope, element, options);\n      activateListeners(element, options);\n\n      return dialogPopIn(element, options)\n        .then(function() {\n          lockScreenReader(element, options);\n          focusOnOpen();\n        });\n\n      /**\n       * For alerts, focus on content... otherwise focus on the close button (or equivalent)\n       */\n      function focusOnOpen() {\n        if (options.focusOnOpen) {\n          var target = $mdUtil.findFocusTarget(element) || findCloseButton() || dialogElement;\n          target.focus();\n        }\n\n        /**\n         * If no element with class dialog-close, try to find the last\n         * button child in md-dialog-actions and assume it is a close button.\n         *\n         * If we find no actions at all, log a warning to the console.\n         */\n        function findCloseButton() {\n          return element[0].querySelector('.dialog-close, md-dialog-actions button:last-child');\n        }\n      }\n    }\n\n    /**\n     * Remove function for all dialogs\n     */\n    function onRemove(scope, element, options) {\n      options.deactivateListeners();\n      options.unlockScreenReader();\n      options.hideBackdrop(options.$destroy);\n\n      // Remove the focus traps that we added earlier for keeping focus within the dialog.\n      if (removeFocusTrap) {\n        removeFocusTrap();\n        removeFocusTrap = null;\n      }\n\n      // For navigation $destroy events, do a quick, non-animated removal,\n      // but for normal closes (from clicks, etc) animate the removal\n      return options.$destroy ? detachAndClean() : animateRemoval().then(detachAndClean);\n\n      /**\n       * For normal closes, animate the removal.\n       * For forced closes (like $destroy events), skip the animations\n       */\n      function animateRemoval() {\n        return dialogPopOut(element, options);\n      }\n\n      /**\n       * Detach the element\n       */\n      function detachAndClean() {\n        angular.element($document[0].body).removeClass('md-dialog-is-showing');\n\n        // Reverse the container stretch if using a content element.\n        if (options.contentElement) {\n          options.reverseContainerStretch();\n        }\n\n        // Exposed cleanup function from the $mdCompiler.\n        options.cleanupElement();\n\n        // Restores the focus to the origin element if the last interaction upon opening was a keyboard.\n        if (!options.$destroy && options.originInteraction === 'keyboard') {\n          options.origin.focus();\n        }\n      }\n    }\n\n    function detectTheming(options) {\n      // Once the user specifies a targetEvent, we will automatically try to find the correct\n      // nested theme.\n      var targetEl;\n      if (options.targetEvent && options.targetEvent.target) {\n        targetEl = angular.element(options.targetEvent.target);\n      }\n\n      var themeCtrl = targetEl && targetEl.controller('mdTheme');\n\n      options.hasTheme = (!!themeCtrl);\n\n      if (!options.hasTheme) {\n        return;\n      }\n\n      options.themeWatch = themeCtrl.$shouldWatch;\n\n      var theme = options.theme || themeCtrl.$mdTheme;\n\n      if (theme) {\n        options.scope.theme = theme;\n      }\n\n      var unwatch = themeCtrl.registerChanges(function (newTheme) {\n        options.scope.theme = newTheme;\n\n        if (!options.themeWatch) {\n          unwatch();\n        }\n      });\n    }\n\n    /**\n     * Capture originator/trigger/from/to element information (if available)\n     * and the parent container for the dialog; defaults to the $rootElement\n     * unless overridden in the options.parent\n     */\n    function captureParentAndFromToElements(options) {\n          options.origin = angular.extend({\n            element: null,\n            bounds: null,\n            focus: angular.noop\n          }, options.origin || {});\n\n          options.parent   = getDomElement(options.parent, $rootElement);\n          options.closeTo  = getBoundingClientRect(getDomElement(options.closeTo));\n          options.openFrom = getBoundingClientRect(getDomElement(options.openFrom));\n\n          if (options.targetEvent) {\n            options.origin = getBoundingClientRect(options.targetEvent.target, options.origin);\n            options.originInteraction = $mdInteraction.getLastInteractionType();\n          }\n\n\n          /**\n           * Identify the bounding RECT for the target element\n           *\n           */\n          function getBoundingClientRect (element, orig) {\n            var source = angular.element((element || {}));\n            if (source && source.length) {\n              // Compute and save the target element's bounding rect, so that if the\n              // element is hidden when the dialog closes, we can shrink the dialog\n              // back to the same position it expanded from.\n              //\n              // Checking if the source is a rect object or a DOM element\n              var bounds = {top:0,left:0,height:0,width:0};\n              var hasFn = angular.isFunction(source[0].getBoundingClientRect);\n\n              return angular.extend(orig || {}, {\n                  element : hasFn ? source : undefined,\n                  bounds  : hasFn ? source[0].getBoundingClientRect() : angular.extend({}, bounds, source[0]),\n                  focus   : angular.bind(source, source.focus),\n              });\n            }\n          }\n\n          /**\n           * If the specifier is a simple string selector, then query for\n           * the DOM element.\n           */\n          function getDomElement(element, defaultElement) {\n            if (angular.isString(element)) {\n              element = $document[0].querySelector(element);\n            }\n\n            // If we have a reference to a raw dom element, always wrap it in jqLite\n            return angular.element(element || defaultElement);\n          }\n\n        }\n\n    /**\n     * Listen for escape keys and outside clicks to auto close\n     */\n    function activateListeners(element, options) {\n      var window = angular.element($window);\n      var onWindowResize = $mdUtil.debounce(function() {\n        stretchDialogContainerToViewport(element, options);\n      }, 60);\n\n      var removeListeners = [];\n      var smartClose = function() {\n        // Only 'confirm' dialogs have a cancel button... escape/clickOutside will\n        // cancel or fallback to hide.\n        var closeFn = (options.$type === 'alert') ? $mdDialog.hide : $mdDialog.cancel;\n        $mdUtil.nextTick(closeFn, true);\n      };\n\n      if (options.escapeToClose) {\n        var parentTarget = options.parent;\n        var keyHandlerFn = function(ev) {\n          if (ev.keyCode === $mdConstant.KEY_CODE.ESCAPE) {\n            ev.stopImmediatePropagation();\n            ev.preventDefault();\n\n            smartClose();\n          }\n        };\n\n        // Add keydown listeners\n        element.on('keydown', keyHandlerFn);\n        parentTarget.on('keydown', keyHandlerFn);\n\n        // Queue remove listeners function\n        removeListeners.push(function() {\n          element.off('keydown', keyHandlerFn);\n          parentTarget.off('keydown', keyHandlerFn);\n        });\n      }\n\n      // Register listener to update dialog on window resize\n      window.on('resize', onWindowResize);\n\n      removeListeners.push(function() {\n        window.off('resize', onWindowResize);\n      });\n\n      if (options.clickOutsideToClose) {\n        var target = element;\n        var sourceElem;\n\n        // Keep track of the element on which the mouse originally went down\n        // so that we can only close the backdrop when the 'click' started on it.\n        // A simple 'click' handler does not work,\n        // it sets the target object as the element the mouse went down on.\n        var mousedownHandler = function(ev) {\n          sourceElem = ev.target;\n        };\n\n        // We check if our original element and the target is the backdrop\n        // because if the original was the backdrop and the target was inside the dialog\n        // we don't want to dialog to close.\n        var mouseupHandler = function(ev) {\n          if (sourceElem === target[0] && ev.target === target[0]) {\n            ev.stopPropagation();\n            ev.preventDefault();\n\n            smartClose();\n          }\n        };\n\n        // Add listeners\n        target.on('mousedown', mousedownHandler);\n        target.on('mouseup', mouseupHandler);\n\n        // Queue remove listeners function\n        removeListeners.push(function() {\n          target.off('mousedown', mousedownHandler);\n          target.off('mouseup', mouseupHandler);\n        });\n      }\n\n      // Attach specific `remove` listener handler\n      options.deactivateListeners = function() {\n        removeListeners.forEach(function(removeFn) {\n          removeFn();\n        });\n        options.deactivateListeners = null;\n      };\n    }\n\n    /**\n     * Show modal backdrop element...\n     */\n    function showBackdrop(scope, element, options) {\n\n      if (options.disableParentScroll) {\n        // !! DO this before creating the backdrop; since disableScrollAround()\n        //    configures the scroll offset; which is used by mdBackDrop postLink()\n        options.restoreScroll = $mdUtil.disableScrollAround(element, options.parent);\n      }\n\n      if (options.hasBackdrop) {\n        options.backdrop = $mdUtil.createBackdrop(scope, \"md-dialog-backdrop md-opaque\");\n        $animate.enter(options.backdrop, options.parent);\n      }\n\n      /**\n       * Hide modal backdrop element...\n       */\n      options.hideBackdrop = function hideBackdrop($destroy) {\n        if (options.backdrop) {\n          if ($destroy) {\n            options.backdrop.remove();\n          } else {\n            $animate.leave(options.backdrop);\n          }\n        }\n\n        if (options.disableParentScroll) {\n          options.restoreScroll && options.restoreScroll();\n          delete options.restoreScroll;\n        }\n\n        options.hideBackdrop = null;\n      };\n    }\n\n    /**\n     * Inject ARIA-specific attributes appropriate for Dialogs\n     */\n    function configureAria(element, options) {\n\n      var role = (options.$type === 'alert') ? 'alertdialog' : 'dialog';\n      var dialogContent = element.find('md-dialog-content');\n      var existingDialogId = element.attr('id');\n      var dialogContentId = 'dialogContent_' + (existingDialogId || $mdUtil.nextUid());\n\n      element.attr({\n        'role': role,\n        'tabIndex': '-1'\n      });\n\n      if (dialogContent.length === 0) {\n        dialogContent = element;\n        // If the dialog element already had an ID, don't clobber it.\n        if (existingDialogId) {\n          dialogContentId = existingDialogId;\n        }\n      }\n\n      dialogContent.attr('id', dialogContentId);\n      element.attr('aria-describedby', dialogContentId);\n\n      if (options.ariaLabel) {\n        $mdAria.expect(element, 'aria-label', options.ariaLabel);\n      }\n      else {\n        $mdAria.expectAsync(element, 'aria-label', function() {\n          // If dialog title is specified, set aria-label with it\n          // See https://github.com/angular/material/issues/10582\n          if (options.title) {\n            return options.title;\n          } else {\n            var words = dialogContent.text().split(/\\s+/);\n            if (words.length > 3) words = words.slice(0, 3).concat('...');\n            return words.join(' ');\n          }\n        });\n      }\n\n      // Set up elements before and after the dialog content to capture focus and\n      // redirect back into the dialog.\n      topFocusTrap = document.createElement('div');\n      topFocusTrap.classList.add('md-dialog-focus-trap');\n      topFocusTrap.tabIndex = 0;\n\n      bottomFocusTrap = topFocusTrap.cloneNode(false);\n\n      /**\n       * When focus is about to move out of the end of the dialog, we intercept it and redirect it\n       * back to the md-dialog element.\n       * When focus is about to move out of the start of the dialog, we intercept it and redirect it\n       * back to the last focusable element in the md-dialog.\n       * @param {FocusEvent} event\n       */\n      var focusHandler = function(event) {\n        if (event.target && event.target.nextSibling &&\n            event.target.nextSibling.nodeName === 'MD-DIALOG') {\n          var lastFocusableElement = $mdUtil.getLastTabbableElement(element[0]);\n          if (angular.isElement(lastFocusableElement)) {\n            lastFocusableElement.focus();\n          }\n        } else {\n          element.focus();\n        }\n      };\n\n      topFocusTrap.addEventListener('focus', focusHandler);\n      bottomFocusTrap.addEventListener('focus', focusHandler);\n\n      removeFocusTrap = function () {\n        topFocusTrap.removeEventListener('focus', focusHandler);\n        bottomFocusTrap.removeEventListener('focus', focusHandler);\n\n        if (topFocusTrap && topFocusTrap.parentNode) {\n          topFocusTrap.parentNode.removeChild(topFocusTrap);\n        }\n\n        if (bottomFocusTrap && bottomFocusTrap.parentNode) {\n          bottomFocusTrap.parentNode.removeChild(bottomFocusTrap);\n        }\n      };\n\n      // The top focus trap inserted immediately before the md-dialog element (as a sibling).\n      // The bottom focus trap is inserted immediately after the md-dialog element (as a sibling).\n      element[0].parentNode.insertBefore(topFocusTrap, element[0]);\n      element.after(bottomFocusTrap);\n    }\n\n    /**\n     * Prevents screen reader interaction behind modal window on swipe interfaces.\n     */\n    function lockScreenReader(element, options) {\n      var isHidden = true;\n\n      // get raw DOM node\n      walkDOM(element[0]);\n\n      options.unlockScreenReader = function () {\n        isHidden = false;\n        walkDOM(element[0]);\n\n        options.unlockScreenReader = null;\n      };\n\n      /**\n       * Get all of an element's parent elements up the DOM tree.\n       * @param {Node & ParentNode} element the element to start from\n       * @return {Element[]} The parent elements\n       */\n      function getParents(element) {\n        var parents = [];\n        while (element.parentNode) {\n          if (element === document.body) {\n            return parents;\n          }\n          var children = element.parentNode.children;\n          for (var i = 0; i < children.length; i++) {\n            // skip over child if it is an ascendant of the dialog\n            // a script or style tag, or a live region.\n            if (element !== children[i] &&\n                !isNodeOneOf(children[i], ['SCRIPT', 'STYLE']) &&\n                !children[i].hasAttribute('aria-live')) {\n              parents.push(children[i]);\n            }\n          }\n          element = element.parentNode;\n        }\n        return parents;\n      }\n\n      /**\n       * Walk DOM to apply or remove aria-hidden on sibling nodes and parent sibling nodes.\n       * @param {Element} element the element to start from when walking up the DOM\n       * @returns {void}\n       */\n      function walkDOM(element) {\n        var elements = getParents(element);\n        for (var i = 0; i < elements.length; i++) {\n          elements[i].setAttribute('aria-hidden', isHidden);\n        }\n      }\n    }\n\n    /**\n     * Ensure the dialog container fill-stretches to the viewport.\n     * @param {JQLite} container dialog container\n     * @param {Object} options\n     * @returns {function(): void} function that reverts the modified styles\n     */\n    function stretchDialogContainerToViewport(container, options) {\n      var isFixed = $window.getComputedStyle($document[0].body).position === 'fixed';\n      var backdrop = options.backdrop ? $window.getComputedStyle(options.backdrop[0]) : null;\n      var height = backdrop ?\n        Math.min($document[0].body.clientHeight, Math.ceil(Math.abs(parseInt(backdrop.height, 10))))\n        : 0;\n\n      var previousStyles = {\n        top: container.css('top'),\n        height: container.css('height')\n      };\n\n      // If the body is fixed, determine the distance to the viewport in relative from the parent.\n      var parentTop = Math.abs(options.parent[0].getBoundingClientRect().top);\n\n      container.css({\n        top: (isFixed ? parentTop : 0) + 'px',\n        height: height ? height + 'px' : '100%'\n      });\n\n      return function() {\n        // Reverts the modified styles back to the previous values.\n        // This is needed for contentElements, which should have the same styles after close\n        // as before.\n        container.css(previousStyles);\n      };\n    }\n\n    /**\n     * Dialog open and pop-in animation.\n     * @param {JQLite} container dialog container\n     * @param {Object} options\n     * @returns {*}\n     */\n    function dialogPopIn(container, options) {\n      // Add the `md-dialog-container` to the DOM\n      options.parent.append(container);\n      options.reverseContainerStretch = stretchDialogContainerToViewport(container, options);\n\n      var dialogEl = container.find('md-dialog');\n      var animator = $mdUtil.dom.animator;\n      var buildTranslateToOrigin = animator.calculateZoomToOrigin;\n      var translateOptions = {transitionInClass: 'md-transition-in', transitionOutClass: 'md-transition-out'};\n      var from = animator.toTransformCss(buildTranslateToOrigin(dialogEl, options.openFrom || options.origin));\n      var to = animator.toTransformCss(\"\");  // defaults to center display (or parent or $rootElement)\n\n      dialogEl.toggleClass('md-dialog-fullscreen', !!options.fullscreen);\n\n      return animator\n        .translate3d(dialogEl, from, to, translateOptions)\n        .then(function(animateReversal) {\n\n          // Build a reversal translate function synced to this translation...\n          options.reverseAnimate = function() {\n            delete options.reverseAnimate;\n\n            if (options.closeTo) {\n              // Using the opposite classes to create a close animation to the closeTo element\n              translateOptions = {transitionInClass: 'md-transition-out', transitionOutClass: 'md-transition-in'};\n              from = to;\n              to = animator.toTransformCss(buildTranslateToOrigin(dialogEl, options.closeTo));\n\n              return animator\n                .translate3d(dialogEl, from, to,translateOptions);\n            }\n\n            return animateReversal(\n              to = animator.toTransformCss(\n                // in case the origin element has moved or is hidden,\n                // let's recalculate the translateCSS\n                buildTranslateToOrigin(dialogEl, options.origin)\n              )\n            );\n          };\n\n          // Function to revert the generated animation styles on the dialog element.\n          // Useful when using a contentElement instead of a template.\n          options.clearAnimate = function() {\n            delete options.clearAnimate;\n\n            // Remove the transition classes, added from $animateCSS, since those can't be removed\n            // by reversely running the animator.\n            dialogEl.removeClass([\n              translateOptions.transitionOutClass,\n              translateOptions.transitionInClass\n            ].join(' '));\n\n            // Run the animation reversely to remove the previous added animation styles.\n            return animator.translate3d(dialogEl, to, animator.toTransformCss(''), {});\n          };\n\n          return true;\n        });\n    }\n\n    /**\n     * Dialog close and pop-out animation.\n     * @param {JQLite} container dialog container\n     * @param {Object} options\n     * @returns {*}\n     */\n    function dialogPopOut(container, options) {\n      return options.reverseAnimate().then(function() {\n        if (options.contentElement) {\n          // When we use a contentElement, we want the element to be the same as before.\n          // That means, that we have to clear all the animation properties, like transform.\n          options.clearAnimate();\n        }\n      });\n    }\n\n    /**\n     * Utility function to filter out raw DOM nodes.\n     * @param {Node} elem\n     * @param {string[]} nodeTypeArray\n     * @returns {boolean}\n     */\n    function isNodeOneOf(elem, nodeTypeArray) {\n      return nodeTypeArray.indexOf(elem.nodeName) !== -1;\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.divider\n * @description Divider module!\n */\nMdDividerDirective.$inject = [\"$mdTheming\"];\nangular.module('material.components.divider', [\n  'material.core'\n])\n  .directive('mdDivider', MdDividerDirective);\n\n/**\n * @ngdoc directive\n * @name mdDivider\n * @module material.components.divider\n * @restrict E\n *\n * @description\n * Dividers group and separate content within lists and page layouts using strong visual and spatial distinctions. This divider is a thin rule, lightweight enough to not distract the user from content.\n *\n * @param {boolean=} md-inset Add this attribute to activate the inset divider style.\n * @usage\n * <hljs lang=\"html\">\n * <md-divider></md-divider>\n *\n * <md-divider md-inset></md-divider>\n * </hljs>\n *\n */\nfunction MdDividerDirective($mdTheming) {\n  return {\n    restrict: 'E',\n    link: $mdTheming\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  /**\n   * @ngdoc module\n   * @name material.components.fabActions\n   */\n  MdFabActionsDirective.$inject = [\"$mdUtil\"];\n  angular\n    .module('material.components.fabActions', ['material.core'])\n    .directive('mdFabActions', MdFabActionsDirective);\n\n  /**\n   * @ngdoc directive\n   * @name mdFabActions\n   * @module material.components.fabActions\n   *\n   * @restrict E\n   *\n   * @description\n   * The `<md-fab-actions>` directive is used inside of a `<md-fab-speed-dial>` or\n   * `<md-fab-toolbar>` directive to mark an element (or elements) as the actions and setup the\n   * proper event listeners.\n   *\n   * @usage\n   * See the `<md-fab-speed-dial>` or `<md-fab-toolbar>` directives for example usage.\n   */\n  function MdFabActionsDirective($mdUtil) {\n    return {\n      restrict: 'E',\n\n      require: ['^?mdFabSpeedDial', '^?mdFabToolbar'],\n\n      compile: function(element, attributes) {\n        var children = element.children();\n        var actionItemButtons;\n        var hasNgRepeat = $mdUtil.prefixer().hasAttribute(children, 'ng-repeat');\n\n        // Action item buttons should not be in the tab order when the speed dial is closed.\n        actionItemButtons = element.find('md-button');\n        angular.forEach(actionItemButtons, function(button) {\n          button.setAttribute('tabindex', -1);\n        });\n\n        // Support both ng-repeat and static content\n        if (hasNgRepeat) {\n          children.addClass('md-fab-action-item');\n        } else {\n          // Wrap every child in a new div and add a class that we can scale/fling independently\n          children.wrap('<div class=\"md-fab-action-item\">');\n        }\n      }\n    };\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  MdFabController.$inject = [\"$scope\", \"$element\", \"$animate\", \"$mdUtil\", \"$mdConstant\", \"$timeout\"];\n  angular.module('material.components.fabShared', ['material.core'])\n    .controller('MdFabController', MdFabController);\n\n  function MdFabController($scope, $element, $animate, $mdUtil, $mdConstant, $timeout) {\n    var ctrl = this;\n    var initialAnimationAttempts = 0;\n\n    // NOTE: We use async eval(s) below to avoid conflicts with any existing digest loops\n\n    ctrl.open = function() {\n      $scope.$evalAsync(\"ctrl.isOpen = true\");\n    };\n\n    ctrl.close = function() {\n      // Async eval to avoid conflicts with existing digest loops\n      $scope.$evalAsync(\"ctrl.isOpen = false\");\n\n      // Focus the trigger when the element closes so users can still tab to the next item\n      $element.find('md-fab-trigger')[0].focus();\n    };\n\n    // Toggle the open/close state when the trigger is clicked\n    ctrl.toggle = function() {\n      $scope.$evalAsync(\"ctrl.isOpen = !ctrl.isOpen\");\n    };\n\n    /*\n     * AngularJS Lifecycle hook for newer AngularJS versions.\n     * Bindings are not guaranteed to have been assigned in the controller, but they are in the\n     * $onInit hook.\n     */\n    ctrl.$onInit = function() {\n      setupDefaults();\n      setupListeners();\n      setupWatchers();\n\n      fireInitialAnimations();\n    };\n\n    // For AngularJS 1.4 and older, where there are no lifecycle hooks but bindings are pre-assigned,\n    // manually call the $onInit hook.\n    if (angular.version.major === 1 && angular.version.minor <= 4) {\n      this.$onInit();\n    }\n\n    function setupDefaults() {\n      // Set the default direction to 'down' if none is specified\n      ctrl.direction = ctrl.direction || 'down';\n\n      // Set the default to be closed\n      ctrl.isOpen = ctrl.isOpen || false;\n\n      // Start the keyboard interaction at the first action\n      resetActionIndex();\n\n      // Add an animations waiting class so we know not to run\n      $element.addClass('md-animations-waiting');\n    }\n\n    function setupListeners() {\n      var eventTypes = [\n        'click', 'focusin', 'focusout'\n      ];\n\n      // Add our listeners\n      angular.forEach(eventTypes, function(eventType) {\n        $element.on(eventType, parseEvents);\n      });\n\n      // Remove our listeners when destroyed\n      $scope.$on('$destroy', function() {\n        angular.forEach(eventTypes, function(eventType) {\n          $element.off(eventType, parseEvents);\n        });\n\n        // remove any attached keyboard handlers in case element is removed while\n        // speed dial is open\n        disableKeyboard();\n      });\n    }\n\n    var closeTimeout;\n\n    /**\n     * @param {MouseEvent} event\n     */\n    function parseEvents(event) {\n      // If the event is a click, just handle it\n      if (event.type == 'click') {\n        handleItemClick(event);\n      }\n\n      // If we focusout, set a timeout to close the element\n      if (event.type == 'focusout' && !closeTimeout) {\n        closeTimeout = $timeout(function() {\n          ctrl.close();\n        }, 100, false);\n      }\n\n      // If we see a focusin and there is a timeout about to run, cancel it so we stay open\n      if (event.type == 'focusin' && closeTimeout) {\n        $timeout.cancel(closeTimeout);\n        closeTimeout = null;\n      }\n    }\n\n    function resetActionIndex() {\n      ctrl.currentActionIndex = -1;\n    }\n\n    function setupWatchers() {\n      // Watch for changes to the direction and update classes/attributes\n      $scope.$watch('ctrl.direction', function(newDir, oldDir) {\n        // Add the appropriate classes so we can target the direction in the CSS\n        $animate.removeClass($element, 'md-' + oldDir);\n        $animate.addClass($element, 'md-' + newDir);\n\n        // Reset the action index since it may have changed\n        resetActionIndex();\n      });\n\n      var trigger, actions;\n\n      // Watch for changes to md-open\n      $scope.$watch('ctrl.isOpen', function(isOpen) {\n        // Reset the action index since it may have changed\n        resetActionIndex();\n\n        // We can't get the trigger/actions outside of the watch because the component hasn't been\n        // linked yet, so we wait until the first watch fires to cache them.\n        if (!trigger || !actions) {\n          trigger = getTriggerElement();\n          actions = getActionsElement();\n        }\n\n        if (isOpen) {\n          enableKeyboard();\n        } else {\n          disableKeyboard();\n        }\n\n        var toAdd = isOpen ? 'md-is-open' : '';\n        var toRemove = isOpen ? '' : 'md-is-open';\n\n        // Set the proper ARIA attributes\n        trigger.attr('aria-haspopup', true);\n        trigger.attr('aria-expanded', isOpen);\n        actions.attr('aria-hidden', !isOpen);\n\n        // Animate the CSS classes\n        $animate.setClass($element, toAdd, toRemove);\n      });\n    }\n\n    function fireInitialAnimations() {\n      // If the element is actually visible on the screen\n      if ($element[0].scrollHeight > 0) {\n        // Fire our animation\n        $animate.addClass($element, '_md-animations-ready').then(function() {\n          // Remove the waiting class\n          $element.removeClass('md-animations-waiting');\n        });\n      }\n\n      // Otherwise, try for up to 1 second before giving up\n      else if (initialAnimationAttempts < 10) {\n        $timeout(fireInitialAnimations, 100);\n\n        // Increment our counter\n        initialAnimationAttempts = initialAnimationAttempts + 1;\n      }\n    }\n\n    function enableKeyboard() {\n      $element.on('keydown', keyPressed);\n\n      // On the next tick, setup a check for outside clicks; we do this on the next tick to avoid\n      // clicks/touches that result in the isOpen attribute changing (e.g. a bound radio button)\n      $mdUtil.nextTick(function() {\n        angular.element(document).on('click touchend', checkForOutsideClick);\n      });\n    }\n\n    function disableKeyboard() {\n      $element.off('keydown', keyPressed);\n      angular.element(document).off('click touchend', checkForOutsideClick);\n    }\n\n    function checkForOutsideClick(event) {\n      if (event.target) {\n        var closestTrigger = $mdUtil.getClosest(event.target, 'md-fab-trigger');\n        var closestActions = $mdUtil.getClosest(event.target, 'md-fab-actions');\n\n        if (!closestTrigger && !closestActions) {\n          ctrl.close();\n        }\n      }\n    }\n\n    /**\n     * @param {KeyboardEvent} event\n     * @returns {boolean}\n     */\n    function keyPressed(event) {\n      switch (event.which) {\n        case $mdConstant.KEY_CODE.ESCAPE: ctrl.close(); event.preventDefault(); return false;\n        case $mdConstant.KEY_CODE.LEFT_ARROW: doKeyLeft(event); return false;\n        case $mdConstant.KEY_CODE.UP_ARROW: doKeyUp(event); return false;\n        case $mdConstant.KEY_CODE.RIGHT_ARROW: doKeyRight(event); return false;\n        case $mdConstant.KEY_CODE.DOWN_ARROW: doKeyDown(event); return false;\n        case $mdConstant.KEY_CODE.TAB: doShift(event); return false;\n      }\n    }\n\n    function doActionPrev(event) {\n      focusAction(event, -1);\n    }\n\n    function doActionNext(event) {\n      focusAction(event, 1);\n    }\n\n    function focusAction(event, direction) {\n      var actions = getActionsElement()[0].querySelectorAll('.md-fab-action-item');\n      var previousActionIndex = ctrl.currentActionIndex;\n\n      // Increment/decrement the counter with restrictions\n      ctrl.currentActionIndex = ctrl.currentActionIndex + direction;\n      ctrl.currentActionIndex = Math.min(actions.length - 1, ctrl.currentActionIndex);\n      ctrl.currentActionIndex = Math.max(0, ctrl.currentActionIndex);\n\n      // Let Tab and Shift+Tab escape if we're trying to move past the start/end.\n      if (event.which !== $mdConstant.KEY_CODE.TAB ||\n          previousActionIndex !== ctrl.currentActionIndex) {\n        // Focus the element\n        var focusElement = angular.element(actions[ctrl.currentActionIndex]).children()[0];\n        focusElement.focus();\n\n        // Make sure the event doesn't bubble and cause something else\n        event.preventDefault();\n        event.stopImmediatePropagation();\n      }\n    }\n\n    function doKeyLeft(event) {\n      if (ctrl.direction === 'left') {\n        doActionNext(event);\n      } else {\n        doActionPrev(event);\n      }\n    }\n\n    function doKeyUp(event) {\n      if (ctrl.direction === 'down') {\n        doActionPrev(event);\n      } else {\n        doActionNext(event);\n      }\n    }\n\n    function doKeyRight(event) {\n      if (ctrl.direction === 'left') {\n        doActionPrev(event);\n      } else {\n        doActionNext(event);\n      }\n    }\n\n    function doKeyDown(event) {\n      if (ctrl.direction === 'up') {\n        doActionPrev(event);\n      } else {\n        doActionNext(event);\n      }\n    }\n\n    function doShift(event) {\n      if (event.shiftKey) {\n        doActionPrev(event);\n      } else {\n        doActionNext(event);\n      }\n    }\n\n    /**\n     * @param {Node} element\n     * @returns {Node|null}\n     */\n    function getClosestButton(element) {\n      return $mdUtil.getClosest(element, 'button') || $mdUtil.getClosest(element, 'md-button');\n    }\n\n    /**\n     * @param {Node} element\n     * @returns {Node|null}\n     */\n    function getClosestTrigger(element) {\n      return $mdUtil.getClosest(element, 'md-fab-trigger');\n    }\n\n    /**\n     * @param {Node} element\n     * @returns {Node|null}\n     */\n    function getClosestAction(element) {\n      return $mdUtil.getClosest(element, 'md-fab-actions');\n    }\n\n    /**\n     * @param {MouseEvent|FocusEvent} event\n     */\n    function handleItemClick(event) {\n      var closestButton = event.target ? getClosestButton(event.target) : null;\n\n      // Check that the button in the trigger is not disabled\n      if (closestButton && !closestButton.disabled) {\n        if (getClosestTrigger(event.target)) {\n          ctrl.toggle();\n        }\n      }\n\n      if (getClosestAction(event.target)) {\n        ctrl.close();\n      }\n    }\n\n    function getTriggerElement() {\n      return $element.find('md-fab-trigger');\n    }\n\n    function getActionsElement() {\n      return $element.find('md-fab-actions');\n    }\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  /**\n   * The duration of the CSS animation in milliseconds.\n   *\n   * @type {number}\n   */\n  MdFabSpeedDialFlingAnimation.$inject = [\"$timeout\"];\n  MdFabSpeedDialScaleAnimation.$inject = [\"$timeout\"];\n  var cssAnimationDuration = 300;\n\n  /**\n   * @ngdoc module\n   * @name material.components.fabSpeedDial\n   */\n  angular\n    // Declare our module\n    .module('material.components.fabSpeedDial', [\n      'material.core',\n      'material.components.fabShared',\n      'material.components.fabActions'\n    ])\n\n    // Register our directive\n    .directive('mdFabSpeedDial', MdFabSpeedDialDirective)\n\n    // Register our custom animations\n    .animation('.md-fling', MdFabSpeedDialFlingAnimation)\n    .animation('.md-scale', MdFabSpeedDialScaleAnimation)\n\n    // Register a service for each animation so that we can easily inject them into unit tests\n    .service('mdFabSpeedDialFlingAnimation', MdFabSpeedDialFlingAnimation)\n    .service('mdFabSpeedDialScaleAnimation', MdFabSpeedDialScaleAnimation);\n\n  /**\n   * @ngdoc directive\n   * @name mdFabSpeedDial\n   * @module material.components.fabSpeedDial\n   *\n   * @restrict E\n   *\n   * @description\n   * The `<md-fab-speed-dial>` directive is used to present a series of popup elements (usually\n   * `<md-button>`s) for quick access to common actions.\n   *\n   * There are currently two animations available by applying one of the following classes to\n   * the component:\n   *\n   *  - `md-fling` - The speed dial items appear from underneath the trigger and move into their\n   *    appropriate positions.\n   *  - `md-scale` - The speed dial items appear in their proper places by scaling from 0% to 100%.\n   *\n   * You may also easily position the trigger by applying one one of the following classes to the\n   * `<md-fab-speed-dial>` element:\n   *  - `md-fab-top-left`\n   *  - `md-fab-top-right`\n   *  - `md-fab-bottom-left`\n   *  - `md-fab-bottom-right`\n   *\n   * These CSS classes use `position: absolute`, so you need to ensure that the container element\n   * also uses `position: absolute` or `position: relative` in order for them to work.\n   *\n   * Additionally, you may use the standard `ng-mouseenter` and `ng-mouseleave` directives to\n   * open or close the speed dial. However, if you wish to allow users to hover over the empty\n   * space where the actions will appear, you must also add the `md-hover-full` class to the speed\n   * dial element. Without this, the hover effect will only occur on top of the trigger.\n   *\n   * See the demos for more information.\n   *\n   * ## Troubleshooting\n   *\n   * If your speed dial shows the closing animation upon launch, you may need to use `ng-cloak` on\n   * the parent container to ensure that it is only visible once ready. We have plans to remove this\n   * necessity in the future.\n   *\n   * @usage\n   * <hljs lang=\"html\">\n   * <md-fab-speed-dial md-direction=\"up\" class=\"md-fling\">\n   *   <md-fab-trigger>\n   *     <md-button aria-label=\"Add...\"><md-icon md-svg-src=\"/img/icons/plus.svg\"></md-icon></md-button>\n   *   </md-fab-trigger>\n   *\n   *   <md-fab-actions>\n   *     <md-button aria-label=\"Add User\">\n   *       <md-icon md-svg-src=\"/img/icons/user.svg\"></md-icon>\n   *     </md-button>\n   *\n   *     <md-button aria-label=\"Add Group\">\n   *       <md-icon md-svg-src=\"/img/icons/group.svg\"></md-icon>\n   *     </md-button>\n   *   </md-fab-actions>\n   * </md-fab-speed-dial>\n   * </hljs>\n   *\n   * @param {string} md-direction From which direction you would like the speed dial to appear\n   * relative to the trigger element.\n   * @param {expression=} md-open Programmatically control whether or not the speed-dial is visible.\n   */\n  function MdFabSpeedDialDirective() {\n    return {\n      restrict: 'E',\n\n      scope: {\n        direction: '@?mdDirection',\n        isOpen: '=?mdOpen'\n      },\n\n      bindToController: true,\n      controller: 'MdFabController',\n      controllerAs: 'ctrl',\n\n      link: FabSpeedDialLink\n    };\n\n    function FabSpeedDialLink(scope, element) {\n      // Prepend an element to hold our CSS variables so we can use them in the animations below\n      element.prepend('<div class=\"_md-css-variables\"></div>');\n    }\n  }\n\n  function MdFabSpeedDialFlingAnimation($timeout) {\n    function delayDone(done) { $timeout(done, cssAnimationDuration, false); }\n\n    function runAnimation(element) {\n      // Don't run if we are still waiting and we are not ready\n      if (element.hasClass('md-animations-waiting') && !element.hasClass('_md-animations-ready')) {\n        return;\n      }\n\n      var el = element[0];\n      var ctrl = element.controller('mdFabSpeedDial');\n      var items = el.querySelectorAll('.md-fab-action-item');\n\n      // Grab our trigger element\n      var triggerElement = el.querySelector('md-fab-trigger');\n\n      // Grab our element which stores CSS variables\n      var variablesElement = el.querySelector('._md-css-variables');\n\n      // Setup JS variables based on our CSS variables\n      var startZIndex = parseInt(window.getComputedStyle(variablesElement).zIndex);\n\n      // Always reset the items to their natural position/state\n      angular.forEach(items, function(item, index) {\n        var styles = item.style;\n\n        styles.transform = styles.webkitTransform = '';\n        styles.transitionDelay = '';\n        styles.opacity = ctrl.isOpen ? 1 : 0;\n\n        // Make the items closest to the trigger have the highest z-index\n        styles.zIndex = (items.length - index) + startZIndex;\n      });\n\n      // Set the trigger to be above all of the actions so they disappear behind it.\n      triggerElement.style.zIndex = startZIndex + items.length + 1;\n\n      // If the control is closed, hide the items behind the trigger\n      if (!ctrl.isOpen) {\n        angular.forEach(items, function(item, index) {\n          var newPosition, axis;\n          var styles = item.style;\n\n          // Make sure to account for differences in the dimensions of the trigger verses the items\n          // so that we can properly center everything; this helps hide the item's shadows behind\n          // the trigger.\n          var triggerItemHeightOffset = (triggerElement.clientHeight - item.clientHeight) / 2;\n          var triggerItemWidthOffset = (triggerElement.clientWidth - item.clientWidth) / 2;\n\n          switch (ctrl.direction) {\n            case 'up':\n              newPosition = (item.scrollHeight * (index + 1) + triggerItemHeightOffset);\n              axis = 'Y';\n              break;\n            case 'down':\n              newPosition = -(item.scrollHeight * (index + 1) + triggerItemHeightOffset);\n              axis = 'Y';\n              break;\n            case 'left':\n              newPosition = (item.scrollWidth * (index + 1) + triggerItemWidthOffset);\n              axis = 'X';\n              break;\n            case 'right':\n              newPosition = -(item.scrollWidth * (index + 1) + triggerItemWidthOffset);\n              axis = 'X';\n              break;\n          }\n\n          var newTranslate = 'translate' + axis + '(' + newPosition + 'px)';\n\n          styles.transform = styles.webkitTransform = newTranslate;\n        });\n      }\n    }\n\n    return {\n      addClass: function(element, className, done) {\n        if (element.hasClass('md-fling')) {\n          runAnimation(element);\n          delayDone(done);\n        } else {\n          done();\n        }\n      },\n      removeClass: function(element, className, done) {\n        runAnimation(element);\n        delayDone(done);\n      }\n    };\n  }\n\n  function MdFabSpeedDialScaleAnimation($timeout) {\n    function delayDone(done) { $timeout(done, cssAnimationDuration, false); }\n\n    var delay = 65;\n\n    function runAnimation(element) {\n      var el = element[0];\n      var ctrl = element.controller('mdFabSpeedDial');\n      var items = el.querySelectorAll('.md-fab-action-item');\n\n      // Grab our element which stores CSS variables\n      var variablesElement = el.querySelector('._md-css-variables');\n\n      // Setup JS variables based on our CSS variables\n      var startZIndex = parseInt(window.getComputedStyle(variablesElement).zIndex);\n\n      // Always reset the items to their natural position/state\n      angular.forEach(items, function(item, index) {\n        var styles = item.style,\n          offsetDelay = index * delay;\n\n        styles.opacity = ctrl.isOpen ? 1 : 0;\n        styles.transform = styles.webkitTransform = ctrl.isOpen ? 'scale(1)' : 'scale(0)';\n        styles.transitionDelay = (ctrl.isOpen ? offsetDelay : (items.length - offsetDelay)) + 'ms';\n\n        // Make the items closest to the trigger have the highest z-index\n        styles.zIndex = (items.length - index) + startZIndex;\n      });\n    }\n\n    return {\n      addClass: function(element, className, done) {\n        runAnimation(element);\n        delayDone(done);\n      },\n\n      removeClass: function(element, className, done) {\n        runAnimation(element);\n        delayDone(done);\n      }\n    };\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\n(function() {\n  'use strict';\n\n  /**\n   * @ngdoc module\n   * @name material.components.fabToolbar\n   */\n  angular\n    // Declare our module\n    .module('material.components.fabToolbar', [\n      'material.core',\n      'material.components.fabShared',\n      'material.components.fabActions'\n    ])\n\n    // Register our directive\n    .directive('mdFabToolbar', MdFabToolbarDirective)\n\n    // Register our custom animations\n    .animation('.md-fab-toolbar', MdFabToolbarAnimation)\n\n    // Register a service for the animation so that we can easily inject it into unit tests\n    .service('mdFabToolbarAnimation', MdFabToolbarAnimation);\n\n  /**\n   * @ngdoc directive\n   * @name mdFabToolbar\n   * @module material.components.fabToolbar\n   *\n   * @restrict E\n   *\n   * @description\n   *\n   * The `<md-fab-toolbar>` directive is used to present a toolbar of elements (usually `<md-button>`s)\n   * for quick access to common actions when a floating action button is activated (via click or\n   * keyboard navigation).\n   *\n   * You may also easily position the trigger by applying one one of the following classes to the\n   * `<md-fab-toolbar>` element:\n   *  - `md-fab-top-left`\n   *  - `md-fab-top-right`\n   *  - `md-fab-bottom-left`\n   *  - `md-fab-bottom-right`\n   *\n   * These CSS classes use `position: absolute`, so you need to ensure that the container element\n   * also uses `position: absolute` or `position: relative` in order for them to work.\n   *\n   * @usage\n   *\n   * <hljs lang=\"html\">\n   * <md-fab-toolbar md-direction='left'>\n   *   <md-fab-trigger>\n   *     <md-button aria-label=\"Add...\"><md-icon md-svg-src=\"/img/icons/plus.svg\"></md-icon></md-button>\n   *   </md-fab-trigger>\n   *\n   *   <md-toolbar>\n   *    <md-fab-actions>\n   *      <md-button aria-label=\"Add User\">\n   *        <md-icon md-svg-src=\"/img/icons/user.svg\"></md-icon>\n   *      </md-button>\n   *\n   *      <md-button aria-label=\"Add Group\">\n   *        <md-icon md-svg-src=\"/img/icons/group.svg\"></md-icon>\n   *      </md-button>\n   *    </md-fab-actions>\n   *   </md-toolbar>\n   * </md-fab-toolbar>\n   * </hljs>\n   *\n   * @param {string} md-direction From which direction you would like the toolbar items to appear\n   * relative to the trigger element. Supports `left` and `right` directions.\n   * @param {expression=} md-open Programmatically control whether or not the toolbar is visible.\n   */\n  function MdFabToolbarDirective() {\n    return {\n      restrict: 'E',\n      transclude: true,\n      template: '<div class=\"md-fab-toolbar-wrapper\">' +\n      '  <div class=\"md-fab-toolbar-content\" ng-transclude></div>' +\n      '</div>',\n\n      scope: {\n        direction: '@?mdDirection',\n        isOpen: '=?mdOpen'\n      },\n\n      bindToController: true,\n      controller: 'MdFabController',\n      controllerAs: 'ctrl',\n\n      link: link\n    };\n\n    function link(scope, element, attributes) {\n      // Add the base class for animations\n      element.addClass('md-fab-toolbar');\n\n      // Prepend the background element to the trigger's button\n      element.find('md-fab-trigger').find('button')\n        .prepend('<div class=\"md-fab-toolbar-background\"></div>');\n    }\n  }\n\n  function MdFabToolbarAnimation() {\n\n    function runAnimation(element, className, done) {\n      // If no className was specified, don't do anything\n      if (!className) {\n        return;\n      }\n\n      var el = element[0];\n      var ctrl = element.controller('mdFabToolbar');\n\n      // Grab the relevant child elements\n      var backgroundElement = el.querySelector('.md-fab-toolbar-background');\n      var triggerElement = el.querySelector('md-fab-trigger button');\n      var toolbarElement = el.querySelector('md-toolbar');\n      var iconElement = el.querySelector('md-fab-trigger button md-icon');\n      var actions = element.find('md-fab-actions').children();\n\n      // If we have both elements, use them to position the new background\n      if (triggerElement && backgroundElement) {\n        // Get our variables\n        var color = window.getComputedStyle(triggerElement).getPropertyValue('background-color');\n        var width = el.offsetWidth;\n        var height = el.offsetHeight;\n\n        // Make it twice as big as it should be since we scale from the center\n        var scale = 2 * (width / triggerElement.offsetWidth);\n\n        // Set some basic styles no matter what animation we're doing\n        backgroundElement.style.backgroundColor = color;\n        backgroundElement.style.borderRadius = width + 'px';\n\n        // If we're open\n        if (ctrl.isOpen) {\n          // Turn on toolbar pointer events when closed\n          toolbarElement.style.pointerEvents = 'inherit';\n\n          backgroundElement.style.width = triggerElement.offsetWidth + 'px';\n          backgroundElement.style.height = triggerElement.offsetHeight + 'px';\n          backgroundElement.style.transform = 'scale(' + scale + ')';\n\n          // Set the next close animation to have the proper delays\n          backgroundElement.style.transitionDelay = '0ms';\n          iconElement && (iconElement.style.transitionDelay = '.3s');\n\n          // Apply a transition delay to actions\n          angular.forEach(actions, function(action, index) {\n            action.style.transitionDelay = (actions.length - index) * 25 + 'ms';\n          });\n        } else {\n          // Turn off toolbar pointer events when closed\n          toolbarElement.style.pointerEvents = 'none';\n\n          // Scale it back down to the trigger's size\n          backgroundElement.style.transform = 'scale(1)';\n\n          // Reset the position\n          backgroundElement.style.top = '0';\n\n          if (element.hasClass('md-right')) {\n            backgroundElement.style.left = '0';\n            backgroundElement.style.right = null;\n          }\n\n          if (element.hasClass('md-left')) {\n            backgroundElement.style.right = '0';\n            backgroundElement.style.left = null;\n          }\n\n          // Set the next open animation to have the proper delays\n          backgroundElement.style.transitionDelay = '200ms';\n          iconElement && (iconElement.style.transitionDelay = '0ms');\n\n          // Apply a transition delay to actions\n          angular.forEach(actions, function(action, index) {\n            action.style.transitionDelay = 200 + (index * 25) + 'ms';\n          });\n        }\n      }\n    }\n\n    return {\n      addClass: function(element, className, done) {\n        runAnimation(element, className, done);\n        done();\n      },\n\n      removeClass: function(element, className, done) {\n        runAnimation(element, className, done);\n        done();\n      }\n    };\n  }\n})();\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.gridList\n */\nGridListController.$inject = [\"$mdUtil\"];\nGridLayoutFactory.$inject = [\"$mdUtil\"];\nGridListDirective.$inject = [\"$interpolate\", \"$mdConstant\", \"$mdGridLayout\", \"$mdMedia\", \"$mdUtil\"];\nGridTileDirective.$inject = [\"$mdMedia\"];\nangular.module('material.components.gridList', ['material.core'])\n       .directive('mdGridList', GridListDirective)\n       .directive('mdGridTile', GridTileDirective)\n       .directive('mdGridTileFooter', GridTileCaptionDirective)\n       .directive('mdGridTileHeader', GridTileCaptionDirective)\n       .factory('$mdGridLayout', GridLayoutFactory);\n\n/**\n * @ngdoc directive\n * @name mdGridList\n * @module material.components.gridList\n * @restrict E\n * @description\n * Grid lists are an alternative to standard list views. Grid lists are distinct\n * from grids used for layouts and other visual presentations.\n *\n * A grid list is best suited to presenting a homogenous data type, typically\n * images, and is optimized for visual comprehension and differentiating between\n * like data types.\n *\n * A grid list is a continuous element consisting of tessellated, regular\n * subdivisions called cells that contain tiles (`md-grid-tile`).\n *\n * <img src=\"//material-design.storage.googleapis.com/publish/v_2/material_ext_publish/0Bx4BSt6jniD7OVlEaXZ5YmU1Xzg/components_grids_usage2.png\"\n *    style=\"width: 300px; height: auto; margin-right: 16px;\" alt=\"Concept of grid explained visually\">\n * <img src=\"//material-design.storage.googleapis.com/publish/v_2/material_ext_publish/0Bx4BSt6jniD7VGhsOE5idWlJWXM/components_grids_usage3.png\"\n *    style=\"width: 300px; height: auto;\" alt=\"Grid concepts legend\">\n *\n * Cells are arrayed vertically and horizontally within the grid.\n *\n * Tiles hold content and can span one or more cells vertically or horizontally.\n *\n * ### Responsive Attributes\n *\n * The `md-grid-list` directive supports \"responsive\" attributes, which allow\n * different `md-cols`, `md-gutter` and `md-row-height` values depending on the\n * currently matching media query.\n *\n * In order to set a responsive attribute, first define the fallback value with\n * the standard attribute name, then add additional attributes with the\n * following convention: `{base-attribute-name}-{media-query-name}=\"{value}\"`\n * (ie. `md-cols-lg=\"8\"`)\n *\n * @param {number} md-cols Number of columns in the grid.\n * @param {string} md-row-height One of\n * <ul>\n *   <li>CSS length - Fixed height rows (eg. `8px` or `1rem`)</li>\n *   <li>`{width}:{height}` - Ratio of width to height (eg.\n *   `md-row-height=\"16:9\"`)</li>\n *   <li>`\"fit\"` - Height will be determined by subdividing the available\n *   height by the number of rows</li>\n * </ul>\n * @param {string=} md-gutter The amount of space between tiles in CSS units\n *     (default 1px)\n * @param {expression=} md-on-layout Expression to evaluate after layout. Event\n *     object is available as `$event`, and contains performance information.\n *\n * @usage\n * Basic:\n * <hljs lang=\"html\">\n * <md-grid-list md-cols=\"5\" md-gutter=\"1em\" md-row-height=\"4:3\">\n *   <md-grid-tile></md-grid-tile>\n * </md-grid-list>\n * </hljs>\n *\n * Fixed-height rows:\n * <hljs lang=\"html\">\n * <md-grid-list md-cols=\"4\" md-row-height=\"200px\" ...>\n *   <md-grid-tile></md-grid-tile>\n * </md-grid-list>\n * </hljs>\n *\n * Fit rows:\n * <hljs lang=\"html\">\n * <md-grid-list md-cols=\"4\" md-row-height=\"fit\" style=\"height: 400px;\" ...>\n *   <md-grid-tile></md-grid-tile>\n * </md-grid-list>\n * </hljs>\n *\n * Using responsive attributes:\n * <hljs lang=\"html\">\n * <md-grid-list\n *     md-cols-sm=\"2\"\n *     md-cols-md=\"4\"\n *     md-cols-lg=\"8\"\n *     md-cols-gt-lg=\"12\"\n *     ...>\n *   <md-grid-tile></md-grid-tile>\n * </md-grid-list>\n * </hljs>\n */\nfunction GridListDirective($interpolate, $mdConstant, $mdGridLayout, $mdMedia, $mdUtil) {\n  return {\n    restrict: 'E',\n    controller: GridListController,\n    scope: {\n      mdOnLayout: '&'\n    },\n    link: postLink\n  };\n\n  function postLink(scope, element, attrs, ctrl) {\n    element.addClass('_md');     // private md component indicator for styling\n\n    // Apply semantics\n    element.attr('role', 'list');\n\n    // Provide the controller with a way to trigger layouts.\n    ctrl.layoutDelegate = layoutDelegate;\n\n    var invalidateLayout = angular.bind(ctrl, ctrl.invalidateLayout),\n        unwatchAttrs = watchMedia();\n      scope.$on('$destroy', unwatchMedia);\n\n    /**\n     * Watches for changes in media, invalidating layout as necessary.\n     */\n    function watchMedia() {\n      for (var mediaName in $mdConstant.MEDIA) {\n        $mdMedia(mediaName); // initialize\n        $mdMedia.getQuery($mdConstant.MEDIA[mediaName])\n            .addListener(invalidateLayout);\n      }\n      return $mdMedia.watchResponsiveAttributes(\n          ['md-cols', 'md-row-height', 'md-gutter'], attrs, layoutIfMediaMatch);\n    }\n\n    function unwatchMedia() {\n      ctrl.layoutDelegate = angular.noop;\n\n      unwatchAttrs();\n      for (var mediaName in $mdConstant.MEDIA) {\n        $mdMedia.getQuery($mdConstant.MEDIA[mediaName])\n            .removeListener(invalidateLayout);\n      }\n    }\n\n    /**\n     * Performs grid layout if the provided mediaName matches the currently\n     * active media type.\n     */\n    function layoutIfMediaMatch(mediaName) {\n      if (mediaName == null) {\n        // TODO(shyndman): It would be nice to only layout if we have\n        // instances of attributes using this media type\n        ctrl.invalidateLayout();\n      } else if ($mdMedia(mediaName)) {\n        ctrl.invalidateLayout();\n      }\n    }\n\n    var lastLayoutProps;\n\n    /**\n     * Invokes the layout engine, and uses its results to lay out our\n     * tile elements.\n     *\n     * @param {boolean} tilesInvalidated Whether tiles have been\n     *    added/removed/moved since the last layout. This is to avoid situations\n     *    where tiles are replaced with properties identical to their removed\n     *    counterparts.\n     */\n    function layoutDelegate(tilesInvalidated) {\n      var tiles = getTileElements();\n      var props = {\n        tileSpans: getTileSpans(tiles),\n        colCount: getColumnCount(),\n        rowMode: getRowMode(),\n        rowHeight: getRowHeight(),\n        gutter: getGutter()\n      };\n\n      if (!tilesInvalidated && angular.equals(props, lastLayoutProps)) {\n        return;\n      }\n\n      var performance =\n        $mdGridLayout(props.colCount, props.tileSpans, tiles)\n          .map(function(tilePositions, rowCount) {\n            return {\n              grid: {\n                element: element,\n                style: getGridStyle(props.colCount, rowCount,\n                    props.gutter, props.rowMode, props.rowHeight)\n              },\n              tiles: tilePositions.map(function(ps, i) {\n                return {\n                  element: angular.element(tiles[i]),\n                  style: getTileStyle(ps.position, ps.spans,\n                      props.colCount, rowCount,\n                      props.gutter, props.rowMode, props.rowHeight)\n                };\n              })\n            };\n          })\n          .reflow()\n          .performance();\n\n      // Report layout\n      scope.mdOnLayout({\n        $event: {\n          performance: performance\n        }\n      });\n\n      lastLayoutProps = props;\n    }\n\n    // Use $interpolate to do some simple string interpolation as a convenience.\n\n    var startSymbol = $interpolate.startSymbol();\n    var endSymbol = $interpolate.endSymbol();\n\n    // Returns an expression wrapped in the interpolator's start and end symbols.\n    function expr(exprStr) {\n      return startSymbol + exprStr + endSymbol;\n    }\n\n    // The amount of space a single 1x1 tile would take up (either width or height), used as\n    // a basis for other calculations. This consists of taking the base size percent (as would be\n    // if evenly dividing the size between cells), and then subtracting the size of one gutter.\n    // However, since there are no gutters on the edges, each tile only uses a fration\n    // (gutterShare = numGutters / numCells) of the gutter size. (Imagine having one gutter per\n    // tile, and then breaking up the extra gutter on the edge evenly among the cells).\n    var UNIT = $interpolate(expr('share') + '% - (' + expr('gutter') + ' * ' + expr('gutterShare') + ')');\n\n    // The horizontal or vertical position of a tile, e.g., the 'top' or 'left' property value.\n    // The position comes the size of a 1x1 tile plus gutter for each previous tile in the\n    // row/column (offset).\n    var POSITION  = $interpolate('calc((' + expr('unit') + ' + ' + expr('gutter') + ') * ' + expr('offset') + ')');\n\n    // The actual size of a tile, e.g., width or height, taking rowSpan or colSpan into account.\n    // This is computed by multiplying the base unit by the rowSpan/colSpan, and then adding back\n    // in the space that the gutter would normally have used (which was already accounted for in\n    // the base unit calculation).\n    var DIMENSION = $interpolate('calc((' + expr('unit') + ') * ' + expr('span') + ' + (' + expr('span') + ' - 1) * ' + expr('gutter') + ')');\n\n    /**\n     * Gets the styles applied to a tile element described by the given parameters.\n     * @param {{row: number, col: number}} position The row and column indices of the tile.\n     * @param {{row: number, col: number}} spans The rowSpan and colSpan of the tile.\n     * @param {number} colCount The number of columns.\n     * @param {number} rowCount The number of rows.\n     * @param {string} gutter The amount of space between tiles. This will be something like\n     *     '5px' or '2em'.\n     * @param {string} rowMode The row height mode. Can be one of:\n     *     'fixed': all rows have a fixed size, given by rowHeight,\n     *     'ratio': row height defined as a ratio to width, or\n     *     'fit': fit to the grid-list element height, divinding evenly among rows.\n     * @param {string|number} rowHeight The height of a row. This is only used for 'fixed' mode and\n     *     for 'ratio' mode. For 'ratio' mode, this is the *ratio* of width-to-height (e.g., 0.75).\n     * @returns {Object} Map of CSS properties to be applied to the style element. Will define\n     *     values for top, left, width, height, marginTop, and paddingTop.\n     */\n    function getTileStyle(position, spans, colCount, rowCount, gutter, rowMode, rowHeight) {\n      // TODO(shyndman): There are style caching opportunities here.\n\n      // Percent of the available horizontal space that one column takes up.\n      var hShare = (1 / colCount) * 100;\n\n      // Fraction of the gutter size that each column takes up.\n      var hGutterShare = (colCount - 1) / colCount;\n\n      // Base horizontal size of a column.\n      var hUnit = UNIT({share: hShare, gutterShare: hGutterShare, gutter: gutter});\n\n      // The width and horizontal position of each tile is always calculated the same way, but the\n      // height and vertical position depends on the rowMode.\n      var style = (!$mdUtil.isRtl(attrs)) ? {\n          left: POSITION({ unit: hUnit, offset: position.col, gutter: gutter }),\n          width: DIMENSION({ unit: hUnit, span: spans.col, gutter: gutter }),\n          // resets\n          paddingTop: '',\n          marginTop: '',\n          top: '',\n          height: ''\n        } : {\n        right: POSITION({ unit: hUnit, offset: position.col, gutter: gutter }),\n        width: DIMENSION({ unit: hUnit, span: spans.col, gutter: gutter }),\n        // resets\n        paddingTop: '',\n        marginTop: '',\n        top: '',\n        height: ''\n      };\n\n      switch (rowMode) {\n        case 'fixed':\n          // In fixed mode, simply use the given rowHeight.\n          style.top = POSITION({ unit: rowHeight, offset: position.row, gutter: gutter });\n          style.height = DIMENSION({ unit: rowHeight, span: spans.row, gutter: gutter });\n          break;\n\n        case 'ratio':\n          // Percent of the available vertical space that one row takes up. Here, rowHeight holds\n          // the ratio value. For example, if the width:height ratio is 4:3, rowHeight = 1.333.\n          var vShare = hShare / rowHeight;\n\n          // Base veritcal size of a row.\n          var vUnit = UNIT({ share: vShare, gutterShare: hGutterShare, gutter: gutter });\n\n          // padidngTop and marginTop are used to maintain the given aspect ratio, as\n          // a percentage-based value for these properties is applied to the *width* of the\n          // containing block. See http://www.w3.org/TR/CSS2/box.html#margin-properties\n          style.paddingTop = DIMENSION({ unit: vUnit, span: spans.row, gutter: gutter});\n          style.marginTop = POSITION({ unit: vUnit, offset: position.row, gutter: gutter });\n          break;\n\n        case 'fit':\n          // Fraction of the gutter size that each column takes up.\n          var vGutterShare = (rowCount - 1) / rowCount;\n\n          // Percent of the available vertical space that one row takes up.\n          vShare = (1 / rowCount) * 100;\n\n          // Base vertical size of a row.\n          vUnit = UNIT({share: vShare, gutterShare: vGutterShare, gutter: gutter});\n\n          style.top = POSITION({unit: vUnit, offset: position.row, gutter: gutter});\n          style.height = DIMENSION({unit: vUnit, span: spans.row, gutter: gutter});\n          break;\n      }\n\n      return style;\n    }\n\n    function getGridStyle(colCount, rowCount, gutter, rowMode, rowHeight) {\n      var style = {};\n\n      switch (rowMode) {\n        case 'fixed':\n          style.height = DIMENSION({ unit: rowHeight, span: rowCount, gutter: gutter });\n          style.paddingBottom = '';\n          break;\n\n        case 'ratio':\n          // rowHeight is width / height\n          var hGutterShare = colCount === 1 ? 0 : (colCount - 1) / colCount,\n              hShare = (1 / colCount) * 100,\n              vShare = hShare * (1 / rowHeight),\n              vUnit = UNIT({ share: vShare, gutterShare: hGutterShare, gutter: gutter });\n\n          style.height = '';\n          style.paddingBottom = DIMENSION({ unit: vUnit, span: rowCount, gutter: gutter});\n          break;\n\n        case 'fit':\n          // noop, as the height is user set\n          break;\n      }\n\n      return style;\n    }\n\n    function getTileElements() {\n      return [].filter.call(element.children(), function(ele) {\n        return ele.tagName == 'MD-GRID-TILE' && !ele.$$mdDestroyed;\n      });\n    }\n\n    /**\n     * Gets an array of objects containing the rowspan and colspan for each tile.\n     * @returns {Array<{row: number, col: number}>}\n     */\n    function getTileSpans(tileElements) {\n      return [].map.call(tileElements, function(ele) {\n        var ctrl = angular.element(ele).controller('mdGridTile');\n        return {\n          row: parseInt(\n              $mdMedia.getResponsiveAttribute(ctrl.$attrs, 'md-rowspan'), 10) || 1,\n          col: parseInt(\n              $mdMedia.getResponsiveAttribute(ctrl.$attrs, 'md-colspan'), 10) || 1\n        };\n      });\n    }\n\n    function getColumnCount() {\n      var colCount = parseInt($mdMedia.getResponsiveAttribute(attrs, 'md-cols'), 10);\n      if (isNaN(colCount)) {\n        throw 'md-grid-list: md-cols attribute was not found, or contained a non-numeric value';\n      }\n      return colCount;\n    }\n\n    function getGutter() {\n      return applyDefaultUnit($mdMedia.getResponsiveAttribute(attrs, 'md-gutter') || 1);\n    }\n\n    function getRowHeight() {\n      var rowHeight = $mdMedia.getResponsiveAttribute(attrs, 'md-row-height');\n      if (!rowHeight) {\n        throw 'md-grid-list: md-row-height attribute was not found';\n      }\n\n      switch (getRowMode()) {\n        case 'fixed':\n          return applyDefaultUnit(rowHeight);\n        case 'ratio':\n          var whRatio = rowHeight.split(':');\n          return parseFloat(whRatio[0]) / parseFloat(whRatio[1]);\n        case 'fit':\n          return 0; // N/A\n      }\n    }\n\n    function getRowMode() {\n      var rowHeight = $mdMedia.getResponsiveAttribute(attrs, 'md-row-height');\n      if (!rowHeight) {\n        throw 'md-grid-list: md-row-height attribute was not found';\n      }\n\n      if (rowHeight == 'fit') {\n        return 'fit';\n      } else if (rowHeight.indexOf(':') !== -1) {\n        return 'ratio';\n      } else {\n        return 'fixed';\n      }\n    }\n\n    function applyDefaultUnit(val) {\n      return /\\D$/.test(val) ? val : val + 'px';\n    }\n  }\n}\n\n/* @ngInject */\nfunction GridListController($mdUtil) {\n  this.layoutInvalidated = false;\n  this.tilesInvalidated = false;\n  this.$timeout_ = $mdUtil.nextTick;\n  this.layoutDelegate = angular.noop;\n}\n\nGridListController.prototype = {\n  invalidateTiles: function() {\n    this.tilesInvalidated = true;\n    this.invalidateLayout();\n  },\n\n  invalidateLayout: function() {\n    if (this.layoutInvalidated) {\n      return;\n    }\n    this.layoutInvalidated = true;\n    this.$timeout_(angular.bind(this, this.layout));\n  },\n\n  layout: function() {\n    try {\n      this.layoutDelegate(this.tilesInvalidated);\n    } finally {\n      this.layoutInvalidated = false;\n      this.tilesInvalidated = false;\n    }\n  }\n};\n\n\n/* @ngInject */\nfunction GridLayoutFactory($mdUtil) {\n  var defaultAnimator = GridTileAnimator;\n\n  /**\n   * Set the reflow animator callback\n   */\n  GridLayout.animateWith = function(customAnimator) {\n    defaultAnimator = !angular.isFunction(customAnimator) ? GridTileAnimator : customAnimator;\n  };\n\n  return GridLayout;\n\n  /**\n   * Publish layout function\n   */\n  function GridLayout(colCount, tileSpans) {\n      var self, layoutInfo, gridStyles, layoutTime, mapTime, reflowTime;\n\n      layoutTime = $mdUtil.time(function() {\n        layoutInfo = calculateGridFor(colCount, tileSpans);\n      });\n\n      return self = {\n\n        /**\n         * An array of objects describing each tile's position in the grid.\n         */\n        layoutInfo: function() {\n          return layoutInfo;\n        },\n\n        /**\n         * Maps grid positioning to an element and a set of styles using the\n         * provided updateFn.\n         */\n        map: function(updateFn) {\n          mapTime = $mdUtil.time(function() {\n            var info = self.layoutInfo();\n            gridStyles = updateFn(info.positioning, info.rowCount);\n          });\n          return self;\n        },\n\n        /**\n         * Default animator simply sets the element.css( <styles> ). An alternate\n         * animator can be provided as an argument. The function has the following\n         * signature:\n         *\n         *    function({grid: {element: JQLite, style: Object}, tiles: Array<{element: JQLite, style: Object}>)\n         */\n        reflow: function(animatorFn) {\n          reflowTime = $mdUtil.time(function() {\n            var animator = animatorFn || defaultAnimator;\n            animator(gridStyles.grid, gridStyles.tiles);\n          });\n          return self;\n        },\n\n        /**\n         * Timing for the most recent layout run.\n         */\n        performance: function() {\n          return {\n            tileCount: tileSpans.length,\n            layoutTime: layoutTime,\n            mapTime: mapTime,\n            reflowTime: reflowTime,\n            totalTime: layoutTime + mapTime + reflowTime\n          };\n        }\n      };\n    }\n\n  /**\n   * Default Gridlist animator simple sets the css for each element;\n   * NOTE: any transitions effects must be manually set in the CSS.\n   * e.g.\n   *\n   *  md-grid-tile {\n   *    transition: all 700ms ease-out 50ms;\n   *  }\n   *\n   */\n  function GridTileAnimator(grid, tiles) {\n    grid.element.css(grid.style);\n    tiles.forEach(function(t) {\n      t.element.css(t.style);\n    });\n  }\n\n  /**\n   * Calculates the positions of tiles.\n   *\n   * The algorithm works as follows:\n   *    An Array<Number> with length colCount (spaceTracker) keeps track of\n   *    available tiling positions, where elements of value 0 represents an\n   *    empty position. Space for a tile is reserved by finding a sequence of\n   *    0s with length <= than the tile's colspan. When such a space has been\n   *    found, the occupied tile positions are incremented by the tile's\n   *    rowspan value, as these positions have become unavailable for that\n   *    many rows.\n   *\n   *    If the end of a row has been reached without finding space for the\n   *    tile, spaceTracker's elements are each decremented by 1 to a minimum\n   *    of 0. Rows are searched in this fashion until space is found.\n   */\n  function calculateGridFor(colCount, tileSpans) {\n    var curCol = 0,\n        curRow = 0,\n        spaceTracker = newSpaceTracker();\n\n    return {\n      positioning: tileSpans.map(function(spans, i) {\n        return {\n          spans: spans,\n          position: reserveSpace(spans, i)\n        };\n      }),\n      rowCount: curRow + Math.max.apply(Math, spaceTracker)\n    };\n\n    function reserveSpace(spans, i) {\n      if (spans.col > colCount) {\n        throw 'md-grid-list: Tile at position ' + i + ' has a colspan ' +\n            '(' + spans.col + ') that exceeds the column count ' +\n            '(' + colCount + ')';\n      }\n\n      var start = 0,\n          end = 0;\n\n      // TODO(shyndman): This loop isn't strictly necessary if you can\n      // determine the minimum number of rows before a space opens up. To do\n      // this, recognize that you've iterated across an entire row looking for\n      // space, and if so fast-forward by the minimum rowSpan count. Repeat\n      // until the required space opens up.\n      while (end - start < spans.col) {\n        if (curCol >= colCount) {\n          nextRow();\n          continue;\n        }\n\n        start = spaceTracker.indexOf(0, curCol);\n        if (start === -1 || (end = findEnd(start + 1)) === -1) {\n          start = end = 0;\n          nextRow();\n          continue;\n        }\n\n        curCol = end + 1;\n      }\n\n      adjustRow(start, spans.col, spans.row);\n      curCol = start + spans.col;\n\n      return {\n        col: start,\n        row: curRow\n      };\n    }\n\n    function nextRow() {\n      curCol = 0;\n      curRow++;\n      adjustRow(0, colCount, -1); // Decrement row spans by one\n    }\n\n    function adjustRow(from, cols, by) {\n      for (var i = from; i < from + cols; i++) {\n        spaceTracker[i] = Math.max(spaceTracker[i] + by, 0);\n      }\n    }\n\n    function findEnd(start) {\n      var i;\n      for (i = start; i < spaceTracker.length; i++) {\n        if (spaceTracker[i] !== 0) {\n          return i;\n        }\n      }\n\n      if (i === spaceTracker.length) {\n        return i;\n      }\n    }\n\n    function newSpaceTracker() {\n      var tracker = [];\n      for (var i = 0; i < colCount; i++) {\n        tracker.push(0);\n      }\n      return tracker;\n    }\n  }\n}\n\n/**\n * @ngdoc directive\n * @name mdGridTile\n * @module material.components.gridList\n * @restrict E\n * @description\n * Tiles contain the content of an `md-grid-list`. They span one or more grid\n * cells vertically or horizontally, and use `md-grid-tile-{footer,header}` to\n * display secondary content.\n *\n * ### Responsive Attributes\n *\n * The `md-grid-tile` directive supports \"responsive\" attributes, which allow\n * different `md-rowspan` and `md-colspan` values depending on the currently\n * matching media query.\n *\n * In order to set a responsive attribute, first define the fallback value with\n * the standard attribute name, then add additional attributes with the\n * following convention: `{base-attribute-name}-{media-query-name}=\"{value}\"`\n * (ie. `md-colspan-sm=\"4\"`)\n *\n * @param {number=} md-colspan The number of columns to span (default 1). Cannot\n *    exceed the number of columns in the grid. Supports interpolation.\n * @param {number=} md-rowspan The number of rows to span (default 1). Supports\n *     interpolation.\n *\n * @usage\n * With header:\n * <hljs lang=\"html\">\n * <md-grid-tile>\n *   <md-grid-tile-header>\n *     <h3>This is a header</h3>\n *   </md-grid-tile-header>\n * </md-grid-tile>\n * </hljs>\n *\n * With footer:\n * <hljs lang=\"html\">\n * <md-grid-tile>\n *   <md-grid-tile-footer>\n *     <h3>This is a footer</h3>\n *   </md-grid-tile-footer>\n * </md-grid-tile>\n * </hljs>\n *\n * Spanning multiple rows/columns:\n * <hljs lang=\"html\">\n * <md-grid-tile md-colspan=\"2\" md-rowspan=\"3\">\n * </md-grid-tile>\n * </hljs>\n *\n * Responsive attributes:\n * <hljs lang=\"html\">\n * <md-grid-tile md-colspan=\"1\" md-colspan-sm=\"3\" md-colspan-md=\"5\">\n * </md-grid-tile>\n * </hljs>\n */\nfunction GridTileDirective($mdMedia) {\n  return {\n    restrict: 'E',\n    require: '^mdGridList',\n    template: '<figure ng-transclude></figure>',\n    transclude: true,\n    scope: {},\n    // Simple controller that exposes attributes to the grid directive\n    controller: [\"$attrs\", function($attrs) {\n      this.$attrs = $attrs;\n    }],\n    link: postLink\n  };\n\n  function postLink(scope, element, attrs, gridCtrl) {\n    // Apply semantics\n    element.attr('role', 'listitem');\n\n    // If our colspan or rowspan changes, trigger a layout\n    var unwatchAttrs = $mdMedia.watchResponsiveAttributes(['md-colspan', 'md-rowspan'],\n        attrs, angular.bind(gridCtrl, gridCtrl.invalidateLayout));\n\n    // Tile registration/deregistration\n    gridCtrl.invalidateTiles();\n    scope.$on('$destroy', function() {\n      // Mark the tile as destroyed so it is no longer considered in layout,\n      // even if the DOM element sticks around (like during a leave animation)\n      element[0].$$mdDestroyed = true;\n      unwatchAttrs();\n      gridCtrl.invalidateLayout();\n    });\n\n    if (angular.isDefined(scope.$parent.$index)) {\n      scope.$watch(function() { return scope.$parent.$index; },\n        function indexChanged(newIdx, oldIdx) {\n          if (newIdx === oldIdx) {\n            return;\n          }\n          gridCtrl.invalidateTiles();\n        });\n    }\n  }\n}\n\n\nfunction GridTileCaptionDirective() {\n  return {\n    template: '<figcaption ng-transclude></figcaption>',\n    transclude: true\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.icon\n * @description\n * Icon\n */\nangular.module('material.components.icon', ['material.core']);\n\n})();\n(function(){\n\"use strict\";\n\nangular\n  .module('material.components.icon')\n  .directive('mdIcon', ['$mdIcon', '$mdTheming', '$mdAria', '$sce', mdIconDirective]);\n\n/**\n * @ngdoc directive\n * @name mdIcon\n * @module material.components.icon\n *\n * @restrict E\n *\n * @description\n * The `md-icon` directive makes it easier to use vector-based icons in your app (as opposed to\n * raster-based icons types like PNG). The directive supports both icon fonts and SVG icons.\n *\n * Icons should be considered view-only elements that should not be used directly as buttons; instead nest a `<md-icon>`\n * inside a `md-button` to add hover and click features.\n *\n * ### Icon fonts\n * Icon fonts are a technique in which you use a font where the glyphs in the font are\n * your icons instead of text. Benefits include a straightforward way to bundle everything into a\n * single HTTP request, simple scaling, easy color changing, and more.\n *\n * `md-icon` lets you consume an icon font by letting you reference specific icons in that font\n * by name rather than character code.\n *\n * When using font-icons, developers must follow three (3) simple steps:\n *\n * <ol>\n * <li>Load the font library. e.g.<br/>\n *    `<link href=\"https://fonts.googleapis.com/icon?family=Material+Icons\" rel=\"stylesheet\">`\n * </li>\n * <li>\n *   Use either (a) font-icon class names or (b) a fontset and a font ligature to render the font glyph by\n *   using its textual name _or_ numerical character reference. Note that `material-icons` is the default fontset when\n *   none is specified.\n * </li>\n * <li> Use any of the following templates: <br/>\n *   <ul>\n *     <li>`<md-icon md-font-icon=\"classname\"></md-icon>`</li>\n *     <li>`<md-icon md-font-set=\"font library classname or alias\">textual_name</md-icon>`</li>\n *     <li>`<md-icon> numerical_character_reference </md-icon>`</li>\n *     <li>`<md-icon ng_bind=\"'textual_name'\"></md-icon>`</li>\n *     <li>`<md-icon ng-bind=\"scopeVariable\"></md-icon>`</li>\n *   </ul>\n * </li>\n * </ol>\n *\n * Full details for these steps can be found in the\n * <a href=\"http://google.github.io/material-design-icons/#icon-font-for-the-web\" target=\"_blank\">\n * Material Design Icon font for the web docs</a>.\n *\n * You can browse and search the Material Design icon style <code>.material-icons</code>\n * in the <a href=\"https://material.io/tools/icons/\" target=\"_blank\">Material Design Icons tool</a>.\n *\n * ### SVG\n * For SVGs, the problem with using `<img>` or a CSS `background-image` is that you can't take\n * advantage of some SVG features, such as styling specific parts of the icon with CSS or SVG\n * animation.\n *\n * `md-icon` makes it easier to use SVG icons by *inlining* the SVG into an `<svg>` element in the\n * document. The most straightforward way of referencing an SVG icon is via URL, just like a\n * traditional `<img>`. `$mdIconProvider`, as a convenience, lets you _name_ an icon so you can\n * reference it by name instead of URL throughout your templates.\n *\n * Additionally, you may not want to make separate HTTP requests for every icon, so you can bundle\n * your SVG icons together and pre-load them with `$mdIconProvider` as an icon set. An icon set can\n * also be given a name, which acts as a namespace for individual icons, so you can reference them\n * like `\"social:cake\"`.\n *\n * When using SVGs, both external SVGs (via URLs) or sets of SVGs (from icon sets) can be\n * easily loaded and used.\n *\n * ### Localization\n *\n * Because an `md-icon` element's text content is not intended to be translated, it is recommended\n * to declare the text content for an `md-icon` element in its start tag. Instead of using the HTML\n * text content, consider using `ng-bind` with a scope variable or literal string.\n *\n * Examples:\n *\n * <ul>\n *   <li>`<md-icon ng-bind=\"myIconVariable\"></md-icon>`</li>\n *   <li>`<md-icon ng-bind=\"'menu'\"></md-icon>`\n * </ul>\n *\n * <h2 id=\"material_design_icons\">Material Design Icons tool</h2>\n * Using the Material Design Icons tool, developers can easily and quickly search for a specific\n * open source Material Design icon. The search is in the top left. Below search, you can select\n * from the new icon themes or filter by icon category.\n *\n * <a href=\"https://material.io/tools/icons/\" target=\"_blank\" style=\"border-bottom:none;\">\n * <img src=\"https://user-images.githubusercontent.com/3506071/41942584-ef0695d0-796d-11e8-9436-44f25023a111.png\"\n *      aria-label=\"Material Design Icons tool\" style=\"max-width:95%\">\n * </a>\n *\n * <div class=\"md-caption\" style=\"text-align: center; margin-bottom: 24px\">\n *  Click on the image above to open the\n *  <a href=\"https://material.io/tools/icons/\" target=\"_blank\">Material Design Icons tool</a>.\n * </div>\n *\n * Click on any icon, then click on the \"Selected Icon\" chevron to see the slide-up\n * information panel with details regarding a SVG download and information on the font-icon's\n * textual name. This panel also allows you to select a black on transparent or white on transparent\n * icon and to change the icon size. These settings only affect the downloaded icons.\n *\n * @param {string} md-font-icon String name of CSS icon associated with the font-face will be used\n *  to render the icon. Requires the fonts and the named CSS styles to be preloaded.\n * @param {string} md-font-set CSS style name associated with the font library; which will be assigned as\n *  the class for the font-icon ligature. This value may also be an alias that is used to lookup the classname;\n *  internally use `$mdIconProvider.fontSet(<alias>)` to determine the style name.\n * @param {string} md-svg-src String URL (or expression) used to load, cache, and display an\n *  external SVG.\n * @param {string} md-svg-icon md-svg-icon String name used for lookup of the icon from the internal cache;\n *  interpolated strings or expressions may also be used. Specific set names can be used with\n *  the syntax `<set name>:<icon name>`.<br/><br/>\n *  To use icon sets, developers are required to pre-register the sets using the `$mdIconProvider` service.\n * @param {string=} aria-label Labels the icon for accessibility. If an empty string is provided,\n *  the icon will be hidden from the accessibility layer with `aria-hidden=\"true\"`. If there is no\n *  `aria-label` attribute on the icon, we check the following, in order: the `alt` attribute, the\n *  `aria-label` from the parent element, the icon's `md-font-icon` or `md-svg-icon` string, and the\n *  text content inside `<md-icon></md-icon>`. If none of these have any text, the icon is hidden\n *  from the accessibility layer with `aria-hidden=\"true\"`.\n * @param {string=} alt Labels the icon for accessibility. If an empty string is provided and the\n *  icon has no `aria-label`, then the icon will be hidden from accessibility layer with\n *  `aria-hidden=\"true\"`.\n *\n * @usage\n * When using SVGs:\n * <hljs lang=\"html\">\n *\n *<!-- Icon ID; may contain optional icon set prefix.\n *     Icons must be registered using $mdIconProvider. -->\n *<md-icon md-svg-icon=\"social:android\"    aria-label=\"android \" ></md-icon>\n *\n *<!-- Icon urls; may be preloaded in templateCache -->\n *<md-icon md-svg-src=\"/android.svg\"       aria-label=\"android \" ></md-icon>\n *<md-icon md-svg-src=\"{{ getAndroid() }}\" aria-label=\"android \" ></md-icon>\n *\n * </hljs>\n *\n * Use the <code>$mdIconProvider</code> to configure your application with\n * SVG icon sets.\n *\n * <hljs lang=\"js\">\n * angular.module('appSvgIconSets', ['ngMaterial'])\n *   .controller('DemoCtrl', function($scope) {})\n *   .config(function($mdIconProvider) {\n *     $mdIconProvider\n *       .iconSet('social', 'img/icons/sets/social-icons.svg', 24)\n *       .defaultIconSet('img/icons/sets/core-icons.svg', 24);\n *    });\n * </hljs>\n *\n *\n * When using Font Icons with classnames:\n * <hljs lang=\"html\">\n *\n * <md-icon md-font-icon=\"android\" aria-label=\"android\" ></md-icon>\n * <md-icon class=\"icon_home\" aria-label=\"Home\"></md-icon>\n *\n * </hljs>\n *\n * When using Material Font Icons with ligatures:\n * <hljs lang=\"html\">\n *  <!--\n *  For Material Design Icons\n *  The class '.material-icons' is auto-added if a style has NOT been specified\n *  since `material-icons` is the default fontset. So your markup:\n *  -->\n *  <md-icon> face </md-icon>\n *  <!-- becomes this at runtime: -->\n *  <md-icon md-font-set=\"material-icons\"> face </md-icon>\n *  <!-- If the fontset does not support ligature names, then we need to use the ligature unicode.-->\n *  <md-icon> &#xE87C; </md-icon>\n *  <!-- The class '.material-icons' must be manually added if other styles are also specified-->\n *  <md-icon class=\"material-icons md-light md-48\"> face </md-icon>\n * </hljs>\n *\n * When using other Font-Icon libraries:\n *\n * <hljs lang=\"js\">\n *  // Specify a font-icon style alias\n *  angular.config(function($mdIconProvider) {\n *    $mdIconProvider.fontSet('md', 'material-icons');\n *  });\n * </hljs>\n *\n * <hljs lang=\"html\">\n *  <md-icon md-font-set=\"md\">favorite</md-icon>\n * </hljs>\n *\n */\nfunction mdIconDirective($mdIcon, $mdTheming, $mdAria, $sce) {\n\n  return {\n    restrict: 'E',\n    link : postLink\n  };\n\n\n  /**\n   * Directive postLink\n   * Supports embedded SVGs, font-icons, & external SVGs.\n   * @param {IScope} scope\n   * @param {JQLite} element\n   * @param {IAttributes} attr\n   */\n  function postLink(scope, element, attr) {\n    $mdTheming(element);\n    var lastFontIcon = attr.mdFontIcon;\n    var lastFontSet = $mdIcon.fontSet(attr.mdFontSet);\n\n    prepareForFontIcon();\n\n    attr.$observe('mdFontIcon', fontIconChanged);\n    attr.$observe('mdFontSet', fontIconChanged);\n\n    /* Provide a default accessibility role of img */\n    if (!attr.role) {\n      $mdAria.expect(element, 'role', 'img');\n      /* manually update attr variable */\n      attr.role = 'img';\n    }\n\n    // If the aria-label is explicitly set to the empty string, then hide this element from the\n    // accessibility layer.\n    if (element[0].hasAttribute('aria-label') && attr.ariaLabel === '') {\n      element.attr('aria-hidden', true);\n    }\n\n    /* Don't process ARIA if already valid */\n    if (attr.role === \"img\" && !attr.ariaHidden && !$mdAria.hasAriaLabel(element)) {\n      // If the developer signals to hide this icon from the accessibility layer, do so.\n      if (element[0].hasAttribute('alt') && attr.alt === '') {\n        element.attr('aria-hidden', true);\n      } else if (attr.alt) {\n        /* Use the alt text for the aria-label by default, if available. */\n        $mdAria.expect(element, 'aria-label', attr.alt);\n      } else if ($mdAria.parentHasAriaLabel(element, 2)) {\n        /* Parent has ARIA so we will assume it will describe the icon. */\n        $mdAria.expect(element, 'aria-hidden', 'true');\n      } else if (attr.mdFontIcon || attr.mdSvgIcon || element.text()) {\n        /* Use icon name or node's text content as the aria-label */\n        $mdAria.expect(element, 'aria-label', attr.mdFontIcon || attr.mdSvgIcon || element.text());\n      } else {\n        /* No label found, hide this icon from the accessibility layer */\n        $mdAria.expect(element, 'aria-hidden', 'true');\n      }\n    }\n\n    var attrName = attr.$normalize(attr.$attr.mdSvgIcon || attr.$attr.mdSvgSrc || '');\n    if (attrName) {\n      // Use either pre-configured SVG or URL source, respectively.\n      attr.$observe(attrName, function(attrVal) {\n        element.empty();\n        if (attrVal) {\n          $mdIcon(attrVal)\n            .then(function(svg) {\n            element.empty();\n            element.append(svg);\n          });\n        }\n      });\n    }\n\n    function prepareForFontIcon() {\n      if (!attr.mdSvgIcon && !attr.mdSvgSrc) {\n        if (attr.mdFontIcon) {\n          element.addClass('md-font ' + attr.mdFontIcon);\n        }\n\n        element.addClass(lastFontSet);\n      }\n    }\n\n    function fontIconChanged() {\n      if (!attr.mdSvgIcon && !attr.mdSvgSrc) {\n        if (attr.mdFontIcon) {\n          element.removeClass(lastFontIcon);\n          element.addClass(attr.mdFontIcon);\n\n          lastFontIcon = attr.mdFontIcon;\n        }\n\n        var fontSet = $mdIcon.fontSet(attr.mdFontSet);\n\n        if (lastFontSet !== fontSet) {\n          element.removeClass(lastFontSet);\n          element.addClass(fontSet);\n\n          lastFontSet = fontSet;\n        }\n      }\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n  \nMdIconService.$inject = [\"config\", \"$templateRequest\", \"$q\", \"$log\", \"$mdUtil\", \"$sce\"];angular\n    .module('material.components.icon')\n    .constant('$$mdSvgRegistry', {\n        'mdTabsArrow':   'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnPjxwb2x5Z29uIHBvaW50cz0iMTUuNCw3LjQgMTQsNiA4LDEyIDE0LDE4IDE1LjQsMTYuNiAxMC44LDEyICIvPjwvZz48L3N2Zz4=',\n        'mdClose':       'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnPjxwYXRoIGQ9Ik0xOSA2LjQxbC0xLjQxLTEuNDEtNS41OSA1LjU5LTUuNTktNS41OS0xLjQxIDEuNDEgNS41OSA1LjU5LTUuNTkgNS41OSAxLjQxIDEuNDEgNS41OS01LjU5IDUuNTkgNS41OSAxLjQxLTEuNDEtNS41OS01LjU5eiIvPjwvZz48L3N2Zz4=',\n        'mdCancel':      'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnPjxwYXRoIGQ9Ik0xMiAyYy01LjUzIDAtMTAgNC40Ny0xMCAxMHM0LjQ3IDEwIDEwIDEwIDEwLTQuNDcgMTAtMTAtNC40Ny0xMC0xMC0xMHptNSAxMy41OWwtMS40MSAxLjQxLTMuNTktMy41OS0zLjU5IDMuNTktMS40MS0xLjQxIDMuNTktMy41OS0zLjU5LTMuNTkgMS40MS0xLjQxIDMuNTkgMy41OSAzLjU5LTMuNTkgMS40MSAxLjQxLTMuNTkgMy41OSAzLjU5IDMuNTl6Ii8+PC9nPjwvc3ZnPg==',\n        'mdMenu':        'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zLDZIMjFWOEgzVjZNMywxMUgyMVYxM0gzVjExTTMsMTZIMjFWMThIM1YxNloiIC8+PC9zdmc+',\n        'mdToggleArrow': 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNDggNDgiPjxwYXRoIGQ9Ik0yNCAxNmwtMTIgMTIgMi44MyAyLjgzIDkuMTctOS4xNyA5LjE3IDkuMTcgMi44My0yLjgzeiIvPjxwYXRoIGQ9Ik0wIDBoNDh2NDhoLTQ4eiIgZmlsbD0ibm9uZSIvPjwvc3ZnPg==',\n        'mdCalendar':    'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTkgM2gtMVYxaC0ydjJIOFYxSDZ2Mkg1Yy0xLjExIDAtMS45OS45LTEuOTkgMkwzIDE5YzAgMS4xLjg5IDIgMiAyaDE0YzEuMSAwIDItLjkgMi0yVjVjMC0xLjEtLjktMi0yLTJ6bTAgMTZINVY4aDE0djExek03IDEwaDV2NUg3eiIvPjwvc3ZnPg==',\n        'mdChecked':     'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnPjxwYXRoIGQ9Ik05IDE2LjE3TDQuODMgMTJsLTEuNDIgMS40MUw5IDE5IDIxIDdsLTEuNDEtMS40MXoiLz48L2c+PC9zdmc+'\n    })\n    .provider('$mdIcon', MdIconProvider);\n\n/**\n * @ngdoc service\n * @name $mdIconProvider\n * @module material.components.icon\n *\n * @description\n * `$mdIconProvider` is used only to register icon IDs with URLs. These configuration features allow\n * icons and icon sets to be pre-registered and associated with source URLs **before** the\n * `<md-icon />` directives are compiled.\n *\n * If using font-icons, the developer is responsible for loading the fonts.\n *\n * If using SVGs, loading of the actual svg files are deferred to on-demand requests and are loaded\n * internally by the `$mdIcon` service using the `$templateRequest` service. When an SVG is\n * requested by name/ID, the `$mdIcon` service searches its registry for the associated source URL;\n * that URL is used to on-demand load and parse the SVG dynamically.\n *\n * The `$templateRequest` service expects the icons source to be loaded over trusted URLs.<br/>\n * This means, when loading icons from an external URL, you have to trust the URL in the\n * `$sceDelegateProvider`.\n *\n * <hljs lang=\"js\">\n *   app.config(function($sceDelegateProvider) {\n *     $sceDelegateProvider.trustedResourceUrlList([\n *       // Adding 'self' to the allow-list, will allow requests from the current origin.\n *       'self',\n *       // Using double asterisks here, will allow all URLs to load.\n *       // However, we recommend only specifying the given domain you want to allow.\n *       '**'\n *     ]);\n *   });\n * </hljs>\n *\n * Read more about the [$sceDelegateProvider](https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider).\n *\n * **Notice:** Most font-icon libraries do not support ligatures (for example `fontawesome`).<br/>\n *  In such cases you are not able to use the icon's ligature name - Like so:\n *\n *  <hljs lang=\"html\">\n *    <md-icon md-font-set=\"fa\">fa-bell</md-icon>\n *  </hljs>\n *\n * You should instead use the given unicode, instead of the ligature name.\n *\n * <p ng-hide=\"true\"> ##// Notice we can't use a hljs element here, because the characters will be escaped.</p>\n *  ```html\n *    <md-icon md-font-set=\"fa\">&#xf0f3</md-icon>\n *  ```\n *\n * All unicode ligatures are prefixed with the `&#x` string.\n *\n * @usage\n * <hljs lang=\"js\">\n *   app.config(function($mdIconProvider) {\n *\n *     // Configure URLs for icons specified by [set:]id.\n *     $mdIconProvider\n *       .defaultFontSet( 'fa' )                   // This sets our default fontset className.\n *       .defaultIconSet('my/app/icons.svg')       // Register a default set of SVG icons\n *       .iconSet('social', 'my/app/social.svg')   // Register a named icon set of SVGs\n *       .icon('android', 'my/app/android.svg')    // Register a specific icon (by name)\n *       .icon('work:chair', 'my/app/chair.svg');  // Register icon in a specific set\n *   });\n * </hljs>\n *\n * SVG icons and icon sets can be easily pre-loaded and cached using either (a) a build process or\n * (b) a runtime **startup** process (shown below):\n *\n * <hljs lang=\"js\">\n *   app.config(function($mdIconProvider) {\n *\n *     // Register a default set of SVG icon definitions\n *     $mdIconProvider.defaultIconSet('my/app/icons.svg')\n *   })\n *   .run(function($templateRequest) {\n *\n *     // Pre-fetch icons sources by URL and cache in the $templateCache...\n *     // subsequent $templateRequest calls will look there first.\n *     var urls = [ 'imy/app/icons.svg', 'img/icons/android.svg'];\n *\n *     angular.forEach(urls, function(url) {\n *       $templateRequest(url);\n *     });\n *   });\n *\n * </hljs>\n *\n * > <b>Note:</b> The loaded SVG data is subsequently cached internally for future requests.\n */\n\n/**\n * @ngdoc method\n * @name $mdIconProvider#icon\n *\n * @description\n * Register a source URL for a specific icon name; the name may include optional 'icon set' name\n * prefix. These icons will later be retrieved from the cache using `$mdIcon(<icon name>)`.\n *\n * @param {string} id Icon name/id used to register the icon\n * @param {string} url specifies the external location for the data file. Used internally by\n *  `$templateRequest` to load the data or as part of the lookup in `$templateCache` if pre-loading\n *  was configured.\n * @param {number=} viewBoxSize Sets the width and height the icon's viewBox.\n *  It is ignored for icons with an existing viewBox. Default size is 24.\n *\n * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API\n *\n * @usage\n * <hljs lang=\"js\">\n *   app.config(function($mdIconProvider) {\n *\n *     // Configure URLs for icons specified by [set:]id.\n *     $mdIconProvider\n *       .icon('android', 'my/app/android.svg')    // Register a specific icon (by name)\n *       .icon('work:chair', 'my/app/chair.svg');  // Register icon in a specific set\n *   });\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdIconProvider#iconSet\n *\n * @description\n * Register a source URL for a 'named' set of icons; group of SVG definitions where each definition\n * has an icon id. Individual icons can be subsequently retrieved from this cached set using\n * `$mdIcon(<icon set name>:<icon name>)`\n *\n * @param {string} id Icon name/id used to register the iconset\n * @param {string} url specifies the external location for the data file. Used internally by\n * `$templateRequest` to load the data or as part of the lookup in `$templateCache` if pre-loading\n * was configured.\n * @param {number=} viewBoxSize Sets the width and height of the viewBox of all icons in the set.\n * It is ignored for icons with an existing viewBox. All icons in the icon set should be the same size.\n * Default value is 24.\n *\n * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API\n *\n * @usage\n * <hljs lang=\"js\">\n *   app.config(function($mdIconProvider) {\n *\n *     // Configure URLs for icons specified by [set:]id.\n *     $mdIconProvider\n *       .iconSet('social', 'my/app/social.svg');   // Register a named icon set\n *   });\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdIconProvider#defaultIconSet\n *\n * @description\n * Register a source URL for the default 'named' set of icons. Unless explicitly registered,\n * subsequent lookups of icons will fail over to search this 'default' icon set.\n * Icon can be retrieved from this cached, default set using `$mdIcon(<name>)`\n *\n * @param {string} url specifies the external location for the data file. Used internally by\n * `$templateRequest` to load the data or as part of the lookup in `$templateCache` if pre-loading\n * was configured.\n * @param {number=} viewBoxSize Sets the width and height of the viewBox of all icons in the set.\n * It is ignored for icons with an existing viewBox. All icons in the icon set should be the same\n * size. Default value is 24.\n *\n * @returns {Object} an `$mdIconProvider` reference; used to support method call chains for the API\n *\n * @usage\n * <hljs lang=\"js\">\n *   app.config(function($mdIconProvider) {\n *\n *     // Configure URLs for icons specified by [set:]id.\n *     $mdIconProvider\n *       .defaultIconSet('my/app/social.svg');   // Register a default icon set\n *   });\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdIconProvider#defaultFontSet\n *\n * @description\n * When using Font-Icons, AngularJS Material assumes the the Material Design icons will be used and\n * automatically configures the default `font-set == 'material-icons'`. Note that the font-set\n * references the font-icon library class style that should be applied to the `<md-icon>`.\n *\n * Configuring the default means that the attributes\n * `md-font-set=\"material-icons\"` or `class=\"material-icons\"` do not need to be explicitly declared\n * on the `<md-icon>` markup.\n *\n * For example:<br/>\n * `<md-icon>face</md-icon>` will render as `<span class=\"material-icons\">face</span>`,<br/>\n * and<br/>\n * `<md-icon md-font-set=\"fa\">face</md-icon>` will render as `<span class=\"fa\">face</span>`\n *\n * @param {string} name Name of the font-library style that should be applied to the md-icon DOM\n *  element.\n *\n * @usage\n * <hljs lang=\"js\">\n *   app.config(function($mdIconProvider) {\n *     $mdIconProvider.defaultFontSet('fa');\n *   });\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdIconProvider#fontSet\n *\n * @description\n * When using a font-set for `<md-icon>` you must specify the correct font classname in the\n * `md-font-set` attribute. If the font-set className is really long, your markup may become\n * cluttered... an easy solution is to define an `alias` for your font-set:\n *\n * @param {string} alias Alias name of the specified font-set.\n * @param {string} className Name of the class for the font-set.\n *\n * @usage\n * <hljs lang=\"js\">\n *   app.config(function($mdIconProvider) {\n *     // In this case, we set an alias for the `material-icons` font-set.\n *     $mdIconProvider.fontSet('md', 'material-icons');\n *   });\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdIconProvider#defaultViewBoxSize\n *\n * @description\n * While `<md-icon>` markup can also be styled with sizing CSS, this method configures\n * the default width **and** height used for all icons; unless overridden by specific CSS.\n * The default sizing is (`24px`, `24px`).\n * @param {number=} viewBoxSize Sets the width and height of the viewBox for an icon or an icon set.\n * All icons in a set should be the same size. The default value is 24.\n *\n * @returns {Object} an `$mdIconProvider` reference; used to support method call chains for the API\n *\n * @usage\n * <hljs lang=\"js\">\n *   app.config(function($mdIconProvider) {\n *\n *     // Configure URLs for icons specified by [set:]id.\n *     $mdIconProvider\n *       .defaultViewBoxSize(36);   // Register a default icon size (width == height)\n *   });\n * </hljs>\n */\n\nvar config = {\n  defaultViewBoxSize: 24,\n  defaultFontSet: 'material-icons',\n  fontSets: []\n};\n\nfunction MdIconProvider() {\n}\n\nMdIconProvider.prototype = {\n  icon: function(id, url, viewBoxSize) {\n    if (id.indexOf(':') == -1) id = '$default:' + id;\n\n    config[id] = new ConfigurationItem(url, viewBoxSize);\n    return this;\n  },\n\n  iconSet: function(id, url, viewBoxSize) {\n    config[id] = new ConfigurationItem(url, viewBoxSize);\n    return this;\n  },\n\n  defaultIconSet: function(url, viewBoxSize) {\n    var setName = '$default';\n\n    if (!config[setName]) {\n      config[setName] = new ConfigurationItem(url, viewBoxSize);\n    }\n\n    config[setName].viewBoxSize = viewBoxSize || config.defaultViewBoxSize;\n\n    return this;\n  },\n\n  defaultViewBoxSize: function(viewBoxSize) {\n    config.defaultViewBoxSize = viewBoxSize;\n    return this;\n  },\n\n  /**\n   * Register an alias name associated with a font-icon library style ;\n   */\n  fontSet: function fontSet(alias, className) {\n    config.fontSets.push({\n      alias: alias,\n      fontSet: className || alias\n    });\n    return this;\n  },\n\n  /**\n   * Specify a default style name associated with a font-icon library\n   * fallback to Material Icons.\n   *\n   */\n  defaultFontSet: function defaultFontSet(className) {\n    config.defaultFontSet = !className ? '' : className;\n    return this;\n  },\n\n  defaultIconSize: function defaultIconSize(iconSize) {\n    config.defaultIconSize = iconSize;\n    return this;\n  },\n\n  $get: ['$templateRequest', '$q', '$log', '$mdUtil', '$sce', function($templateRequest, $q, $log, $mdUtil, $sce) {\n    return MdIconService(config, $templateRequest, $q, $log, $mdUtil, $sce);\n  }]\n};\n\n  /**\n   * Configuration item stored in the Icon registry; used for lookups\n   * to load if not already cached in the `loaded` cache\n   * @param {string} url\n   * @param {=number} viewBoxSize\n   * @constructor\n   */\n  function ConfigurationItem(url, viewBoxSize) {\n    this.url = url;\n    this.viewBoxSize = viewBoxSize || config.defaultViewBoxSize;\n  }\n\n/**\n * @ngdoc service\n * @name $mdIcon\n * @module material.components.icon\n *\n * @description\n * The `$mdIcon` service is a function used to lookup SVG icons.\n *\n * @param {string} id Query value for a unique Id or URL. If the argument is a URL, then the service will retrieve the icon element\n * from its internal cache or load the icon and cache it first. If the value is not a URL-type string, then an ID lookup is\n * performed. The Id may be a unique icon ID or may include an iconSet ID prefix.\n *\n * For the **id** query to work properly, this means that all id-to-URL mappings must have been previously configured\n * using the `$mdIconProvider`.\n *\n * @returns {angular.$q.Promise} A promise that gets resolved to a clone of the initial SVG DOM element; which was\n * created from the SVG markup in the SVG data file. If an error occurs (e.g. the icon cannot be found) the promise\n * will get rejected.\n *\n * @usage\n * <hljs lang=\"js\">\n * function SomeDirective($mdIcon) {\n *\n *   // See if the icon has already been loaded, if not then lookup the icon from the\n *   // registry cache, load and cache it for future requests.\n *   // NOTE: Non-URL queries require configuration with $mdIconProvider.\n *   $mdIcon('android').then(function(iconEl)    { element.append(iconEl); });\n *   $mdIcon('work:chair').then(function(iconEl) { element.append(iconEl); });\n *\n *   // Load and cache the external SVG using a URL.\n *   $mdIcon('img/icons/android.svg').then(function(iconEl) {\n *     element.append(iconEl);\n *   });\n * };\n * </hljs>\n *\n * > <b>Note:</b> The `<md-icon>` directive internally uses the `$mdIcon` service to query, load,\n *   and instantiate SVG DOM elements.\n */\n\n/* @ngInject */\nfunction MdIconService(config, $templateRequest, $q, $log, $mdUtil, $sce) {\n  var iconCache = {};\n  var svgCache = {};\n  var urlRegex = /[-\\w@:%+.~#?&//=]{2,}\\.[a-z]{2,4}\\b(\\/[-\\w@:%+.~#?&//=]*)?/i;\n  var dataUrlRegex = /^data:image\\/svg\\+xml[\\s*;\\w\\-=]*?(base64)?,(.*)$/i;\n\n  Icon.prototype = {clone: cloneSVG, prepare: prepareAndStyle};\n  getIcon.fontSet = findRegisteredFontSet;\n\n  // Publish service...\n  return getIcon;\n\n  /**\n   * Actual $mdIcon service is essentially a lookup function\n   * @param {*} id $sce trust wrapper over a URL string, URL, icon registry id, or icon set id\n   * @returns {angular.$q.Promise}\n   */\n  function getIcon(id) {\n    id = id || '';\n\n    // If the \"id\" provided is not a string, the only other valid value is a $sce trust wrapper\n    // over a URL string. If the value is not trusted, this will intentionally throw an error\n    // because the user is attempted to use an unsafe URL, potentially opening themselves up\n    // to an XSS attack.\n    if (!angular.isString(id)) {\n      id = $sce.getTrustedUrl(id);\n    }\n\n    // If already loaded and cached, use a clone of the cached icon.\n    // Otherwise either load by URL, or lookup in the registry and then load by URL, and cache.\n\n    if (iconCache[id]) {\n      return $q.when(transformClone(iconCache[id]));\n    }\n\n    if (urlRegex.test(id) || dataUrlRegex.test(id)) {\n      return loadByURL(id).then(cacheIcon(id));\n    }\n\n    if (id.indexOf(':') === -1) {\n      id = '$default:' + id;\n    }\n\n    var load = config[id] ? loadByID : loadFromIconSet;\n    return load(id)\n      .then(cacheIcon(id));\n  }\n\n  /**\n   * Lookup a registered fontSet style using its alias.\n   * @param {string} alias used to lookup the alias in the array of fontSets\n   * @returns {*} matching fontSet or the defaultFontSet if that alias does not match\n   */\n  function findRegisteredFontSet(alias) {\n    var useDefault = angular.isUndefined(alias) || !(alias && alias.length);\n    if (useDefault) {\n      return config.defaultFontSet;\n    }\n\n    var result = alias;\n    angular.forEach(config.fontSets, function(fontSet) {\n      if (fontSet.alias === alias) {\n        result = fontSet.fontSet || result;\n      }\n    });\n\n    return result;\n  }\n\n  /**\n   * @param {!Icon} cacheElement cached icon from the iconCache\n   * @returns {Icon} cloned Icon element with unique ids\n   */\n  function transformClone(cacheElement) {\n    var clone = cacheElement.clone();\n    var newUid = $mdUtil.nextUid();\n    var cacheSuffix, svgUrlQuerySelector, i, xlinkHrefValue;\n    // These are SVG attributes that can reference element ids.\n    var svgUrlAttributes = [\n      'clip-path', 'color-profile', 'cursor', 'fill', 'filter', 'href', 'marker-start',\n      'marker-mid', 'marker-end', 'mask', 'stroke', 'style', 'vector-effect'\n    ];\n    var isIeSvg = clone.innerHTML === undefined;\n\n    // Verify that the newUid only contains a number and not some XSS content.\n    if (!isFinite(Number(newUid))) {\n      throw new Error('Unsafe and unexpected non-number result from $mdUtil.nextUid().');\n    }\n    cacheSuffix = '_cache' + newUid;\n\n    // For each cached icon, we need to modify the id attributes and references.\n    // This is needed because SVG ids are treated as normal DOM ids and should not be duplicated on\n    // the page.\n    if (clone.id) {\n      clone.id += cacheSuffix;\n    }\n\n    // Do as much as possible with querySelectorAll as it provides much greater performance\n    // than RegEx against serialized DOM.\n    angular.forEach(clone.querySelectorAll('[id]'), function(descendantElem) {\n      svgUrlQuerySelector = '';\n      for (i = 0; i < svgUrlAttributes.length; i++) {\n        svgUrlQuerySelector += '[' + svgUrlAttributes[i] + '=\"url(#' + descendantElem.id + ')\"]';\n        if (i + 1 < svgUrlAttributes.length) {\n          svgUrlQuerySelector += ', ';\n        }\n      }\n      // Append the cacheSuffix to references of the element's id within url(#id) calls.\n      angular.forEach(clone.querySelectorAll(svgUrlQuerySelector), function(refItem) {\n        updateSvgIdReferences(descendantElem, refItem, isIeSvg, newUid);\n      });\n      // Handle usages of url(#id) in the SVG's stylesheets\n      angular.forEach(clone.querySelectorAll('style'), function(refItem) {\n        updateSvgIdReferences(descendantElem, refItem, isIeSvg, newUid);\n      });\n\n      // Update ids referenced by the deprecated (in SVG v2) xlink:href XML attribute. The now\n      // preferred href attribute is handled above. However, this non-standard XML namespaced\n      // attribute cannot be handled in the same way. Explanation of this query selector here:\n      // https://stackoverflow.com/q/23034283/633107.\n      angular.forEach(clone.querySelectorAll('[*|href]:not([href])'), function(refItem) {\n        xlinkHrefValue = refItem.getAttribute('xlink:href');\n        if (xlinkHrefValue) {\n          xlinkHrefValue = xlinkHrefValue.replace(\"#\" + descendantElem.id, \"#\" + descendantElem.id + cacheSuffix);\n          refItem.setAttribute('xlink:href', xlinkHrefValue);\n        }\n      });\n\n      descendantElem.id += cacheSuffix;\n    });\n\n    return clone;\n  }\n\n  /**\n   * @param {Element} referencedElement element w/ id that needs to be updated\n   * @param {Element} referencingElement element that references the original id\n   * @param {boolean} isIeSvg true if we're dealing with an SVG in IE11, false otherwise\n   * @param {string} newUid the cache id to add as part of the cache suffix\n   */\n  function updateSvgIdReferences(referencedElement, referencingElement, isIeSvg, newUid) {\n    var svgElement, cacheSuffix;\n\n    // Verify that the newUid only contains a number and not some XSS content.\n    if (!isFinite(Number(newUid))) {\n      throw new Error('Unsafe and unexpected non-number result for newUid.');\n    }\n    cacheSuffix = '_cache' + newUid;\n\n    // outerHTML of SVG elements is not supported by IE11\n    if (isIeSvg) {\n      svgElement = $mdUtil.getOuterHTML(referencingElement);\n      svgElement = svgElement.replace(\"url(#\" + referencedElement.id + \")\",\n        \"url(#\" + referencedElement.id + cacheSuffix + \")\");\n      referencingElement.textContent = angular.element(svgElement)[0].innerHTML;\n    } else {\n      // This use of outerHTML should be safe from XSS attack since we are only injecting the\n      // cacheSuffix with content from $mdUtil.nextUid which we verify is a finite number above.\n      referencingElement.outerHTML = referencingElement.outerHTML.replace(\n        \"url(#\" + referencedElement.id + \")\",\n        \"url(#\" + referencedElement.id + cacheSuffix + \")\");\n    }\n  }\n\n  /**\n   * Prepare and cache the loaded icon for the specified `id`.\n   * @param {string} id icon cache id\n   * @returns {function(*=): *}\n   */\n  function cacheIcon(id) {\n\n    return function updateCache(icon) {\n      iconCache[id] = isIcon(icon) ? icon : new Icon(icon, config[id]);\n\n      return transformClone(iconCache[id]);\n    };\n  }\n\n  /**\n   * Lookup the configuration in the registry, if !registered throw an error\n   * otherwise load the icon [on-demand] using the registered URL.\n   * @param {string} id icon registry id\n   * @returns {angular.$q.Promise}\n   */\n  function loadByID(id) {\n    var iconConfig = config[id];\n    return loadByURL(iconConfig.url).then(function(icon) {\n      return new Icon(icon, iconConfig);\n    });\n  }\n\n  /**\n   * Loads the file as XML and uses querySelector( <id> ) to find the desired node...\n   * @param {string} id icon id in icon set\n   * @returns {angular.$q.Promise}\n   */\n  function loadFromIconSet(id) {\n    var setName = id.substring(0, id.lastIndexOf(':')) || '$default';\n    var iconSetConfig = config[setName];\n\n    return !iconSetConfig ? announceIdNotFound(id) : loadByURL(iconSetConfig.url).then(extractFromSet);\n\n    function extractFromSet(set) {\n      var iconName = id.slice(id.lastIndexOf(':') + 1);\n      var icon = set.querySelector('#' + iconName);\n      return icon ? new Icon(icon, iconSetConfig) : announceIdNotFound(id);\n    }\n\n    function announceIdNotFound(id) {\n      var msg = 'icon ' + id + ' not found';\n      $log.warn(msg);\n\n      return $q.reject(msg || id);\n    }\n  }\n\n  /**\n   * Load the icon by URL (may use the $templateCache).\n   * Extract the data for later conversion to Icon\n   * @param {string} url icon URL\n   * @returns {angular.$q.Promise}\n   */\n  function loadByURL(url) {\n    /* Load the icon from embedded data URL. */\n    function loadByDataUrl(url) {\n      var results = dataUrlRegex.exec(url);\n      var isBase64 = /base64/i.test(url);\n      var data = isBase64 ? window.atob(results[2]) : results[2];\n\n      return $q.when(angular.element(data)[0]);\n    }\n\n    /* Load the icon by URL using HTTP. */\n    function loadByHttpUrl(url) {\n      return $q(function(resolve, reject) {\n        // Catch HTTP or generic errors not related to incorrect icon IDs.\n        var announceAndReject = function(err) {\n            var msg = angular.isString(err) ? err : (err.message || err.data || err.statusText);\n            $log.warn(msg);\n            reject(err);\n          },\n          extractSvg = function(response) {\n            if (!svgCache[url]) {\n              svgCache[url] = angular.element('<div>').append(response)[0].querySelector('svg');\n            }\n            resolve(svgCache[url]);\n          };\n\n        $templateRequest(url, true).then(extractSvg, announceAndReject);\n      });\n    }\n\n    return dataUrlRegex.test(url)\n      ? loadByDataUrl(url)\n      : loadByHttpUrl(url);\n  }\n\n  /**\n   * Check target signature to see if it is an Icon instance.\n   * @param {Icon|Element} target\n   * @returns {boolean} true if the specified target is an Icon object, false otherwise.\n   */\n  function isIcon(target) {\n    return angular.isDefined(target.element) && angular.isDefined(target.config);\n  }\n\n  /**\n   * Define the Icon class\n   * @param {Element} el\n   * @param {=ConfigurationItem} config\n   * @constructor\n   */\n  function Icon(el, config) {\n    // If the node is a <symbol>, it won't be rendered so we have to convert it into <svg>.\n    if (el && el.tagName.toLowerCase() === 'symbol') {\n      var viewbox = el.getAttribute('viewBox');\n      // // Check if innerHTML is supported as IE11 does not support innerHTML on SVG elements.\n      if (el.innerHTML) {\n        el = angular.element('<svg xmlns=\"http://www.w3.org/2000/svg\">')\n          .html(el.innerHTML)[0];\n      } else {\n        el = angular.element('<svg xmlns=\"http://www.w3.org/2000/svg\">')\n          .append($mdUtil.getInnerHTML(el))[0];\n      }\n      if (viewbox) el.setAttribute('viewBox', viewbox);\n    }\n\n    if (el && el.tagName.toLowerCase() !== 'svg') {\n      el = angular.element(\n        '<svg xmlns=\"http://www.w3.org/2000/svg\">').append(el.cloneNode(true))[0];\n    }\n\n    // Inject the namespace if not available...\n    if (!el.getAttribute('xmlns')) {\n      el.setAttribute('xmlns', \"http://www.w3.org/2000/svg\");\n    }\n\n    this.element = el;\n    this.config = config;\n    this.prepare();\n  }\n\n  /**\n   *  Prepare the DOM element that will be cached in the\n   *  loaded iconCache store.\n   */\n  function prepareAndStyle() {\n    var viewBoxSize = this.config ? this.config.viewBoxSize : config.defaultViewBoxSize;\n    angular.forEach({\n      'fit': '',\n      'height': '100%',\n      'width': '100%',\n      'preserveAspectRatio': 'xMidYMid meet',\n      'viewBox': this.element.getAttribute('viewBox') || ('0 0 ' + viewBoxSize + ' ' + viewBoxSize),\n      'focusable': false // Disable IE11s default behavior to make SVGs focusable\n    }, function(val, attr) {\n      this.element.setAttribute(attr, val);\n    }, this);\n  }\n\n  /**\n   * Clone the Icon DOM element.\n   */\n  function cloneSVG() {\n    // If the element or any of its children have a style attribute, then a CSP policy without\n    // 'unsafe-inline' in the style-src directive, will result in a violation.\n    return this.element.cloneNode(true);\n  }\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.input\n */\nmdInputContainerDirective.$inject = [\"$mdTheming\", \"$parse\", \"$$rAF\"];\ninputTextareaDirective.$inject = [\"$mdUtil\", \"$window\", \"$mdAria\", \"$timeout\", \"$mdGesture\"];\nmdMaxlengthDirective.$inject = [\"$animate\", \"$mdUtil\"];\nplaceholderDirective.$inject = [\"$compile\"];\nngMessageDirective.$inject = [\"$mdUtil\"];\nmdSelectOnFocusDirective.$inject = [\"$document\", \"$timeout\"];\nmdInputInvalidMessagesAnimation.$inject = [\"$$AnimateRunner\", \"$animateCss\", \"$mdUtil\"];\nngMessagesAnimation.$inject = [\"$$AnimateRunner\", \"$animateCss\", \"$mdUtil\"];\nngMessageAnimation.$inject = [\"$$AnimateRunner\", \"$animateCss\", \"$mdUtil\", \"$log\"];\nvar inputModule = angular.module('material.components.input', [\n    'material.core'\n  ])\n  .directive('mdInputContainer', mdInputContainerDirective)\n  .directive('label', labelDirective)\n  .directive('input', inputTextareaDirective)\n  .directive('textarea', inputTextareaDirective)\n  .directive('mdMaxlength', mdMaxlengthDirective)\n  .directive('placeholder', placeholderDirective)\n  .directive('ngMessages', ngMessagesDirective)\n  .directive('ngMessage', ngMessageDirective)\n  .directive('ngMessageExp', ngMessageDirective)\n  .directive('mdSelectOnFocus', mdSelectOnFocusDirective)\n\n  .animation('.md-input-invalid', mdInputInvalidMessagesAnimation)\n  .animation('.md-input-messages-animation', ngMessagesAnimation)\n  .animation('.md-input-message-animation', ngMessageAnimation);\n\n// If we are running inside of tests; expose some extra services so that we can test them\nif (window._mdMocksIncluded) {\n  inputModule.service('$$mdInput', function() {\n    return {\n      // special accessor to internals... useful for testing\n      messages: {\n        getElement  : getMessagesElement\n      }\n    };\n  })\n\n  // Register a service for each animation so that we can easily inject them into unit tests\n  .service('mdInputInvalidAnimation', mdInputInvalidMessagesAnimation)\n  .service('mdInputMessagesAnimation', ngMessagesAnimation)\n  .service('mdInputMessageAnimation', ngMessageAnimation);\n}\n\n/**\n * @ngdoc directive\n * @name mdInputContainer\n * @module material.components.input\n *\n * @restrict E\n *\n * @description\n * `<md-input-container>` is the parent of any input or textarea element. It can also optionally\n * wrap `<md-select>` elements so that they will be formatted for use in a form.\n *\n * Input and textarea elements will not behave properly unless the md-input-container parent is\n * provided.\n *\n * A single `<md-input-container>` should contain only one `<input>` or `<md-select>` element,\n * otherwise it will throw an error.\n *\n * <b>Exception:</b> Hidden inputs (`<input type=\"hidden\" />`) are ignored and will not throw an\n * error, so you may combine these with other inputs.\n *\n * <b>Note:</b> When using `ngMessages` with your input element, make sure the message and container\n * elements are *block* elements, otherwise animations applied to the messages will not look as\n * intended. Either use a `div` and apply the `ng-message` and `ng-messages` classes respectively,\n * or use the `md-block` class on your element.\n *\n * @param {expression=} md-is-error When the given expression evaluates to `true`, the input\n *   container will go into the error state. Defaults to erroring if the input has been touched and\n *   is invalid.\n * @param {boolean=} md-no-float When present, `placeholder` attributes on the input will not be\n *   converted to floating labels.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-input-container>\n *   <label>Username</label>\n *   <input type=\"text\" ng-model=\"user.name\">\n * </md-input-container>\n *\n * <md-input-container>\n *   <label>Description</label>\n *   <textarea ng-model=\"user.description\"></textarea>\n * </md-input-container>\n *\n * <md-input-container>\n *   <md-select ng-model=\"user.state\" placeholder=\"State of Residence\">\n *     <md-option ng-value=\"state\" ng-repeat=\"state in states\">{{ state }}</md-option>\n *   </md-select>\n * </md-input-container>\n * </hljs>\n *\n * <h3>When disabling floating labels</h3>\n * <hljs lang=\"html\">\n * <md-input-container md-no-float>\n *   <input type=\"text\" placeholder=\"Non-Floating Label\">\n * </md-input-container>\n * </hljs>\n *\n * <h3>Aligning Form Elements</h3>\n * Wrap your form elements with the `md-inline-form` class in order to align them horizontally\n * within a form.\n *\n * <hljs lang=\"html\">\n * <form class=\"md-inline-form\">\n *   <md-input-container>\n *     <label>Username</label>\n *     <input type=\"text\" ng-model=\"user.name\">\n *   </md-input-container>\n *\n *   <md-input-container>\n *     <label>Description</label>\n *     <textarea ng-model=\"user.description\"></textarea>\n *   </md-input-container>\n *\n *   <md-input-container>\n *     <label>State of Residence</label>\n *     <md-select ng-model=\"user.state\">\n *       <md-option ng-value=\"state\" ng-repeat=\"state in states\">{{ state }}</md-option>\n *     </md-select>\n *   </md-input-container>\n *\n *   <md-input-container>\n *     <label>Enter date</label>\n *     <md-datepicker ng-model=\"user.submissionDate\"></md-datepicker>\n *   </md-input-container>\n *\n *   <md-input-container>\n *     <md-checkbox ng-model=\"user.licenseAccepted\">\n *       I agree to the license terms.\n *     </md-checkbox>\n *   </md-input-container>\n * </form>\n * </hljs>\n */\nfunction mdInputContainerDirective($mdTheming, $parse, $$rAF) {\n\n  ContainerCtrl.$inject = [\"$scope\", \"$element\", \"$attrs\", \"$animate\"];\n  var INPUT_TAGS = ['INPUT', 'TEXTAREA', 'SELECT', 'MD-SELECT'];\n\n  var LEFT_SELECTORS = INPUT_TAGS.reduce(function(selectors, isel) {\n    return selectors.concat(['md-icon ~ ' + isel, '.md-icon ~ ' + isel]);\n  }, []).join(\",\");\n\n  var RIGHT_SELECTORS = INPUT_TAGS.reduce(function(selectors, isel) {\n    return selectors.concat([isel + ' ~ md-icon', isel + ' ~ .md-icon']);\n  }, []).join(\",\");\n\n  return {\n    restrict: 'E',\n    compile: compile,\n    controller: ContainerCtrl\n  };\n\n  function compile(tElement) {\n    // Check for both a left & right icon\n    var hasLeftIcon = tElement[0].querySelector(LEFT_SELECTORS);\n    var hasRightIcon = tElement[0].querySelector(RIGHT_SELECTORS);\n\n    return function postLink(scope, element) {\n      $mdTheming(element);\n\n      if (hasLeftIcon || hasRightIcon) {\n        // When accessing the element's contents synchronously, they may not be defined yet because\n        // of the use of ng-if. If we wait one frame, then the element should be there if the ng-if\n        // resolves to true.\n        $$rAF(function() {\n          // Handle the case where the md-icon element is initially hidden via ng-if from #9529.\n          // We don't want to preserve the space for the icon in the case of ng-if, like we do for\n          // ng-show.\n          // Note that we can't use the same selectors from above because the elements are no longer\n          // siblings for textareas at this point due to the insertion of the md-resize-wrapper.\n          var iconNotRemoved = element[0].querySelector('md-icon') ||\n            element[0].querySelector('.md-icon');\n          if (hasLeftIcon && iconNotRemoved) {\n            element.addClass('md-icon-left');\n          }\n          if (hasRightIcon && iconNotRemoved) {\n            element.addClass('md-icon-right');\n          }\n        });\n      }\n    };\n  }\n\n  function ContainerCtrl($scope, $element, $attrs, $animate) {\n    var self = this;\n\n    $element.addClass('md-auto-horizontal-margin');\n\n    self.isErrorGetter = $attrs.mdIsError && $parse($attrs.mdIsError);\n\n    self.delegateClick = function() {\n      self.input.focus();\n    };\n    self.element = $element;\n    self.setFocused = function(isFocused) {\n      $element.toggleClass('md-input-focused', !!isFocused);\n    };\n    self.setHasValue = function(hasValue) {\n      $element.toggleClass('md-input-has-value', !!hasValue);\n    };\n    self.setHasPlaceholder = function(hasPlaceholder) {\n      $element.toggleClass('md-input-has-placeholder', !!hasPlaceholder);\n    };\n    self.setInvalid = function(isInvalid) {\n      if (isInvalid) {\n        $animate.addClass($element, 'md-input-invalid');\n      } else {\n        $animate.removeClass($element, 'md-input-invalid');\n      }\n    };\n    $scope.$watch(function() {\n      return self.label && self.input;\n    }, function(hasLabelAndInput) {\n      if (hasLabelAndInput && !self.label.attr('for')) {\n        self.label.attr('for', self.input.attr('id'));\n      }\n    });\n  }\n}\n\nfunction labelDirective() {\n  return {\n    restrict: 'E',\n    require: '^?mdInputContainer',\n    link: function(scope, element, attr, containerCtrl) {\n      if (!containerCtrl || attr.mdNoFloat || element.hasClass('md-container-ignore')) return;\n\n      containerCtrl.label = element;\n      scope.$on('$destroy', function() {\n        containerCtrl.label = null;\n      });\n    }\n  };\n}\n\n/**\n * @ngdoc directive\n * @name mdInput\n * @restrict E\n * @module material.components.input\n *\n * @description\n * You can use any `<input>` or `<textarea>` element as a child of an `<md-input-container>`. This\n * allows you to build complex forms for data entry.\n *\n * When the input is required and uses a floating label, then the label will automatically contain\n * an asterisk (`*`).<br/>\n * This behavior can be disabled by using the `md-no-asterisk` attribute.\n *\n * @param {number=} md-maxlength The maximum number of characters allowed in this input. If this is\n *   specified, a character counter will be shown underneath the input.<br/><br/>\n *   The purpose of **`md-maxlength`** is exactly to show the max length counter text. If you don't\n *   want the counter text and only need \"plain\" validation, you can use the \"simple\" `ng-maxlength`\n *   or maxlength attributes.<br/><br/>\n * @param {boolean=} ng-trim If set to false, the input text will be not trimmed automatically.\n *     Defaults to true.\n * @param {string=} aria-label Aria-label is required when no label is present.  A warning message\n *   will be logged in the console if not present.\n * @param {string=} placeholder An alternative approach to using aria-label when the label is not\n *   PRESENT. The placeholder text is copied to the aria-label attribute.\n * @param {boolean=} md-no-autogrow When present, textareas will not grow automatically.\n * @param {boolean=} md-no-asterisk When present, an asterisk will not be appended to the inputs\n *   floating label.\n * @param {boolean=} md-no-resize Disables the textarea resize handle.\n * @param {number=} max-rows The maximum amount of rows for a textarea.\n * @param {boolean=} md-detect-hidden When present, textareas will be sized properly when they are\n *   revealed after being hidden. This is off by default for performance reasons because it\n *   guarantees a reflow every digest cycle.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-input-container>\n *   <label>Color</label>\n *   <input type=\"text\" ng-model=\"color\" required md-maxlength=\"10\">\n * </md-input-container>\n * </hljs>\n *\n * <h3>With Errors</h3>\n *\n * `md-input-container` also supports errors using the standard `ng-messages` directives and\n * animates the messages when they become visible using from the `ngEnter`/`ngLeave` events or\n * the `ngShow`/`ngHide` events.\n *\n * By default, the messages will be hidden until the input is in an error state. This is based off\n * of the `md-is-error` expression of the `md-input-container`. This gives the user a chance to\n * fill out the form before the errors become visible.\n *\n * <hljs lang=\"html\">\n * <form name=\"colorForm\">\n *   <md-input-container>\n *     <label>Favorite Color</label>\n *     <input name=\"favoriteColor\" ng-model=\"favoriteColor\" required>\n *     <div ng-messages=\"colorForm.favoriteColor.$error\">\n *       <div ng-message=\"required\">This is required!</div>\n *     </div>\n *   </md-input-container>\n * </form>\n * </hljs>\n *\n * We automatically disable this auto-hiding functionality if you provide any of the following\n * visibility directives on the `ng-messages` container:\n *\n *  - `ng-if`\n *  - `ng-show`/`ng-hide`\n *  - `ng-switch-when`/`ng-switch-default`\n *\n * You can also disable this functionality manually by adding the `md-auto-hide=\"false\"` expression\n * to the `ng-messages` container. This may be helpful if you always want to see the error messages\n * or if you are building your own visibility directive.\n *\n * _<b>Note:</b> The `md-auto-hide` attribute is a static string that is  only checked upon\n * initialization of the `ng-messages` directive to see if it equals the string `false`._\n *\n * <hljs lang=\"html\">\n * <form name=\"userForm\">\n *   <md-input-container>\n *     <label>Last Name</label>\n *     <input name=\"lastName\" ng-model=\"lastName\" required md-maxlength=\"10\" minlength=\"4\">\n *     <div ng-messages=\"userForm.lastName.$error\" ng-show=\"userForm.lastName.$dirty\">\n *       <div ng-message=\"required\">This is required!</div>\n *       <div ng-message=\"md-maxlength\">That's too long!</div>\n *       <div ng-message=\"minlength\">That's too short!</div>\n *     </div>\n *   </md-input-container>\n *   <md-input-container>\n *     <label>Biography</label>\n *     <textarea name=\"bio\" ng-model=\"biography\" required md-maxlength=\"150\"></textarea>\n *     <div ng-messages=\"userForm.bio.$error\" ng-show=\"userForm.bio.$dirty\">\n *       <div ng-message=\"required\">This is required!</div>\n *       <div ng-message=\"md-maxlength\">That's too long!</div>\n *     </div>\n *   </md-input-container>\n *   <md-input-container>\n *     <input aria-label='title' ng-model='title'>\n *   </md-input-container>\n *   <md-input-container>\n *     <input placeholder='title' ng-model='title'>\n *   </md-input-container>\n * </form>\n * </hljs>\n *\n * <h3>Notes</h3>\n *\n * - Requires [ngMessages](https://docs.angularjs.org/api/ngMessages).\n * - Behaves like the [AngularJS input directive](https://docs.angularjs.org/api/ng/directive/input).\n *\n * The `md-input` and `md-input-container` directives use very specific positioning to achieve the\n * error animation effects. Therefore, it is *not* advised to use the Layout system inside of the\n * `<md-input-container>` tags. Instead, use relative or absolute positioning.\n *\n *\n * <h3>Textarea directive</h3>\n * The `textarea` element within a `md-input-container` has the following specific behavior:\n * - By default the `textarea` grows as the user types. This can be disabled via the `md-no-autogrow`\n * attribute.\n * - If a `textarea` has the `rows` attribute, it will treat the `rows` as the minimum height and will\n * continue growing as the user types. For example a textarea with `rows=\"3\"` will be 3 lines of text\n * high initially. If no rows are specified, the directive defaults to 1.\n * - The textarea's height gets set on initialization, as well as while the user is typing. In certain situations\n * (e.g. while animating) the directive might have been initialized, before the element got it's final height. In\n * those cases, you can trigger a resize manually by broadcasting a `md-resize-textarea` event on the scope.\n * - If you want a `textarea` to stop growing at a certain point, you can specify the `max-rows` attribute.\n * - The textarea's bottom border acts as a handle which users can drag, in order to resize the element vertically.\n * Once the user has resized a `textarea`, the autogrowing functionality becomes disabled. If you don't want a\n * `textarea` to be resizeable by the user, you can add the `md-no-resize` attribute.\n */\n\nfunction inputTextareaDirective($mdUtil, $window, $mdAria, $timeout, $mdGesture) {\n  return {\n    restrict: 'E',\n    require: ['^?mdInputContainer', '?ngModel', '?^form'],\n    link: postLink\n  };\n\n  function postLink(scope, element, attr, ctrls) {\n\n    var containerCtrl = ctrls[0];\n    var hasNgModel = !!ctrls[1];\n    var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();\n    var parentForm = ctrls[2];\n    var isReadonly = angular.isDefined(attr.readonly);\n    var mdNoAsterisk = $mdUtil.parseAttributeBoolean(attr.mdNoAsterisk);\n    var tagName = element[0].tagName.toLowerCase();\n\n\n    if (!containerCtrl) return;\n    if (attr.type === 'hidden') {\n      element.attr('aria-hidden', 'true');\n      return;\n    } else if (containerCtrl.input) {\n      if (containerCtrl.input[0].contains(element[0])) {\n        return;\n      } else {\n        throw new Error(\"<md-input-container> can only have *one* <input>, <textarea> or <md-select> child element!\");\n      }\n    }\n    containerCtrl.input = element;\n\n    setupAttributeWatchers();\n\n    // Add an error spacer div after our input to provide space for the char counter and any ng-messages\n    var errorsSpacer = angular.element('<div class=\"md-errors-spacer\">');\n    element.after(errorsSpacer);\n\n    var placeholderText = angular.isString(attr.placeholder) ? attr.placeholder.trim() : '';\n    if (!containerCtrl.label && !placeholderText.length) {\n      $mdAria.expect(element, 'aria-label');\n    }\n\n    element.addClass('md-input');\n    if (!element.attr('id')) {\n      element.attr('id', 'input_' + $mdUtil.nextUid());\n    }\n\n    // This works around a Webkit issue where number inputs, placed in a flexbox, that have\n    // a `min` and `max` will collapse to about 1/3 of their proper width. Please check #7349\n    // for more info. Also note that we don't override the `step` if the user has specified it,\n    // in order to prevent some unexpected behaviour.\n    if (tagName === 'input' && attr.type === 'number' && attr.min && attr.max && !attr.step) {\n      element.attr('step', 'any');\n    } else if (tagName === 'textarea') {\n      setupTextarea();\n    }\n\n    // If the input doesn't have an ngModel, it may have a static value. For that case,\n    // we have to do one initial check to determine if the container should be in the\n    // \"has a value\" state.\n    if (!hasNgModel) {\n      inputCheckValue();\n    }\n\n    var isErrorGetter = containerCtrl.isErrorGetter || function() {\n      return ngModelCtrl.$invalid && (ngModelCtrl.$touched || (parentForm && parentForm.$submitted));\n    };\n\n    scope.$watch(isErrorGetter, containerCtrl.setInvalid);\n\n    // When the developer uses the ngValue directive for the input, we have to observe the attribute, because\n    // AngularJS's ngValue directive is just setting the `value` attribute.\n    if (attr.ngValue) {\n      attr.$observe('value', inputCheckValue);\n    }\n\n    ngModelCtrl.$parsers.push(ngModelPipelineCheckValue);\n    ngModelCtrl.$formatters.push(ngModelPipelineCheckValue);\n\n    element.on('input', inputCheckValue);\n\n    if (!isReadonly) {\n      element\n        .on('focus', function(ev) {\n          $mdUtil.nextTick(function() {\n            containerCtrl.setFocused(true);\n          });\n        })\n        .on('blur', function(ev) {\n          $mdUtil.nextTick(function() {\n            containerCtrl.setFocused(false);\n            inputCheckValue();\n          });\n        });\n    }\n\n    scope.$on('$destroy', function() {\n      containerCtrl.setFocused(false);\n      containerCtrl.setHasValue(false);\n      containerCtrl.input = null;\n    });\n\n    /** Gets run through ngModel's pipeline and set the `has-value` class on the container. */\n    function ngModelPipelineCheckValue(arg) {\n      containerCtrl.setHasValue(!ngModelCtrl.$isEmpty(arg));\n      return arg;\n    }\n\n    function setupAttributeWatchers() {\n      if (containerCtrl.label) {\n        attr.$observe('required', function (value) {\n          // We don't need to parse the required value, it's always a boolean because of AngularJS'\n          // required directive.\n          if (containerCtrl.label) {\n            containerCtrl.label.toggleClass('md-required', value && !mdNoAsterisk);\n          }\n        });\n      }\n    }\n\n    function inputCheckValue() {\n      // An input's value counts if its length > 0,\n      // or if the input's validity state says it has bad input (eg string in a number input)\n      containerCtrl.setHasValue(element.val().length > 0 || (element[0].validity || {}).badInput);\n    }\n\n    function setupTextarea() {\n      var isAutogrowing = !attr.hasOwnProperty('mdNoAutogrow');\n\n      attachResizeHandle();\n\n      if (!isAutogrowing) return;\n\n      // Can't check if height was or not explicity set,\n      // so rows attribute will take precedence if present\n      var minRows = attr.hasOwnProperty('rows') ? parseInt(attr.rows) : NaN;\n      var maxRows = attr.hasOwnProperty('maxRows') ? parseInt(attr.maxRows) : NaN;\n      var scopeResizeListener = scope.$on('md-resize-textarea', growTextarea);\n      var lineHeight = null;\n      var node = element[0];\n\n      // This timeout is necessary, because the browser needs a little bit\n      // of time to calculate the `clientHeight` and `scrollHeight`.\n      $timeout(function() {\n        $mdUtil.nextTick(growTextarea);\n      }, 10, false);\n\n      // We could leverage ngModel's $parsers here, however it\n      // isn't reliable, because AngularJS trims the input by default,\n      // which means that growTextarea won't fire when newlines and\n      // spaces are added.\n      element.on('input', growTextarea);\n\n      // We should still use the $formatters, because they fire when\n      // the value was changed from outside the textarea.\n      if (hasNgModel) {\n        ngModelCtrl.$formatters.push(formattersListener);\n      }\n\n      if (!minRows) {\n        element.attr('rows', 1);\n      }\n\n      angular.element($window).on('resize', growTextarea);\n      scope.$on('$destroy', disableAutogrow);\n\n      function growTextarea() {\n        // temporarily disables element's flex so its height 'runs free'\n        element\n          .attr('rows', 1)\n          .css('height', 'auto')\n          .addClass('md-no-flex');\n\n        var height = getHeight();\n\n        if (!lineHeight) {\n          // offsetHeight includes padding which can throw off our value\n          var originalPadding = element[0].style.padding || '';\n          lineHeight = element.css('padding', 0).prop('offsetHeight');\n          element[0].style.padding = originalPadding;\n        }\n\n        if (minRows && lineHeight) {\n          height = Math.max(height, lineHeight * minRows);\n        }\n\n        if (maxRows && lineHeight) {\n          var maxHeight = lineHeight * maxRows;\n\n          if (maxHeight < height) {\n            element.attr('md-no-autogrow', '');\n            height = maxHeight;\n          } else {\n            element.removeAttr('md-no-autogrow');\n          }\n        }\n\n        if (lineHeight) {\n          element.attr('rows', Math.round(height / lineHeight));\n        }\n\n        element\n          .css('height', height + 'px')\n          .removeClass('md-no-flex');\n      }\n\n      function getHeight() {\n        var offsetHeight = node.offsetHeight;\n        var line = node.scrollHeight - offsetHeight;\n        return offsetHeight + Math.max(line, 0);\n      }\n\n      function formattersListener(value) {\n        $mdUtil.nextTick(growTextarea);\n        return value;\n      }\n\n      function disableAutogrow() {\n        if (!isAutogrowing) return;\n\n        isAutogrowing = false;\n        angular.element($window).off('resize', growTextarea);\n        scopeResizeListener && scopeResizeListener();\n        element\n          .attr('md-no-autogrow', '')\n          .off('input', growTextarea);\n\n        if (hasNgModel) {\n          var listenerIndex = ngModelCtrl.$formatters.indexOf(formattersListener);\n\n          if (listenerIndex > -1) {\n            ngModelCtrl.$formatters.splice(listenerIndex, 1);\n          }\n        }\n      }\n\n      function attachResizeHandle() {\n        if (attr.hasOwnProperty('mdNoResize')) return;\n\n        var handle = angular.element('<div class=\"md-resize-handle\"></div>');\n        var isDragging = false;\n        var dragStart = null;\n        var startHeight = 0;\n        var container = containerCtrl.element;\n        var dragGestureHandler = $mdGesture.register(handle, 'drag', { horizontal: false });\n\n\n        element.wrap('<div class=\"md-resize-wrapper\">').after(handle);\n        handle.on('mousedown', onMouseDown);\n\n        container\n          .on('$md.dragstart', onDragStart)\n          .on('$md.drag', onDrag)\n          .on('$md.dragend', onDragEnd);\n\n        scope.$on('$destroy', function() {\n          handle\n            .off('mousedown', onMouseDown)\n            .remove();\n\n          container\n            .off('$md.dragstart', onDragStart)\n            .off('$md.drag', onDrag)\n            .off('$md.dragend', onDragEnd);\n\n          dragGestureHandler();\n          handle = null;\n          container = null;\n          dragGestureHandler = null;\n        });\n\n        function onMouseDown(ev) {\n          ev.preventDefault();\n          isDragging = true;\n          dragStart = ev.clientY;\n          startHeight = parseFloat(element.css('height')) || element.prop('offsetHeight');\n        }\n\n        function onDragStart(ev) {\n          if (!isDragging) return;\n          ev.preventDefault();\n          disableAutogrow();\n          container.addClass('md-input-resized');\n        }\n\n        function onDrag(ev) {\n          if (!isDragging) return;\n\n          element.css('height', (startHeight + ev.pointer.distanceY) + 'px');\n        }\n\n        function onDragEnd(ev) {\n          if (!isDragging) return;\n          isDragging = false;\n          container.removeClass('md-input-resized');\n        }\n      }\n\n      // Attach a watcher to detect when the textarea gets shown.\n      if (attr.hasOwnProperty('mdDetectHidden')) {\n\n        var handleHiddenChange = function() {\n          var wasHidden = false;\n\n          return function() {\n            var isHidden = node.offsetHeight === 0;\n\n            if (isHidden === false && wasHidden === true) {\n              growTextarea();\n            }\n\n            wasHidden = isHidden;\n          };\n        }();\n\n        // Check every digest cycle whether the visibility of the textarea has changed.\n        // Queue up to run after the digest cycle is complete.\n        scope.$watch(function() {\n          $mdUtil.nextTick(handleHiddenChange, false);\n          return true;\n        });\n      }\n    }\n  }\n}\n\nfunction mdMaxlengthDirective($animate, $mdUtil) {\n  return {\n    restrict: 'A',\n    require: ['ngModel', '^mdInputContainer'],\n    link: postLink\n  };\n\n  function postLink(scope, element, attr, ctrls) {\n    var maxlength = parseInt(attr.mdMaxlength);\n    if (isNaN(maxlength)) maxlength = -1;\n    var ngModelCtrl = ctrls[0];\n    var containerCtrl = ctrls[1];\n    var charCountEl, errorsSpacer;\n    var ngTrim = angular.isDefined(attr.ngTrim) ? $mdUtil.parseAttributeBoolean(attr.ngTrim) : true;\n    var isPasswordInput = attr.type === 'password';\n\n    scope.$watch(attr.mdMaxlength, function(value) {\n      maxlength = value;\n    });\n\n    ngModelCtrl.$validators['md-maxlength'] = function(modelValue, viewValue) {\n      if (!angular.isNumber(maxlength) || maxlength < 0) {\n        return true;\n      }\n\n      // We always update the char count, when the modelValue has changed.\n      // Using the $validators for triggering the update works very well.\n      renderCharCount();\n\n      var elementVal = element.val() || viewValue;\n      if (elementVal === undefined || elementVal === null) {\n        elementVal = '';\n      }\n      elementVal = ngTrim && !isPasswordInput && angular.isString(elementVal) ? elementVal.trim() : elementVal;\n      // Force the value into a string since it may be a number,\n      // which does not have a length property.\n      return String(elementVal).length <= maxlength;\n    };\n\n    /**\n     * Override the default NgModelController $isEmpty check to take ng-trim, password inputs,\n     * etc. into account.\n     * @param value {*} the input's value\n     * @returns {boolean} true if the input's value should be considered empty, false otherwise\n     */\n    ngModelCtrl.$isEmpty = function(value) {\n      return calculateInputValueLength(value) === 0;\n    };\n\n    // Wait until the next tick to ensure that the input has setup the errors spacer where we will\n    // append our counter\n    $mdUtil.nextTick(function() {\n      errorsSpacer = angular.element(containerCtrl.element[0].querySelector('.md-errors-spacer'));\n      charCountEl = angular.element('<div class=\"md-char-counter\">');\n\n      // Append our character counter inside the errors spacer\n      errorsSpacer.append(charCountEl);\n\n      attr.$observe('ngTrim', function (value) {\n        ngTrim = angular.isDefined(value) ? $mdUtil.parseAttributeBoolean(value) : true;\n      });\n\n      scope.$watch(attr.mdMaxlength, function(value) {\n        if (angular.isNumber(value) && value > 0) {\n          if (!charCountEl.parent().length) {\n            $animate.enter(charCountEl, errorsSpacer);\n          }\n          renderCharCount();\n        } else {\n          $animate.leave(charCountEl);\n        }\n      });\n    });\n\n    /**\n     * Calculate the input value's length after coercing it to a string\n     * and trimming it if appropriate.\n     * @param value {*} the input's value\n     * @returns {number} calculated length of the input's value\n     */\n    function calculateInputValueLength(value) {\n      value = ngTrim && !isPasswordInput && angular.isString(value) ? value.trim() : value;\n      if (value === undefined || value === null) {\n        value = '';\n      }\n      return String(value).length;\n    }\n\n    function renderCharCount() {\n      // If we have not been initialized or appended to the body yet; do not render.\n      if (!charCountEl || !charCountEl.parent()) {\n        return;\n      }\n      // Force the value into a string since it may be a number,\n      // which does not have a length property.\n      charCountEl.text(calculateInputValueLength(element.val()) + ' / ' + maxlength);\n    }\n  }\n}\n\nfunction placeholderDirective($compile) {\n  return {\n    restrict: 'A',\n    require: '^^?mdInputContainer',\n    priority: 200,\n    link: {\n      // Note that we need to do this in the pre-link, as opposed to the post link, if we want to\n      // support data bindings in the placeholder. This is necessary, because we have a case where\n      // we transfer the placeholder value to the `<label>` and we remove it from the original `<input>`.\n      // If we did this in the post-link, AngularJS would have set up the observers already and would be\n      // re-adding the attribute, even though we removed it from the element.\n      pre: preLink\n    }\n  };\n\n  function preLink(scope, element, attr, inputContainer) {\n    // If there is no input container, just return\n    if (!inputContainer) return;\n\n    var label = inputContainer.element.find('label');\n    var noFloat = inputContainer.element.attr('md-no-float');\n\n    // If we have a label, or they specify the md-no-float attribute, just return\n    if ((label && label.length) || noFloat === '' || scope.$eval(noFloat)) {\n      // Add a placeholder class so we can target it in the CSS\n      inputContainer.setHasPlaceholder(true);\n      return;\n    }\n\n    // md-select handles placeholders on it's own\n    if (element[0].nodeName !== 'MD-SELECT') {\n      // Move the placeholder expression to the label\n      var newLabel = angular.element(\n        '<label ng-click=\"delegateClick()\" tabindex=\"-1\" aria-hidden=\"true\">' + attr.placeholder +\n        '</label>');\n\n      // Note that we unset it via `attr`, in order to get AngularJS\n      // to remove any observers that it might have set up. Otherwise\n      // the attribute will be added on the next digest.\n      attr.$set('placeholder', null);\n\n      // We need to compile the label manually in case it has any bindings.\n      // A gotcha here is that we first add the element to the DOM and we compile\n      // it later. This is necessary, because if we compile the element beforehand,\n      // it won't be able to find the `mdInputContainer` controller.\n      inputContainer.element\n        .addClass('md-icon-float')\n        .prepend(newLabel);\n\n      $compile(newLabel)(scope);\n    }\n  }\n}\n\n/**\n * @ngdoc directive\n * @name mdSelectOnFocus\n * @module material.components.input\n *\n * @restrict A\n *\n * @description\n * The `md-select-on-focus` directive allows you to automatically select the element's input text on focus.\n *\n * <h3>Notes</h3>\n * - The use of `md-select-on-focus` is restricted to `<input>` and `<textarea>` elements.\n *\n * @usage\n * <h3>Using with an Input</h3>\n * <hljs lang=\"html\">\n *\n * <md-input-container>\n *   <label>Auto Select</label>\n *   <input type=\"text\" md-select-on-focus>\n * </md-input-container>\n * </hljs>\n *\n * <h3>Using with a Textarea</h3>\n * <hljs lang=\"html\">\n *\n * <md-input-container>\n *   <label>Auto Select</label>\n *   <textarea md-select-on-focus>This text will be selected on focus.</textarea>\n * </md-input-container>\n *\n * </hljs>\n */\nfunction mdSelectOnFocusDirective($document, $timeout) {\n\n  return {\n    restrict: 'A',\n    link: postLink\n  };\n\n  function postLink(scope, element, attr) {\n    if (element[0].nodeName !== 'INPUT' && element[0].nodeName !== \"TEXTAREA\") return;\n\n    var preventMouseUp = false;\n\n    element\n      .on('focus', onFocus)\n      .on('mouseup', onMouseUp);\n\n    scope.$on('$destroy', function() {\n      element\n        .off('focus', onFocus)\n        .off('mouseup', onMouseUp);\n    });\n\n    function onFocus() {\n      preventMouseUp = true;\n\n      $timeout(function() {\n\n        // Use HTMLInputElement#select to fix firefox select issues.\n        // The debounce is here for Edge's sake, otherwise the selection doesn't work.\n        // Since focus may already have been lost on the input (and because `select()`\n        // will re-focus), make sure the element is still active before applying.\n        if ($document[0].activeElement === element[0]) {\n          element[0].select();\n        }\n\n        // This should be reset from inside the `focus`, because the event might\n        // have originated from something different than a click, e.g. a keyboard event.\n        preventMouseUp = false;\n      }, 1, false);\n    }\n\n    // Prevents the default action of the first `mouseup` after a focus.\n    // This is necessary, because browsers fire a `mouseup` right after the element\n    // has been focused. In some browsers (Firefox in particular) this can clear the\n    // selection. There are examples of the problem in issue #7487.\n    function onMouseUp(event) {\n      if (preventMouseUp) {\n        event.preventDefault();\n      }\n    }\n  }\n}\n\nvar visibilityDirectives = ['ngIf', 'ngShow', 'ngHide', 'ngSwitchWhen', 'ngSwitchDefault'];\nfunction ngMessagesDirective() {\n  return {\n    restrict: 'EA',\n    link: postLink,\n\n    // This is optional because we don't want target *all* ngMessage instances, just those inside of\n    // mdInputContainer.\n    require: '^^?mdInputContainer'\n  };\n\n  function postLink(scope, element, attrs, inputContainer) {\n    // If we are not a child of an input container, don't do anything\n    if (!inputContainer) return;\n\n    // Add our animation class\n    element.toggleClass('md-input-messages-animation', true);\n\n    // Add our md-auto-hide class to automatically hide/show messages when container is invalid\n    element.toggleClass('md-auto-hide', true);\n\n    // If we see some known visibility directives, remove the md-auto-hide class\n    if (attrs.mdAutoHide == 'false' || hasVisibiltyDirective(attrs)) {\n      element.toggleClass('md-auto-hide', false);\n    }\n  }\n\n  function hasVisibiltyDirective(attrs) {\n    return visibilityDirectives.some(function(attr) {\n      return attrs[attr];\n    });\n  }\n}\n\nfunction ngMessageDirective($mdUtil) {\n  return {\n    restrict: 'EA',\n    compile: compile,\n    priority: 100\n  };\n\n  function compile(tElement) {\n    if (!isInsideInputContainer(tElement)) {\n\n      // When the current element is inside of a document fragment, then we need to check for an input-container\n      // in the postLink, because the element will be later added to the DOM and is currently just in a temporary\n      // fragment, which causes the input-container check to fail.\n      if (isInsideFragment()) {\n        return function (scope, element) {\n          if (isInsideInputContainer(element)) {\n            // Inside of the postLink function, a ngMessage directive will be a comment element, because it's\n            // currently hidden. To access the shown element, we need to use the element from the compile function.\n            initMessageElement(tElement);\n          }\n        };\n      }\n    } else {\n      initMessageElement(tElement);\n    }\n\n    function isInsideFragment() {\n      var nextNode = tElement[0];\n      while (nextNode = nextNode.parentNode) {\n        if (nextNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    function isInsideInputContainer(element) {\n      return !!$mdUtil.getClosest(element, \"md-input-container\");\n    }\n\n    function initMessageElement(element) {\n      // Add our animation class\n      element.toggleClass('md-input-message-animation', true);\n    }\n  }\n}\n\nvar $$AnimateRunner, $animateCss, $mdUtil;\n\nfunction mdInputInvalidMessagesAnimation($$AnimateRunner, $animateCss, $mdUtil) {\n  saveSharedServices($$AnimateRunner, $animateCss, $mdUtil);\n\n  return {\n    addClass: function(element, className, done) {\n      showInputMessages(element, done);\n    }\n\n    // NOTE: We do not need the removeClass method, because the message ng-leave animation will fire\n  };\n}\n\nfunction ngMessagesAnimation($$AnimateRunner, $animateCss, $mdUtil) {\n  saveSharedServices($$AnimateRunner, $animateCss, $mdUtil);\n\n  return {\n    enter: function(element, done) {\n      showInputMessages(element, done);\n    },\n\n    leave: function(element, done) {\n      hideInputMessages(element, done);\n    },\n\n    addClass: function(element, className, done) {\n      if (className == \"ng-hide\") {\n        hideInputMessages(element, done);\n      } else {\n        done();\n      }\n    },\n\n    removeClass: function(element, className, done) {\n      if (className == \"ng-hide\") {\n        showInputMessages(element, done);\n      } else {\n        done();\n      }\n    }\n  };\n}\n\nfunction ngMessageAnimation($$AnimateRunner, $animateCss, $mdUtil, $log) {\n  saveSharedServices($$AnimateRunner, $animateCss, $mdUtil, $log);\n\n  return {\n    enter: function(element, done) {\n      var animator = showMessage(element);\n\n      animator.start().done(done);\n    },\n\n    leave: function(element, done) {\n      var animator = hideMessage(element);\n\n      animator.start().done(done);\n    }\n  };\n}\n\nfunction showInputMessages(element, done) {\n  var animators = [], animator;\n  var messages = getMessagesElement(element);\n  var children = messages.children();\n\n  if (messages.length == 0 || children.length == 0) {\n    done();\n    return;\n  }\n\n  angular.forEach(children, function(child) {\n    animator = showMessage(angular.element(child));\n\n    animators.push(animator.start());\n  });\n\n  $$AnimateRunner.all(animators, done);\n}\n\nfunction hideInputMessages(element, done) {\n  var animators = [], animator;\n  var messages = getMessagesElement(element);\n  var children = messages.children();\n\n  if (messages.length == 0 || children.length == 0) {\n    done();\n    return;\n  }\n\n  angular.forEach(children, function(child) {\n    animator = hideMessage(angular.element(child));\n\n    animators.push(animator.start());\n  });\n\n  $$AnimateRunner.all(animators, done);\n}\n\nfunction showMessage(element) {\n  var height = parseInt(window.getComputedStyle(element[0]).height);\n  var topMargin = parseInt(window.getComputedStyle(element[0]).marginTop);\n\n  var messages = getMessagesElement(element);\n  var container = getInputElement(element);\n\n  // Check to see if the message is already visible so we can skip\n  var alreadyVisible = (topMargin > -height);\n\n  // If we have the md-auto-hide class, the md-input-invalid animation will fire, so we can skip\n  if (alreadyVisible || (messages.hasClass('md-auto-hide') && !container.hasClass('md-input-invalid'))) {\n    return $animateCss(element, {});\n  }\n\n  return $animateCss(element, {\n    event: 'enter',\n    structural: true,\n    from: {\"opacity\": 0, \"margin-top\": -height + \"px\"},\n    to: {\"opacity\": 1, \"margin-top\": \"0\"},\n    duration: 0.3\n  });\n}\n\nfunction hideMessage(element) {\n  var height = element[0].offsetHeight;\n  var styles = window.getComputedStyle(element[0]);\n\n  // If we are already hidden, just return an empty animation\n  if (parseInt(styles.opacity) === 0) {\n    return $animateCss(element, {});\n  }\n\n  // Otherwise, animate\n  return $animateCss(element, {\n    event: 'leave',\n    structural: true,\n    from: {\"opacity\": 1, \"margin-top\": 0},\n    to: {\"opacity\": 0, \"margin-top\": -height + \"px\"},\n    duration: 0.3\n  });\n}\n\nfunction getInputElement(element) {\n  var inputContainer = element.controller('mdInputContainer');\n\n  return inputContainer.element;\n}\n\nfunction getMessagesElement(element) {\n  // If we ARE the messages element, just return ourself\n  if (element.hasClass('md-input-messages-animation')) {\n    return element;\n  }\n\n  // If we are a ng-message element, we need to traverse up the DOM tree\n  if (element.hasClass('md-input-message-animation')) {\n    return angular.element($mdUtil.getClosest(element, function(node) {\n      return node.classList.contains('md-input-messages-animation');\n    }));\n  }\n\n  // Otherwise, we can traverse down\n  return angular.element(element[0].querySelector('.md-input-messages-animation'));\n}\n\nfunction saveSharedServices(_$$AnimateRunner_, _$animateCss_, _$mdUtil_) {\n  $$AnimateRunner = _$$AnimateRunner_;\n  $animateCss = _$animateCss_;\n  $mdUtil = _$mdUtil_;\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.list\n * @description\n * List module\n */\nMdListController.$inject = [\"$scope\", \"$element\", \"$mdListInkRipple\"];\nmdListDirective.$inject = [\"$mdTheming\"];\nmdListItemDirective.$inject = [\"$mdAria\", \"$mdConstant\", \"$mdUtil\", \"$timeout\"];\nangular.module('material.components.list', [\n  'material.core'\n])\n  .controller('MdListController', MdListController)\n  .directive('mdList', mdListDirective)\n  .directive('mdListItem', mdListItemDirective);\n\n/**\n * @ngdoc directive\n * @name mdList\n * @module material.components.list\n *\n * @restrict E\n *\n * @description\n * The `<md-list>` directive is a list container for 1..n `<md-list-item>` tags.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-list>\n *   <md-list-item class=\"md-2-line\" ng-repeat=\"item in todos\">\n *     <md-checkbox ng-model=\"item.done\"></md-checkbox>\n *     <div class=\"md-list-item-text\">\n *       <h3>{{item.title}}</h3>\n *       <p>{{item.description}}</p>\n *     </div>\n *   </md-list-item>\n * </md-list>\n * </hljs>\n */\n\nfunction mdListDirective($mdTheming) {\n  return {\n    restrict: 'E',\n    compile: function(tEl) {\n      tEl[0].setAttribute('role', 'list');\n      return $mdTheming;\n    }\n  };\n}\n/**\n * @ngdoc directive\n * @name mdListItem\n * @module material.components.list\n *\n * @restrict E\n *\n * @description\n * A `md-list-item` element can be used to represent some information in a row.<br/>\n *\n * @usage\n * ### Single Row Item\n * <hljs lang=\"html\">\n *   <md-list-item>\n *     <span>Single Row Item</span>\n *   </md-list-item>\n * </hljs>\n *\n * ### Multiple Lines\n * By using the following markup, you will be able to have two lines inside of one `md-list-item`.\n *\n * <hljs lang=\"html\">\n *   <md-list-item class=\"md-2-line\">\n *     <div class=\"md-list-item-text\" layout=\"column\">\n *       <p>First Line</p>\n *       <p>Second Line</p>\n *     </div>\n *   </md-list-item>\n * </hljs>\n *\n * It is also possible to have three lines inside of one list item.\n *\n * <hljs lang=\"html\">\n *   <md-list-item class=\"md-3-line\">\n *     <div class=\"md-list-item-text\" layout=\"column\">\n *       <p>First Line</p>\n *       <p>Second Line</p>\n *       <p>Third Line</p>\n *     </div>\n *   </md-list-item>\n * </hljs>\n *\n * ### Secondary Items\n * Secondary items are elements which will be aligned at the end of the `md-list-item`.\n *\n * <hljs lang=\"html\">\n *   <md-list-item>\n *     <span>Single Row Item</span>\n *     <md-button class=\"md-secondary\">\n *       Secondary Button\n *     </md-button>\n *   </md-list-item>\n * </hljs>\n *\n * It also possible to have multiple secondary items inside of one `md-list-item`.\n *\n * <hljs lang=\"html\">\n *   <md-list-item>\n *     <span>Single Row Item</span>\n *     <md-button class=\"md-secondary\">First Button</md-button>\n *     <md-button class=\"md-secondary\">Second Button</md-button>\n *   </md-list-item>\n * </hljs>\n *\n * ### Proxy Item\n * Proxies are elements, which will execute their specific action on click<br/>\n * Currently supported proxy items are\n * - `md-checkbox` (Toggle)\n * - `md-switch` (Toggle)\n * - `md-menu` (Open)\n *\n * This means, when using a supported proxy item inside of `md-list-item`, the list item will\n * automatically become clickable and executes the associated action of the proxy element on click.\n *\n * It is possible to disable this behavior by applying the `md-no-proxy` class to the list item.\n *\n * <hljs lang=\"html\">\n *   <md-list-item class=\"md-no-proxy\">\n *     <span>No Proxy List</span>\n *     <md-checkbox class=\"md-secondary\"></md-checkbox>\n *   </md-list-item>\n * </hljs>\n *\n * Here are a few examples of proxy elements inside of a list item.\n *\n * <hljs lang=\"html\">\n *   <md-list-item>\n *     <span>First Line</span>\n *     <md-checkbox class=\"md-secondary\"></md-checkbox>\n *   </md-list-item>\n * </hljs>\n *\n * The `md-checkbox` element will be automatically detected as a proxy element and will toggle on\n * click.\n *\n * If not provided, an `aria-label` will be applied using the text of the list item.\n * In this case, the following will be applied to the `md-checkbox`:\n * `aria-label=\"Toggle First Line\"`.\n * When localizing your application, you should supply a localized `aria-label`.\n *\n * <hljs lang=\"html\">\n *   <md-list-item>\n *     <span>First Line</span>\n *     <md-switch class=\"md-secondary\"></md-switch>\n *   </md-list-item>\n * </hljs>\n *\n * The recognized `md-switch` will toggle its state, when the user clicks on the `md-list-item`.\n *\n * It is also possible to have a `md-menu` inside of a `md-list-item`.\n *\n * <hljs lang=\"html\">\n *   <md-list-item>\n *     <p>Click anywhere to fire the secondary action</p>\n *     <md-menu class=\"md-secondary\">\n *       <md-button class=\"md-icon-button\">\n *         <md-icon md-svg-icon=\"communication:message\"></md-icon>\n *       </md-button>\n *       <md-menu-content width=\"4\">\n *         <md-menu-item>\n *           <md-button>\n *             Redial\n *           </md-button>\n *         </md-menu-item>\n *         <md-menu-item>\n *           <md-button>\n *             Check voicemail\n *           </md-button>\n *         </md-menu-item>\n *         <md-menu-divider></md-menu-divider>\n *         <md-menu-item>\n *           <md-button>\n *             Notifications\n *           </md-button>\n *         </md-menu-item>\n *       </md-menu-content>\n *     </md-menu>\n *   </md-list-item>\n * </hljs>\n *\n * The menu will automatically open, when the users clicks on the `md-list-item`.<br/>\n *\n * If the developer didn't specify any position mode on the menu, the `md-list-item` will\n * automatically detect the position mode and apply it to the `md-menu`.\n *\n * ### Avatars\n * Sometimes you may want to have avatars inside of the `md-list-item `.<br/>\n * You are able to create an optimized icon for the list item, by applying the `.md-avatar` class on\n * the `<img>` element.\n *\n * <hljs lang=\"html\">\n *   <md-list-item>\n *     <img src=\"my-avatar.png\" class=\"md-avatar\">\n *     <span>Alan Turing</span>\n * </hljs>\n *\n * When using `<md-icon>` for an avatar, you have to use the `.md-avatar-icon` class.\n *\n * <hljs lang=\"html\">\n *   <md-list-item>\n *     <md-icon class=\"md-avatar-icon\" md-svg-icon=\"social:person\"></md-icon>\n *     <span>Timothy Kopra</span>\n *   </md-list-item>\n * </hljs>\n *\n * In cases where you have a `md-list-item`, which doesn't have an avatar,\n * but you want to align it with the other avatar items, you need to use the `.md-offset` class.\n *\n * <hljs lang=\"html\">\n *   <md-list-item class=\"md-offset\">\n *     <span>Jon Doe</span>\n *   </md-list-item>\n * </hljs>\n *\n * ### DOM modification\n * The `md-list-item` component automatically detects if the list item should be clickable.\n *\n * ---\n * If the `md-list-item` is clickable, we wrap all content inside of a `<div>` and create\n * an overlaying button, which will will execute the given actions (like `ng-href`, `ng-click`).\n *\n * We create an overlaying button, instead of wrapping all content inside of the button,\n * because otherwise some elements may not be clickable inside of the button.\n *\n * ---\n * When using a secondary item inside of your list item, the `md-list-item` component will\n * automatically create a secondary container at the end of the `md-list-item`, which contains all\n * secondary items.\n *\n * The secondary item container is not static, because that would cause issues with the overflow\n * of the list item.\n */\nfunction mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {\n  var proxiedTypes = ['md-checkbox', 'md-switch', 'md-menu'];\n  return {\n    restrict: 'E',\n    controller: 'MdListController',\n\n    compile: function(tElement, tAttrs) {\n\n      // Check for proxy controls (no ng-click on parent, and a control inside)\n      var secondaryItems = tElement[0].querySelectorAll('.md-secondary');\n      var hasProxiedElement;\n      var proxyElement;\n      var itemContainer = tElement;\n\n      tElement[0].setAttribute('role', 'listitem');\n\n      if (tAttrs.ngClick || tAttrs.ngDblclick ||  tAttrs.ngHref || tAttrs.href || tAttrs.uiSref || tAttrs.ngAttrUiSref) {\n        wrapIn('button');\n      } else if (!tElement.hasClass('md-no-proxy')) {\n\n        for (var i = 0, type; i < proxiedTypes.length; ++i) {\n          proxyElement = tElement[0].querySelector(proxiedTypes[i]);\n          if (proxyElement !== null) {\n            hasProxiedElement = true;\n            break;\n          }\n        }\n\n        if (hasProxiedElement) {\n          wrapIn('div');\n        } else {\n          tElement.addClass('md-no-proxy');\n        }\n      }\n\n      wrapSecondaryItems();\n      setupToggleAria();\n\n      if (hasProxiedElement && proxyElement.nodeName === \"MD-MENU\") {\n        setupProxiedMenu();\n      }\n\n      function setupToggleAria() {\n        var toggleTypes = ['md-switch', 'md-checkbox'];\n        var toggle;\n\n        for (var i = 0, toggleType; i < toggleTypes.length; ++i) {\n          toggle = tElement.find(toggleTypes[i])[0];\n          if (toggle) {\n            if (!toggle.hasAttribute('aria-label')) {\n              var labelElement = tElement.find('p')[0];\n              if (!labelElement) {\n                labelElement = tElement.find('span')[0];\n              }\n              if (!labelElement) return;\n              toggle.setAttribute('aria-label', 'Toggle ' + labelElement.textContent);\n            }\n          }\n        }\n      }\n\n      function setupProxiedMenu() {\n        var menuEl = angular.element(proxyElement);\n\n        var isEndAligned = menuEl.parent().hasClass('md-secondary-container') ||\n                           proxyElement.parentNode.firstElementChild !== proxyElement;\n\n        var xAxisPosition = 'left';\n\n        if (isEndAligned) {\n          // When the proxy item is aligned at the end of the list, we have to set the origin to the end.\n          xAxisPosition = 'right';\n        }\n\n        // Set the position mode / origin of the proxied menu.\n        if (!menuEl.attr('md-position-mode')) {\n          menuEl.attr('md-position-mode', xAxisPosition + ' target');\n        }\n\n        // Apply menu open binding to menu button\n        var menuOpenButton = menuEl.children().eq(0);\n        if (!hasClickEvent(menuOpenButton[0])) {\n          menuOpenButton.attr('ng-click', '$mdMenu.open($event)');\n        }\n\n        if (!menuOpenButton.attr('aria-label')) {\n          menuOpenButton.attr('aria-label', 'Open List Menu');\n        }\n      }\n\n      /**\n       * @param {'div'|'button'} type\n       */\n      function wrapIn(type) {\n        if (type === 'div') {\n          itemContainer = angular.element('<div class=\"md-no-style md-list-item-inner\">');\n          itemContainer.append(tElement.contents());\n          tElement.addClass('md-proxy-focus');\n        } else {\n          // Element which holds the default list-item content.\n          itemContainer = angular.element(\n            '<div class=\"md-button md-no-style\">' +\n            '   <div class=\"md-list-item-inner\"></div>' +\n            '</div>'\n          );\n\n          // Button which shows ripple and executes primary action.\n          var buttonWrap = angular.element('<md-button class=\"md-no-style\"></md-button>');\n\n          moveAttributes(tElement[0], buttonWrap[0]);\n\n          // If there is no aria-label set on the button (previously copied over if present)\n          // we determine the label from the content and copy it to the button.\n          if (!buttonWrap.attr('aria-label')) {\n            buttonWrap.attr('aria-label', $mdAria.getText(tElement));\n\n            // If we set the button's aria-label to the text content, then make the content hidden\n            // from screen readers so that it isn't read/traversed twice.\n            var listItemInner = itemContainer[0].querySelector('.md-list-item-inner');\n            if (listItemInner) {\n              listItemInner.setAttribute('aria-hidden', 'true');\n            }\n          }\n\n          // We allow developers to specify the `md-no-focus` class, to disable the focus style\n          // on the button executor. Once more classes should be forwarded, we should probably make\n          // the class forward more generic.\n          if (tElement.hasClass('md-no-focus')) {\n            buttonWrap.addClass('md-no-focus');\n          }\n\n          // Append the button wrap before our list-item content, because it will overlay in\n          // relative.\n          itemContainer.prepend(buttonWrap);\n          itemContainer.children().eq(1).append(tElement.contents());\n\n          tElement.addClass('_md-button-wrap');\n        }\n\n        tElement[0].setAttribute('tabindex', '-1');\n        tElement.append(itemContainer);\n      }\n\n      function wrapSecondaryItems() {\n        var secondaryItemsWrapper = angular.element('<div class=\"md-secondary-container\">');\n\n        angular.forEach(secondaryItems, function(secondaryItem) {\n          wrapSecondaryItem(secondaryItem, secondaryItemsWrapper);\n        });\n\n        itemContainer.append(secondaryItemsWrapper);\n      }\n\n      /**\n       * @param {HTMLElement} secondaryItem\n       * @param {HTMLDivElement} container\n       */\n      function wrapSecondaryItem(secondaryItem, container) {\n        // If the current secondary item is not a button, but contains a ng-click attribute,\n        // the secondary item will be automatically wrapped inside of a button.\n        if (secondaryItem && !isButton(secondaryItem) && secondaryItem.hasAttribute('ng-click')) {\n\n          $mdAria.expect(secondaryItem, 'aria-label');\n          var buttonWrapper = angular.element('<md-button class=\"md-secondary md-icon-button\">');\n\n          // Move the attributes from the secondary item to the generated button.\n          // We also support some additional attributes from the secondary item,\n          // because some developers may use a ngIf, ngHide, ngShow on their item.\n          moveAttributes(secondaryItem, buttonWrapper[0], ['ng-if', 'ng-hide', 'ng-show']);\n\n          secondaryItem.setAttribute('tabindex', '-1');\n          buttonWrapper.append(secondaryItem);\n\n          secondaryItem = buttonWrapper[0];\n        }\n\n        if (secondaryItem &&\n            (!hasClickEvent(secondaryItem) ||\n              (!tAttrs.ngClick && isProxiedElement(secondaryItem)))) {\n          // In this case we remove the secondary class, so we can identify it later, when searching\n          // for the proxy items.\n          angular.element(secondaryItem).removeClass('md-secondary');\n        }\n\n        tElement.addClass('md-with-secondary');\n        container.append(secondaryItem);\n      }\n\n      /**\n       * Moves attributes from a source element to the destination element.\n       * By default, the function will copy the most necessary attributes, supported\n       * by the button executor for clickable list items.\n       * @param {Element} source Element with the specified attributes\n       * @param {Element} destination Element which will receive the attributes\n       * @param {string|string[]} extraAttrs Additional attributes, which will be moved over\n       */\n      function moveAttributes(source, destination, extraAttrs) {\n        var copiedAttrs = $mdUtil.prefixer([\n          'ng-if', 'ng-click', 'ng-dblclick', 'aria-label', 'ng-disabled', 'ui-sref',\n          'href', 'ng-href', 'rel', 'target', 'ng-attr-ui-sref', 'ui-sref-opts', 'download'\n        ]);\n\n        if (extraAttrs) {\n          copiedAttrs = copiedAttrs.concat($mdUtil.prefixer(extraAttrs));\n        }\n\n        angular.forEach(copiedAttrs, function(attr) {\n          if (source.hasAttribute(attr)) {\n            destination.setAttribute(attr, source.getAttribute(attr));\n            source.removeAttribute(attr);\n          }\n        });\n      }\n\n      /**\n       * @param {HTMLElement} element\n       * @return {boolean} true if the element has one of the proxied tags, false otherwise\n       */\n      function isProxiedElement(element) {\n        return proxiedTypes.indexOf(element.nodeName.toLowerCase()) !== -1;\n      }\n\n      /**\n       * @param {HTMLElement} element\n       * @return {boolean} true if the element is a button or md-button, false otherwise\n       */\n      function isButton(element) {\n        var nodeName = element.nodeName.toUpperCase();\n\n        return nodeName === \"MD-BUTTON\" || nodeName === \"BUTTON\";\n      }\n\n      /**\n       * @param {Element} element\n       * @return {boolean} true if the element has an ng-click attribute, false otherwise\n       */\n      function hasClickEvent(element) {\n        var attr = element.attributes;\n        for (var i = 0; i < attr.length; i++) {\n          if (tAttrs.$normalize(attr[i].name) === 'ngClick') {\n            return true;\n          }\n        }\n        return false;\n      }\n\n      return postLink;\n\n      function postLink($scope, $element, $attr, ctrl) {\n        $element.addClass('_md');     // private md component indicator for styling\n\n        var proxies       = [],\n            firstElement  = $element[0].firstElementChild,\n            isButtonWrap  = $element.hasClass('_md-button-wrap'),\n            clickChild    = isButtonWrap ? firstElement.firstElementChild : firstElement,\n            hasClick      = clickChild && hasClickEvent(clickChild),\n            noProxies     = $element.hasClass('md-no-proxy');\n\n        computeProxies();\n        computeClickable();\n\n        if (proxies.length) {\n          angular.forEach(proxies, function(proxy) {\n            proxy = angular.element(proxy);\n\n            $scope.mouseActive = false;\n            proxy.on('mousedown', function() {\n              $scope.mouseActive = true;\n              $timeout(function() {\n                $scope.mouseActive = false;\n              }, 100);\n            })\n            .on('focus', function() {\n              if ($scope.mouseActive === false) { $element.addClass('md-focused'); }\n              proxy.on('blur', function proxyOnBlur() {\n                $element.removeClass('md-focused');\n                proxy.off('blur', proxyOnBlur);\n              });\n            });\n          });\n        }\n\n        function computeProxies() {\n          if (firstElement && firstElement.children && !hasClick && !noProxies) {\n\n            angular.forEach(proxiedTypes, function(type) {\n              // All elements which are not capable of being used as a proxy have the .md-secondary\n              // class applied. These items were identified in the secondary wrap function.\n              angular.forEach(firstElement.querySelectorAll(type + ':not(.md-secondary)'), function(child) {\n                proxies.push(child);\n              });\n            });\n          }\n        }\n\n        function computeClickable() {\n          if (proxies.length === 1 || hasClick) {\n            $element.addClass('md-clickable');\n\n            if (!hasClick) {\n              ctrl.attachRipple($scope, angular.element($element[0].querySelector('.md-no-style')));\n            }\n          }\n        }\n\n        /**\n         * @param {MouseEvent} event\n         * @return {boolean}\n         */\n        function isEventFromControl(event) {\n          var forbiddenControls = ['md-slider'];\n          var eventBubblePath = $mdUtil.getEventPath(event);\n\n          // If there is no bubble path, then the event was not bubbled.\n          if (!eventBubblePath || eventBubblePath.length === 0) {\n            return forbiddenControls.indexOf(event.target.tagName.toLowerCase()) !== -1;\n          }\n\n          // We iterate the event bubble path up and check for a possible component.\n          // Our maximum index to search, is the list item root.\n          var maxPath = eventBubblePath.indexOf($element.children()[0]);\n\n          for (var i = 0; i < maxPath; i++) {\n            if (forbiddenControls.indexOf(eventBubblePath[i].tagName.toLowerCase()) !== -1) {\n              return true;\n            }\n          }\n          return false;\n        }\n\n        /**\n         * @param {KeyboardEvent} keypressEvent\n         */\n        var clickChildKeypressListener = function(keypressEvent) {\n          if (keypressEvent.target.nodeName !== 'INPUT' &&\n              keypressEvent.target.nodeName !== 'TEXTAREA' &&\n              !keypressEvent.target.isContentEditable) {\n            var keyCode = keypressEvent.which || keypressEvent.keyCode;\n            if (keyCode === $mdConstant.KEY_CODE.SPACE) {\n              if (clickChild) {\n                clickChild.click();\n                keypressEvent.preventDefault();\n                keypressEvent.stopPropagation();\n              }\n            }\n          }\n        };\n\n        if (!hasClick && !proxies.length) {\n          clickChild && clickChild.addEventListener('keypress', clickChildKeypressListener);\n        }\n\n        $element.off('click');\n        $element.off('keypress');\n        // Disable ng-aria's \"helpful\" keydown event that causes our ng-click handlers to be called\n        // twice.\n        $element.off('keydown');\n\n        if (proxies.length === 1 && clickChild) {\n          $element.children().eq(0).on('click', function(clickEvent) {\n            // When the event is coming from a control and it should not trigger the proxied element\n            // then we are skipping.\n            if (isEventFromControl(clickEvent)) return;\n\n            var parentButton = $mdUtil.getClosest(clickEvent.target, 'BUTTON');\n            if (!parentButton && clickChild.contains(clickEvent.target)) {\n              angular.forEach(proxies, function(proxy) {\n                if (clickEvent.target !== proxy && !proxy.contains(clickEvent.target)) {\n                  if (proxy.nodeName === 'MD-MENU') {\n                    proxy = proxy.children[0];\n                  }\n                  angular.element(proxy).triggerHandler('click');\n                }\n              });\n            }\n          });\n        }\n\n        $scope.$on('$destroy', function () {\n          clickChild && clickChild.removeEventListener('keypress', clickChildKeypressListener);\n        });\n      }\n    }\n  };\n}\n\n/*\n * @private\n * @ngdoc controller\n * @name MdListController\n * @module material.components.list\n */\nfunction MdListController($scope, $element, $mdListInkRipple) {\n  var ctrl = this;\n  ctrl.attachRipple = attachRipple;\n\n  function attachRipple (scope, element) {\n    var options = {};\n    $mdListInkRipple.attach(scope, element, options);\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.menu\n */\n\nangular.module('material.components.menu', [\n  'material.core',\n  'material.components.backdrop'\n]);\n\n})();\n(function(){\n\"use strict\";\n\n\n\nMenuController.$inject = [\"$mdMenu\", \"$attrs\", \"$element\", \"$scope\", \"$mdUtil\", \"$timeout\", \"$rootScope\", \"$q\", \"$log\"];\nangular\n    .module('material.components.menu')\n    .controller('mdMenuCtrl', MenuController);\n\n/**\n * @ngInject\n */\nfunction MenuController($mdMenu, $attrs, $element, $scope, $mdUtil, $timeout, $rootScope, $q, $log) {\n\n  var prefixer = $mdUtil.prefixer();\n  var menuContainer;\n  var self = this;\n  var triggerElement;\n\n  this.nestLevel = parseInt($attrs.mdNestLevel, 10) || 0;\n\n  /**\n   * Called by our linking fn to provide access to the menu-content\n   * element removed during link\n   */\n  this.init = function init(setMenuContainer, opts) {\n    opts = opts || {};\n    menuContainer = setMenuContainer;\n\n    // Default element for ARIA attributes has the ngClick or ngMouseenter expression\n    triggerElement = $element[0].querySelector(prefixer.buildSelector(['ng-click', 'ng-mouseenter']));\n    triggerElement.setAttribute('aria-expanded', 'false');\n\n    this.isInMenuBar = opts.isInMenuBar;\n    this.mdMenuBarCtrl = opts.mdMenuBarCtrl;\n    this.nestedMenus = $mdUtil.nodesToArray(menuContainer[0].querySelectorAll('.md-nested-menu'));\n\n    menuContainer.on('$mdInterimElementRemove', function() {\n      self.isOpen = false;\n      $mdUtil.nextTick(function(){ self.onIsOpenChanged(self.isOpen);});\n    });\n    $mdUtil.nextTick(function(){ self.onIsOpenChanged(self.isOpen);});\n\n    var menuContainerId = 'menu_container_' + $mdUtil.nextUid();\n    menuContainer.attr('id', menuContainerId);\n    angular.element(triggerElement).attr({\n      'aria-owns': menuContainerId,\n      'aria-haspopup': 'true'\n    });\n\n    $scope.$on('$destroy', angular.bind(this, function() {\n      this.disableHoverListener();\n      $mdMenu.destroy();\n    }));\n\n    menuContainer.on('$destroy', function() {\n      $mdMenu.destroy();\n    });\n  };\n\n  var openMenuTimeout, menuItems, deregisterScopeListeners = [];\n  this.enableHoverListener = function() {\n    deregisterScopeListeners.push($rootScope.$on('$mdMenuOpen', function(event, el) {\n      if (menuContainer[0].contains(el[0])) {\n        self.currentlyOpenMenu = el.controller('mdMenu');\n        self.isAlreadyOpening = false;\n        self.currentlyOpenMenu.registerContainerProxy(self.triggerContainerProxy.bind(self));\n      }\n    }));\n    deregisterScopeListeners.push($rootScope.$on('$mdMenuClose', function(event, el) {\n      if (menuContainer[0].contains(el[0])) {\n        self.currentlyOpenMenu = undefined;\n      }\n    }));\n    menuItems = angular.element($mdUtil.nodesToArray(menuContainer[0].children[0].children));\n    menuItems.on('mouseenter', self.handleMenuItemHover);\n    menuItems.on('mouseleave', self.handleMenuItemMouseLeave);\n  };\n\n  this.disableHoverListener = function() {\n    while (deregisterScopeListeners.length) {\n      deregisterScopeListeners.shift()();\n    }\n    menuItems && menuItems.off('mouseenter', self.handleMenuItemHover);\n    menuItems && menuItems.off('mouseleave', self.handleMenuItemMouseLeave);\n  };\n\n  this.handleMenuItemHover = function(event) {\n    if (self.isAlreadyOpening) return;\n    var nestedMenu = (\n      event.target.querySelector('md-menu')\n        || $mdUtil.getClosest(event.target, 'MD-MENU')\n    );\n    openMenuTimeout = $timeout(function() {\n      if (nestedMenu) {\n        nestedMenu = angular.element(nestedMenu).controller('mdMenu');\n      }\n\n      if (self.currentlyOpenMenu && self.currentlyOpenMenu != nestedMenu) {\n        var closeTo = self.nestLevel + 1;\n        self.currentlyOpenMenu.close(true, { closeTo: closeTo });\n        self.isAlreadyOpening = !!nestedMenu;\n        nestedMenu && nestedMenu.open();\n      } else if (nestedMenu && !nestedMenu.isOpen && nestedMenu.open) {\n        self.isAlreadyOpening = !!nestedMenu;\n        nestedMenu && nestedMenu.open();\n      }\n    }, nestedMenu ? 100 : 250);\n    var focusableTarget = event.currentTarget.querySelector('.md-button:not([disabled])');\n    focusableTarget && focusableTarget.focus();\n  };\n\n  this.handleMenuItemMouseLeave = function() {\n    if (openMenuTimeout) {\n      $timeout.cancel(openMenuTimeout);\n      openMenuTimeout = undefined;\n    }\n  };\n\n\n  /**\n   * Uses the $mdMenu interim element service to open the menu contents\n   */\n  this.open = function openMenu(ev) {\n    ev && ev.stopPropagation();\n    ev && ev.preventDefault();\n    if (self.isOpen) return;\n    self.enableHoverListener();\n    self.isOpen = true;\n    $mdUtil.nextTick(function(){ self.onIsOpenChanged(self.isOpen);});\n    triggerElement = triggerElement || (ev ? ev.target : $element[0]);\n    triggerElement.setAttribute('aria-expanded', 'true');\n    $scope.$emit('$mdMenuOpen', $element);\n    $mdMenu.show({\n      scope: $scope,\n      mdMenuCtrl: self,\n      nestLevel: self.nestLevel,\n      element: menuContainer,\n      target: triggerElement,\n      preserveElement: true,\n      parent: 'body'\n    }).finally(function() {\n      triggerElement.setAttribute('aria-expanded', 'false');\n      self.disableHoverListener();\n    });\n  };\n\n  this.onIsOpenChanged = function(isOpen) {\n    if (isOpen) {\n      menuContainer.attr('aria-hidden', 'false');\n      $element[0].classList.add('md-open');\n      angular.forEach(self.nestedMenus, function(el) {\n        el.classList.remove('md-open');\n      });\n    } else {\n      menuContainer.attr('aria-hidden', 'true');\n      $element[0].classList.remove('md-open');\n    }\n    $scope.$mdMenuIsOpen = self.isOpen;\n  };\n\n  this.focusMenuContainer = function focusMenuContainer() {\n    var focusTarget = menuContainer[0]\n      .querySelector(prefixer.buildSelector(['md-menu-focus-target', 'md-autofocus']));\n\n    if (!focusTarget) focusTarget = menuContainer[0].querySelector('.md-button:not([disabled])');\n    focusTarget.focus();\n  };\n\n  this.registerContainerProxy = function registerContainerProxy(handler) {\n    this.containerProxy = handler;\n  };\n\n  this.triggerContainerProxy = function triggerContainerProxy(ev) {\n    this.containerProxy && this.containerProxy(ev);\n  };\n\n  this.destroy = function() {\n    return self.isOpen ? $mdMenu.destroy() : $q.when(false);\n  };\n\n  // Use the $mdMenu interim element service to close the menu contents\n  this.close = function closeMenu(skipFocus, closeOpts) {\n    if (!self.isOpen) return;\n    self.isOpen = false;\n    $mdUtil.nextTick(function(){ self.onIsOpenChanged(self.isOpen);});\n\n    var eventDetails = angular.extend({}, closeOpts, { skipFocus: skipFocus });\n    $scope.$emit('$mdMenuClose', $element, eventDetails);\n    $mdMenu.hide(null, closeOpts);\n\n    if (!skipFocus) {\n      var el = self.restoreFocusTo || $element.find('button')[0];\n      if (el instanceof angular.element) el = el[0];\n      if (el) el.focus();\n    }\n  };\n\n  /**\n   * Build a nice object out of our string attribute which specifies the\n   * target mode for left and top positioning\n   */\n  this.positionMode = function positionMode() {\n    var attachment = ($attrs.mdPositionMode || 'target').split(' ');\n\n    // If attachment is a single item, duplicate it for our second value.\n    // ie. 'target' -> 'target target'\n    if (attachment.length === 1) {\n      attachment.push(attachment[0]);\n    }\n\n    return {\n      left: attachment[0],\n      top: attachment[1]\n    };\n  };\n\n  /**\n   * Build a nice object out of our string attribute which specifies\n   * the offset of top and left in pixels.\n   */\n  this.offsets = function offsets() {\n    var position = ($attrs.mdOffset || '0 0').split(' ').map(parseFloat);\n    if (position.length === 2) {\n      return {\n        left: position[0],\n        top: position[1]\n      };\n    } else if (position.length === 1) {\n      return {\n        top: position[0],\n        left: position[0]\n      };\n    } else {\n      throw Error('Invalid offsets specified. Please follow format <x, y> or <n>');\n    }\n  };\n\n  // Functionality that is exposed in the view.\n  $scope.$mdMenu = {\n    open: this.open,\n    close: this.close\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc directive\n * @name mdMenu\n * @module material.components.menu\n * @restrict E\n * @description\n *\n * Menus are elements that open when clicked. They are useful for displaying\n * additional options within the context of an action.\n *\n * Every `md-menu` must specify exactly two child elements. The first element is what is\n * left in the DOM and is used to open the menu. This element is called the trigger element.\n * The trigger element's scope has access to `$mdMenu.open($event)`\n * which it may call to open the menu. By passing $event as argument, the\n * corresponding event is stopped from propagating up the DOM-tree. Similarly, `$mdMenu.close()`\n * can be used to close the menu.\n *\n * The second element is the `md-menu-content` element which represents the\n * contents of the menu when it is open. Typically this will contain `md-menu-item`s,\n * but you can do custom content as well.\n *\n * <hljs lang=\"html\">\n * <md-menu>\n *  <!-- Trigger element is a md-button with an icon -->\n *  <md-button ng-click=\"$mdMenu.open($event)\" class=\"md-icon-button\" aria-label=\"Open sample menu\">\n *    <md-icon md-svg-icon=\"call:phone\"></md-icon>\n *  </md-button>\n *  <md-menu-content>\n *    <md-menu-item><md-button ng-click=\"doSomething()\">Do Something</md-button></md-menu-item>\n *  </md-menu-content>\n * </md-menu>\n * </hljs>\n\n * ## Sizing Menus\n *\n * The width of the menu when it is open may be specified by specifying a `width`\n * attribute on the `md-menu-content` element.\n * See the [Material Design Spec](https://material.io/archive/guidelines/components/menus.html#menus-simple-menus)\n * for more information.\n *\n * ## Menu Density\n *\n * You can use dense menus by adding the `md-dense` class to the `md-menu-content` element.\n * This reduces the height of menu items, their top and bottom padding, and default font size.\n * Without the `md-dense` class, we use the \"mobile\" height of `48px`. With the `md-dense` class,\n * we use the \"desktop\" height of `32px`. We do not support the \"dense desktop\" option in the spec,\n * which uses a height of `24px`, at this time.\n * See the [Menu Specs](https://material.io/archive/guidelines/components/menus.html#menus-specs)\n * section of the Material Design Spec for more information.\n *\n * ## Aligning Menus\n *\n * When a menu opens, it is important that the content aligns with the trigger element.\n * Failure to align menus can result in jarring experiences for users as content\n * suddenly shifts. To help with this, `md-menu` provides several APIs to help\n * with alignment.\n *\n * ### Target Mode\n *\n * By default, `md-menu` will attempt to align the `md-menu-content` by aligning\n * designated child elements in both the trigger and the menu content.\n *\n * To specify the alignment element in the `trigger` you can use the `md-menu-origin`\n * attribute on a child element. If no `md-menu-origin` is specified, the `md-menu`\n * will be used as the origin element.\n *\n * Similarly, the `md-menu-content` may specify a `md-menu-align-target` for a\n * `md-menu-item` to specify the node that it should try and align with.\n *\n * In this example code, we specify an icon to be our origin element, and an\n * icon in our menu content to be our alignment target. This ensures that both\n * icons are aligned when the menu opens.\n *\n * <hljs lang=\"html\">\n * <md-menu>\n *  <md-button ng-click=\"$mdMenu.open($event)\" class=\"md-icon-button\" aria-label=\"Open some menu\">\n *    <md-icon md-menu-origin md-svg-icon=\"call:phone\"></md-icon>\n *  </md-button>\n *  <md-menu-content>\n *    <md-menu-item>\n *      <md-button ng-click=\"doSomething()\" aria-label=\"Do something\">\n *        <md-icon md-menu-align-target md-svg-icon=\"call:phone\"></md-icon>\n *        Do Something\n *      </md-button>\n *    </md-menu-item>\n *  </md-menu-content>\n * </md-menu>\n * </hljs>\n *\n * ### Position Mode\n *\n * We can specify the origin of the menu by using the `md-position-mode` attribute.\n * This attribute allows specifying the positioning by the `x` and `y` axes.\n *\n * The default mode is `target target`. This mode uses the left and top edges of the origin element\n * to position the menu in LTR layouts. The `x` axis modes will adjust when in RTL layouts.\n *\n * Sometimes you want to specify alignment from the right side of a origin element. For example,\n * if we have a menu on the right side a toolbar, we may want to right align our menu content.\n * We can use `target-right target` to specify a right-oriented alignment target.\n * There is a working example of this in the Menu Position Modes demo.\n *\n * #### Horizontal Positioning Options\n * - `target`\n * - `target-left`\n * - `target-right`\n * - `cascade`\n * - `right`\n * - `left`\n *\n * #### Vertical Positioning Options\n * - `target`\n * - `cascade`\n * - `bottom`\n *\n * ### Menu Offsets\n *\n * It is sometimes unavoidable to need to have a deeper level of control for\n * the positioning of a menu to ensure perfect alignment. `md-menu` provides\n * the `md-offset` attribute to allow pixel-level specificity when adjusting\n * menu positioning.\n *\n * This offset is provided in the format of `x y` or `n` where `n` will be used\n * in both the `x` and `y` axis.\n * For example, to move a menu by `2px` down from the top, we can use:\n *\n * <hljs lang=\"html\">\n * <md-menu md-offset=\"0 2\">\n *   <!-- menu-content -->\n * </md-menu>\n * </hljs>\n *\n * Specifying `md-offset=\"2 2\"` would shift the menu two pixels down and two pixels to the right.\n *\n * ### Auto Focus\n * By default, when a menu opens, `md-menu` focuses the first button in the menu content.\n *\n * Sometimes you would like to focus another menu item instead of the first.<br/>\n * This can be done by applying the `md-autofocus` directive on the given element.\n *\n * <hljs lang=\"html\">\n * <md-menu-item>\n *   <md-button md-autofocus ng-click=\"doSomething()\">\n *     Auto Focus\n *   </md-button>\n * </md-menu-item>\n * </hljs>\n *\n *\n * ### Preventing close\n *\n * Sometimes you would like to be able to click on a menu item without having the menu\n * close. To do this, AngularJS Material exposes the `md-prevent-menu-close` attribute which\n * can be added to a button inside a menu to stop the menu from automatically closing.\n * You can then close the menu either by using `$mdMenu.close()` in the template,\n * or programmatically by injecting `$mdMenu` and calling `$mdMenu.hide()`.\n *\n * <hljs lang=\"html\">\n * <md-menu-content ng-mouseleave=\"$mdMenu.close()\">\n *   <md-menu-item>\n *     <md-button ng-click=\"doSomething()\" aria-label=\"Do something\" md-prevent-menu-close=\"md-prevent-menu-close\">\n *       <md-icon md-menu-align-target md-svg-icon=\"call:phone\"></md-icon>\n *       Do Something\n *     </md-button>\n *   </md-menu-item>\n * </md-menu-content>\n * </hljs>\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-menu>\n *  <md-button ng-click=\"$mdMenu.open($event)\" class=\"md-icon-button\">\n *    <md-icon md-svg-icon=\"call:phone\"></md-icon>\n *  </md-button>\n *  <md-menu-content>\n *    <md-menu-item><md-button ng-click=\"doSomething()\">Do Something</md-button></md-menu-item>\n *  </md-menu-content>\n * </md-menu>\n * </hljs>\n *\n * @param {string=} md-position-mode Specify pre-defined position modes for the `x` and `y` axes.\n *  The default modes are `target target`. This positions the origin of the menu using the left and top edges\n *  of the origin element in LTR layouts.<br>\n *  #### Valid modes for horizontal positioning\n * - `target`\n * - `target-left`\n * - `target-right`\n * - `cascade`\n * - `right`\n * - `left`<br>\n *  #### Valid modes for vertical positioning\n * - `target`\n * - `cascade`\n * - `bottom`\n * @param {string=} md-offset An offset to apply to the dropdown on opening, after positioning.\n *  Defined as `x` and `y` pixel offset values in the form of `x y`.<br>\n *  The default value is `0 0`.\n */\nMenuDirective.$inject = [\"$mdUtil\"];\nangular\n    .module('material.components.menu')\n    .directive('mdMenu', MenuDirective);\n\n/**\n * @ngInject\n */\nfunction MenuDirective($mdUtil) {\n  var INVALID_PREFIX = 'Invalid HTML for md-menu: ';\n  return {\n    restrict: 'E',\n    require: ['mdMenu', '?^mdMenuBar'],\n    controller: 'mdMenuCtrl', // empty function to be built by link\n    scope: true,\n    compile: compile\n  };\n\n  function compile(templateElement) {\n    templateElement.addClass('md-menu');\n\n    var triggerEl = templateElement.children()[0];\n    var prefixer = $mdUtil.prefixer();\n\n    if (!prefixer.hasAttribute(triggerEl, 'ng-click')) {\n      triggerEl = triggerEl\n          .querySelector(prefixer.buildSelector(['ng-click', 'ng-mouseenter'])) || triggerEl;\n    }\n\n    var isButtonTrigger = triggerEl.nodeName === 'MD-BUTTON' || triggerEl.nodeName === 'BUTTON';\n\n    if (triggerEl && isButtonTrigger && !triggerEl.hasAttribute('type')) {\n      triggerEl.setAttribute('type', 'button');\n    }\n\n    if (!triggerEl) {\n      throw Error(INVALID_PREFIX + 'Expected the menu to have a trigger element.');\n    }\n\n    if (templateElement.children().length !== 2) {\n      throw Error(INVALID_PREFIX + 'Expected two children elements. The second element must have a `md-menu-content` element.');\n    }\n\n    // Default element for ARIA attributes has the ngClick or ngMouseenter expression\n    triggerEl && triggerEl.setAttribute('aria-haspopup', 'true');\n\n    var nestedMenus = templateElement[0].querySelectorAll('md-menu');\n    var nestingDepth = parseInt(templateElement[0].getAttribute('md-nest-level'), 10) || 0;\n    if (nestedMenus) {\n      angular.forEach($mdUtil.nodesToArray(nestedMenus), function(menuEl) {\n        if (!menuEl.hasAttribute('md-position-mode')) {\n          menuEl.setAttribute('md-position-mode', 'cascade');\n        }\n        menuEl.classList.add('_md-nested-menu');\n        menuEl.setAttribute('md-nest-level', nestingDepth + 1);\n      });\n    }\n    return link;\n  }\n\n  function link(scope, element, attr, ctrls) {\n    var mdMenuCtrl = ctrls[0];\n    var isInMenuBar = !!ctrls[1];\n    var mdMenuBarCtrl = ctrls[1];\n    // Move everything into a md-menu-container and pass it to the controller\n    var menuContainer = angular.element('<div class=\"_md md-open-menu-container md-whiteframe-z2\"></div>');\n    var menuContents = element.children()[1];\n\n    element.addClass('_md');     // private md component indicator for styling\n\n    if (!menuContents.hasAttribute('role')) {\n      menuContents.setAttribute('role', 'menu');\n    }\n    menuContainer.append(menuContents);\n\n    element.on('$destroy', function() {\n      menuContainer.remove();\n    });\n\n    element.append(menuContainer);\n    menuContainer[0].style.display = 'none';\n    mdMenuCtrl.init(menuContainer, { isInMenuBar: isInMenuBar, mdMenuBarCtrl: mdMenuBarCtrl });\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMenuProvider.$inject = [\"$$interimElementProvider\"];angular\n  .module('material.components.menu')\n  .provider('$mdMenu', MenuProvider);\n\n/**\n * Interim element provider for the menu.\n * Handles behavior for a menu while it is open, including:\n *    - handling animating the menu opening/closing\n *    - handling key/mouse events on the menu element\n *    - handling enabling/disabling scroll while the menu is open\n *    - handling redrawing during resizes and orientation changes\n *\n */\n\nfunction MenuProvider($$interimElementProvider) {\n  menuDefaultOptions.$inject = [\"$mdUtil\", \"$mdTheming\", \"$mdConstant\", \"$document\", \"$window\", \"$q\", \"$$rAF\", \"$animateCss\", \"$animate\", \"$log\"];\n  var MENU_EDGE_MARGIN = 8;\n\n  return $$interimElementProvider('$mdMenu')\n    .setDefaults({\n      methods: ['target'],\n      options: menuDefaultOptions\n    });\n\n  /* @ngInject */\n  function menuDefaultOptions($mdUtil, $mdTheming, $mdConstant, $document, $window, $q, $$rAF,\n                              $animateCss, $animate, $log) {\n\n    var prefixer = $mdUtil.prefixer();\n    var animator = $mdUtil.dom.animator;\n\n    return {\n      parent: 'body',\n      onShow: onShow,\n      onRemove: onRemove,\n      hasBackdrop: true,\n      disableParentScroll: true,\n      skipCompile: true,\n      preserveScope: true,\n      multiple: true,\n      themable: true\n    };\n\n    /**\n     * Show modal backdrop element...\n     * @returns {function(): void} A function that removes this backdrop\n     */\n    function showBackdrop(scope, element, options) {\n      if (options.nestLevel) return angular.noop;\n\n      // If we are not within a dialog...\n      if (options.disableParentScroll && !$mdUtil.getClosest(options.target, 'MD-DIALOG')) {\n        // !! DO this before creating the backdrop; since disableScrollAround()\n        //    configures the scroll offset; which is used by mdBackDrop postLink()\n        options.restoreScroll = $mdUtil.disableScrollAround(options.element, options.parent);\n      } else {\n        options.disableParentScroll = false;\n      }\n\n      if (options.hasBackdrop) {\n        options.backdrop = $mdUtil.createBackdrop(scope, \"md-menu-backdrop md-click-catcher\");\n\n        $animate.enter(options.backdrop, $document[0].body);\n      }\n\n      /**\n       * Hide and destroys the backdrop created by showBackdrop()\n       */\n      return function hideBackdrop() {\n        if (options.backdrop) options.backdrop.remove();\n        if (options.disableParentScroll) options.restoreScroll();\n      };\n    }\n\n    /**\n     * Removing the menu element from the DOM and remove all associated event listeners\n     * and backdrop\n     */\n    function onRemove(scope, element, opts) {\n      opts.cleanupInteraction();\n      opts.cleanupBackdrop();\n      opts.cleanupResizing();\n      opts.hideBackdrop();\n\n      // Before the menu is closing remove the clickable class.\n      element.removeClass('md-clickable');\n\n      // For navigation $destroy events, do a quick, non-animated removal,\n      // but for normal closes (from clicks, etc) animate the removal\n\n      return (opts.$destroy === true) ? detachAndClean() : animateRemoval().then(detachAndClean);\n\n      /**\n       * For normal closes, animate the removal.\n       * For forced closes (like $destroy events), skip the animations\n       */\n      function animateRemoval() {\n        return $animateCss(element, {addClass: 'md-leave'}).start();\n      }\n\n      /**\n       * Detach the element\n       */\n      function detachAndClean() {\n        element.removeClass('md-active');\n        detachElement(element, opts);\n        opts.alreadyOpen = false;\n      }\n\n    }\n\n    /**\n     * Inserts and configures the staged Menu element into the DOM, positioning it,\n     * and wiring up various interaction events\n     */\n    function onShow(scope, element, opts) {\n      sanitizeAndConfigure(opts);\n\n      if (opts.menuContentEl[0]) {\n        // Inherit the theme from the target element.\n        $mdTheming.inherit(opts.menuContentEl, opts.target);\n      } else {\n        $log.warn(\n          '$mdMenu: Menu elements should always contain a `md-menu-content` element,' +\n          'otherwise interactivity features will not work properly.',\n          element\n        );\n      }\n\n      // Register various listeners to move menu on resize/orientation change\n      opts.cleanupResizing = startRepositioningOnResize();\n      opts.hideBackdrop = showBackdrop(scope, element, opts);\n\n      // Return the promise for when our menu is done animating in\n      return showMenu()\n        .then(function(response) {\n          opts.alreadyOpen = true;\n          opts.cleanupInteraction = activateInteraction();\n          opts.cleanupBackdrop = setupBackdrop();\n\n          // Since the menu finished its animation, mark the menu as clickable.\n          element.addClass('md-clickable');\n\n          return response;\n        });\n\n      /**\n       * Place the menu into the DOM and call positioning related functions\n       */\n      function showMenu() {\n        opts.parent.append(element);\n        element[0].style.display = '';\n\n        return $q(function(resolve) {\n          var position = calculateMenuPosition(element, opts);\n\n          element.removeClass('md-leave');\n\n          // Animate the menu scaling, and opacity [from its position origin (default == top-left)]\n          // to normal scale.\n          $animateCss(element, {\n            addClass: 'md-active',\n            from: animator.toCss(position),\n            to: animator.toCss({transform: ''})\n          })\n          .start()\n          .then(resolve);\n\n        });\n      }\n\n      /**\n       * Check for valid opts and set some useful defaults\n       */\n      function sanitizeAndConfigure() {\n        if (!opts.target) {\n          throw Error(\n            '$mdMenu.show() expected a target to animate from in options.target'\n          );\n        }\n        angular.extend(opts, {\n          alreadyOpen: false,\n          isRemoved: false,\n          target: angular.element(opts.target), // make sure it's not a naked DOM node\n          parent: angular.element(opts.parent),\n          menuContentEl: angular.element(element[0].querySelector('md-menu-content'))\n        });\n      }\n\n      /**\n       * Configure various resize listeners for screen changes\n       */\n      function startRepositioningOnResize() {\n\n        var repositionMenu = (function(target, options) {\n          return $$rAF.throttle(function() {\n            if (opts.isRemoved) return;\n            var position = calculateMenuPosition(target, options);\n\n            target.css(animator.toCss(position));\n          });\n        })(element, opts);\n\n        $window.addEventListener('resize', repositionMenu);\n        $window.addEventListener('orientationchange', repositionMenu);\n\n        return function stopRepositioningOnResize() {\n\n          // Disable resizing handlers\n          $window.removeEventListener('resize', repositionMenu);\n          $window.removeEventListener('orientationchange', repositionMenu);\n\n        };\n      }\n\n      /**\n       * Sets up the backdrop and listens for click elements.\n       * Once the backdrop will be clicked, the menu will automatically close.\n       * @returns {!Function} Function to remove the backdrop.\n       */\n      function setupBackdrop() {\n        if (!opts.backdrop) return angular.noop;\n\n        opts.backdrop.on('click', onBackdropClick);\n\n        return function() {\n          opts.backdrop.off('click', onBackdropClick);\n        };\n      }\n\n      /**\n       * Function to be called whenever the backdrop is clicked.\n       * @param {!MouseEvent} event\n       */\n      function onBackdropClick(event) {\n        event.preventDefault();\n        event.stopPropagation();\n\n        scope.$apply(function() {\n          opts.mdMenuCtrl.close(true, { closeAll: true });\n        });\n      }\n\n      /**\n       * Activate interaction on the menu. Resolves the focus target and closes the menu on\n       * escape or option click.\n       * @returns {!Function} Function to deactivate the interaction listeners.\n       */\n      function activateInteraction() {\n        if (!opts.menuContentEl[0]) return angular.noop;\n\n        // Wire up keyboard listeners.\n        // - Close on escape,\n        // - focus next item on down arrow,\n        // - focus prev item on up\n        opts.menuContentEl.on('keydown', onMenuKeyDown);\n        opts.menuContentEl[0].addEventListener('click', captureClickListener, true);\n\n        // kick off initial focus in the menu on the first enabled element\n        var focusTarget = opts.menuContentEl[0]\n          .querySelector(prefixer.buildSelector(['md-menu-focus-target', 'md-autofocus']));\n\n        if (!focusTarget) {\n          var childrenLen = opts.menuContentEl[0].children.length;\n          for (var childIndex = 0; childIndex < childrenLen; childIndex++) {\n            var child = opts.menuContentEl[0].children[childIndex];\n            focusTarget = child.querySelector('.md-button:not([disabled])');\n            if (focusTarget) {\n              break;\n            }\n            // Need to check the attribute as well since this might be a custom element whose\n            // disabled property is undefined.\n            if (child.firstElementChild && !child.firstElementChild.disabled &&\n                !child.firstElementChild.getAttribute('disabled')) {\n              focusTarget = child.firstElementChild;\n              break;\n            }\n          }\n        }\n\n        focusTarget && focusTarget.focus();\n\n        return function cleanupInteraction() {\n          opts.menuContentEl.off('keydown', onMenuKeyDown);\n          opts.menuContentEl[0].removeEventListener('click', captureClickListener, true);\n        };\n\n        // ************************************\n        // internal functions\n        // ************************************\n\n        function onMenuKeyDown(ev) {\n          var handled;\n          switch (ev.keyCode) {\n            case $mdConstant.KEY_CODE.ESCAPE:\n              if (opts.nestLevel) {\n                opts.mdMenuCtrl.close();\n              } else {\n                opts.mdMenuCtrl.close(false, { closeAll: true });\n              }\n              handled = true;\n              break;\n            case $mdConstant.KEY_CODE.TAB:\n              opts.mdMenuCtrl.close(false, { closeAll: true });\n              // Don't prevent default or stop propagation on this event as we want tab\n              // to move the focus to the next focusable element on the page.\n              handled = false;\n              break;\n            case $mdConstant.KEY_CODE.UP_ARROW:\n              if (!focusMenuItem(ev, opts.menuContentEl, opts, -1) && !opts.nestLevel) {\n                opts.mdMenuCtrl.triggerContainerProxy(ev);\n              }\n              handled = true;\n              break;\n            case $mdConstant.KEY_CODE.DOWN_ARROW:\n              if (!focusMenuItem(ev, opts.menuContentEl, opts, 1) && !opts.nestLevel) {\n                opts.mdMenuCtrl.triggerContainerProxy(ev);\n              }\n              handled = true;\n              break;\n            case $mdConstant.KEY_CODE.LEFT_ARROW:\n              if (opts.nestLevel) {\n                opts.mdMenuCtrl.close();\n              } else {\n                opts.mdMenuCtrl.triggerContainerProxy(ev);\n              }\n              handled = true;\n              break;\n            case $mdConstant.KEY_CODE.RIGHT_ARROW:\n              var parentMenu = $mdUtil.getClosest(ev.target, 'MD-MENU');\n              if (parentMenu && parentMenu != opts.parent[0]) {\n                ev.target.click();\n              } else {\n                opts.mdMenuCtrl.triggerContainerProxy(ev);\n              }\n              handled = true;\n              break;\n          }\n          if (handled) {\n            ev.preventDefault();\n            ev.stopImmediatePropagation();\n          }\n        }\n\n        function onBackdropClick(e) {\n          e.preventDefault();\n          e.stopPropagation();\n          scope.$apply(function() {\n            opts.mdMenuCtrl.close(true, { closeAll: true });\n          });\n        }\n\n        // Close menu on menu item click, if said menu-item is not disabled\n        function captureClickListener(e) {\n          var target = e.target;\n          // Traverse up the event until we get to the menuContentEl to see if\n          // there is an ng-click and that the ng-click is not disabled\n          do {\n            if (target == opts.menuContentEl[0]) return;\n            if ((hasAnyAttribute(target, ['ng-click', 'ng-href', 'ui-sref']) ||\n                target.nodeName == 'BUTTON' || target.nodeName == 'MD-BUTTON') && !hasAnyAttribute(target, ['md-prevent-menu-close'])) {\n              var closestMenu = $mdUtil.getClosest(target, 'MD-MENU');\n              if (!target.hasAttribute('disabled') && (!closestMenu || closestMenu == opts.parent[0])) {\n                close();\n              }\n              break;\n            }\n          } while (target = target.parentNode);\n\n          function close() {\n            scope.$apply(function() {\n              opts.mdMenuCtrl.close(true, { closeAll: true });\n            });\n          }\n\n          function hasAnyAttribute(target, attrs) {\n            if (!target) return false;\n\n            for (var i = 0, attr; attr = attrs[i]; ++i) {\n              if (prefixer.hasAttribute(target, attr)) {\n                return true;\n              }\n            }\n\n            return false;\n          }\n        }\n\n      }\n    }\n\n    /**\n     * Takes a keypress event and focuses the next/previous menu\n     * item from the emitting element\n     * @param {event} e - The origin keypress event\n     * @param {angular.element} menuEl - The menu element\n     * @param {object} opts - The interim element options for the mdMenu\n     * @param {number} direction - The direction to move in (+1 = next, -1 = prev)\n     */\n    function focusMenuItem(e, menuEl, opts, direction) {\n      var currentItem = $mdUtil.getClosest(e.target, 'MD-MENU-ITEM');\n\n      var items = $mdUtil.nodesToArray(menuEl[0].children);\n      var currentIndex = items.indexOf(currentItem);\n\n      // Traverse through our elements in the specified direction (+/-1) and try to\n      // focus them until we find one that accepts focus\n      var didFocus;\n      for (var i = currentIndex + direction; i >= 0 && i < items.length; i = i + direction) {\n        var focusTarget = items[i].querySelector('.md-button');\n        didFocus = attemptFocus(focusTarget);\n        if (didFocus) {\n          break;\n        }\n      }\n      return didFocus;\n    }\n\n    /**\n     * Attempts to focus an element. Checks whether that element is the currently\n     * focused element after attempting.\n     * @param {HTMLElement} el - the element to attempt focus on\n     * @returns {boolean} - whether the element was successfully focused\n     */\n    function attemptFocus(el) {\n      if (el && el.getAttribute('tabindex') != -1) {\n        el.focus();\n        return ($document[0].activeElement == el);\n      }\n    }\n\n    /**\n     * Use browser to remove this element without triggering a $destroy event\n     */\n    function detachElement(element, opts) {\n      if (!opts.preserveElement) {\n        if (toNode(element).parentNode === toNode(opts.parent)) {\n          toNode(opts.parent).removeChild(toNode(element));\n        }\n      } else {\n        toNode(element).style.display = 'none';\n      }\n    }\n\n    /**\n     * Computes menu position and sets the style on the menu container\n     * @param {HTMLElement} el - the menu container element\n     * @param {object} opts - the interim element options object\n     */\n    function calculateMenuPosition(el, opts) {\n\n      var containerNode = el[0],\n        openMenuNode = el[0].firstElementChild,\n        openMenuNodeRect = openMenuNode.getBoundingClientRect(),\n        boundryNode = $document[0].body,\n        boundryNodeRect = boundryNode.getBoundingClientRect();\n\n      var menuStyle = $window.getComputedStyle(openMenuNode);\n\n      var originNode = opts.target[0].querySelector(prefixer.buildSelector('md-menu-origin')) || opts.target[0],\n        originNodeRect = originNode.getBoundingClientRect();\n\n      var bounds = {\n        left: boundryNodeRect.left + MENU_EDGE_MARGIN,\n        top: Math.max(boundryNodeRect.top, 0) + MENU_EDGE_MARGIN,\n        bottom: Math.max(boundryNodeRect.bottom, Math.max(boundryNodeRect.top, 0) + boundryNodeRect.height) - MENU_EDGE_MARGIN,\n        right: boundryNodeRect.right - MENU_EDGE_MARGIN\n      };\n\n      var alignTarget, alignTargetRect = { top:0, left : 0, right:0, bottom:0 }, existingOffsets  = { top:0, left : 0, right:0, bottom:0  };\n      var positionMode = opts.mdMenuCtrl.positionMode();\n\n      if (positionMode.top === 'target' || positionMode.left === 'target' || positionMode.left === 'target-right') {\n        alignTarget = firstVisibleChild();\n        if (alignTarget) {\n          // TODO: Allow centering on an arbitrary node, for now center on first menu-item's child\n          alignTarget = alignTarget.firstElementChild || alignTarget;\n          alignTarget = alignTarget.querySelector(prefixer.buildSelector('md-menu-align-target')) || alignTarget;\n          alignTargetRect = alignTarget.getBoundingClientRect();\n\n          existingOffsets = {\n            top: parseFloat(containerNode.style.top || 0),\n            left: parseFloat(containerNode.style.left || 0)\n          };\n        }\n      }\n\n      var position = {};\n      var transformOrigin = 'top ';\n\n      switch (positionMode.top) {\n        case 'target':\n          position.top = existingOffsets.top + originNodeRect.top - alignTargetRect.top;\n          break;\n        case 'cascade':\n          position.top = originNodeRect.top - parseFloat(menuStyle.paddingTop) - originNode.style.top;\n          break;\n        case 'bottom':\n          position.top = originNodeRect.top + originNodeRect.height;\n          break;\n        default:\n          throw new Error('Invalid target mode \"' + positionMode.top + '\" specified for md-menu on Y axis.');\n      }\n\n      var rtl = $mdUtil.isRtl(el);\n\n      switch (positionMode.left) {\n        case 'target':\n          position.left = existingOffsets.left + originNodeRect.left - alignTargetRect.left;\n          transformOrigin += rtl ? 'right'  : 'left';\n          break;\n        case 'target-left':\n          position.left = originNodeRect.left;\n          transformOrigin += 'left';\n          break;\n        case 'target-right':\n          position.left = originNodeRect.right - openMenuNodeRect.width + (openMenuNodeRect.right - alignTargetRect.right);\n          transformOrigin += 'right';\n          break;\n        case 'cascade':\n          var willFitRight = rtl ? (originNodeRect.left - openMenuNodeRect.width) < bounds.left : (originNodeRect.right + openMenuNodeRect.width) < bounds.right;\n          position.left = willFitRight ? originNodeRect.right - originNode.style.left : originNodeRect.left - originNode.style.left - openMenuNodeRect.width;\n          transformOrigin += willFitRight ? 'left' : 'right';\n          break;\n        case 'right':\n          if (rtl) {\n            position.left = originNodeRect.right - originNodeRect.width;\n            transformOrigin += 'left';\n          } else {\n            position.left = originNodeRect.right - openMenuNodeRect.width;\n            transformOrigin += 'right';\n          }\n          break;\n        case 'left':\n          if (rtl) {\n            position.left = originNodeRect.right - openMenuNodeRect.width;\n            transformOrigin += 'right';\n          } else {\n            position.left = originNodeRect.left;\n            transformOrigin += 'left';\n          }\n          break;\n        default:\n          throw new Error('Invalid target mode \"' + positionMode.left + '\" specified for md-menu on X axis.');\n      }\n\n      var offsets = opts.mdMenuCtrl.offsets();\n      position.top += offsets.top;\n      position.left += offsets.left;\n\n      clamp(position);\n\n      var scaleX = Math.round(100 * Math.min(originNodeRect.width / containerNode.offsetWidth, 1.0)) / 100;\n      var scaleY = Math.round(100 * Math.min(originNodeRect.height / containerNode.offsetHeight, 1.0)) / 100;\n\n      return {\n        top: Math.round(position.top),\n        left: Math.round(position.left),\n        // Animate a scale out if we aren't just repositioning\n        transform: !opts.alreadyOpen ? $mdUtil.supplant('scale({0},{1})', [scaleX, scaleY]) : undefined,\n        transformOrigin: transformOrigin\n      };\n\n      /**\n       * Clamps the repositioning of the menu within the confines of\n       * bounding element (often the screen/body)\n       */\n      function clamp(pos) {\n        pos.top = Math.max(Math.min(pos.top, bounds.bottom - containerNode.offsetHeight), bounds.top);\n        pos.left = Math.max(Math.min(pos.left, bounds.right - containerNode.offsetWidth), bounds.left);\n      }\n\n      /**\n       * Gets the first visible child in the openMenuNode\n       * Necessary incase menu nodes are being dynamically hidden\n       */\n      function firstVisibleChild() {\n        for (var i = 0; i < openMenuNode.children.length; ++i) {\n          if ($window.getComputedStyle(openMenuNode.children[i]).display != 'none') {\n            return openMenuNode.children[i];\n          }\n        }\n      }\n    }\n  }\n  function toNode(el) {\n    if (el instanceof angular.element) {\n      el = el[0];\n    }\n    return el;\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.menuBar\n */\n\nangular.module('material.components.menuBar', [\n  'material.core',\n  'material.components.icon',\n  'material.components.menu'\n]);\n\n})();\n(function(){\n\"use strict\";\n\n\nMenuBarController.$inject = [\"$scope\", \"$rootScope\", \"$element\", \"$attrs\", \"$mdConstant\", \"$document\", \"$mdUtil\", \"$timeout\"];\nangular\n  .module('material.components.menuBar')\n  .controller('MenuBarController', MenuBarController);\n\nvar BOUND_MENU_METHODS = ['handleKeyDown', 'handleMenuHover', 'scheduleOpenHoveredMenu', 'cancelScheduledOpen'];\n\n/**\n * @ngInject\n */\nfunction MenuBarController($scope, $rootScope, $element, $attrs, $mdConstant, $document, $mdUtil, $timeout) {\n  this.$element = $element;\n  this.$attrs = $attrs;\n  this.$mdConstant = $mdConstant;\n  this.$mdUtil = $mdUtil;\n  this.$document = $document;\n  this.$scope = $scope;\n  this.$rootScope = $rootScope;\n  this.$timeout = $timeout;\n\n  var self = this;\n  angular.forEach(BOUND_MENU_METHODS, function(methodName) {\n    self[methodName] = angular.bind(self, self[methodName]);\n  });\n}\n\nMenuBarController.prototype.init = function() {\n  var $element = this.$element;\n  var $mdUtil = this.$mdUtil;\n  var $scope = this.$scope;\n\n  var self = this;\n  var deregisterFns = [];\n  $element.on('keydown', this.handleKeyDown);\n  this.parentToolbar = $mdUtil.getClosest($element, 'MD-TOOLBAR');\n\n  deregisterFns.push(this.$rootScope.$on('$mdMenuOpen', function(event, el) {\n    if (self.getMenus().indexOf(el[0]) != -1) {\n      $element[0].classList.add('md-open');\n      el[0].classList.add('md-open');\n      self.currentlyOpenMenu = el.controller('mdMenu');\n      self.currentlyOpenMenu.registerContainerProxy(self.handleKeyDown);\n      self.enableOpenOnHover();\n    }\n  }));\n\n  deregisterFns.push(this.$rootScope.$on('$mdMenuClose', function(event, el, opts) {\n    var rootMenus = self.getMenus();\n    if (rootMenus.indexOf(el[0]) != -1) {\n      $element[0].classList.remove('md-open');\n      el[0].classList.remove('md-open');\n    }\n\n    var ctrl = angular.element(el[0]).controller('mdMenu');\n    if (ctrl.isInMenuBar && ctrl.mdMenuBarCtrl === self) {\n      var parentMenu = el[0];\n      while (parentMenu && rootMenus.indexOf(parentMenu) == -1) {\n        parentMenu = $mdUtil.getClosest(parentMenu, 'MD-MENU', true);\n      }\n      if (parentMenu) {\n        if (!opts.skipFocus) parentMenu.querySelector('button:not([disabled])').focus();\n        self.currentlyOpenMenu = undefined;\n      }\n      self.disableOpenOnHover();\n      self.setKeyboardMode(true);\n    }\n  }));\n\n  $scope.$on('$destroy', function() {\n    self.disableOpenOnHover();\n    while (deregisterFns.length) {\n      deregisterFns.shift()();\n    }\n  });\n\n\n  this.setKeyboardMode(true);\n};\n\nMenuBarController.prototype.setKeyboardMode = function(enabled) {\n  if (enabled) this.$element[0].classList.add('md-keyboard-mode');\n  else this.$element[0].classList.remove('md-keyboard-mode');\n};\n\nMenuBarController.prototype.enableOpenOnHover = function() {\n  if (this.openOnHoverEnabled) return;\n\n  var self = this;\n\n  self.openOnHoverEnabled = true;\n\n  if (self.parentToolbar) {\n    self.parentToolbar.classList.add('md-has-open-menu');\n\n    // Needs to be on the next tick so it doesn't close immediately.\n    self.$mdUtil.nextTick(function() {\n      angular.element(self.parentToolbar).on('click', self.handleParentClick);\n    }, false);\n  }\n\n  angular\n    .element(self.getMenus())\n    .on('mouseenter', self.handleMenuHover);\n};\n\nMenuBarController.prototype.handleMenuHover = function(e) {\n  this.setKeyboardMode(false);\n  if (this.openOnHoverEnabled) {\n    this.scheduleOpenHoveredMenu(e);\n  }\n};\n\nMenuBarController.prototype.disableOpenOnHover = function() {\n  if (!this.openOnHoverEnabled) return;\n\n  this.openOnHoverEnabled = false;\n\n  if (this.parentToolbar) {\n    this.parentToolbar.classList.remove('md-has-open-menu');\n    angular.element(this.parentToolbar).off('click', this.handleParentClick);\n  }\n\n  angular\n    .element(this.getMenus())\n    .off('mouseenter', this.handleMenuHover);\n};\n\nMenuBarController.prototype.scheduleOpenHoveredMenu = function(e) {\n  var menuEl = angular.element(e.currentTarget);\n  var menuCtrl = menuEl.controller('mdMenu');\n  this.setKeyboardMode(false);\n  this.scheduleOpenMenu(menuCtrl);\n};\n\nMenuBarController.prototype.scheduleOpenMenu = function(menuCtrl) {\n  var self = this;\n  var $timeout = this.$timeout;\n  if (menuCtrl != self.currentlyOpenMenu) {\n    $timeout.cancel(self.pendingMenuOpen);\n    self.pendingMenuOpen = $timeout(function() {\n      self.pendingMenuOpen = undefined;\n      if (self.currentlyOpenMenu) {\n        self.currentlyOpenMenu.close(true, { closeAll: true });\n      }\n      menuCtrl.open();\n    }, 200, false);\n  }\n};\n\nMenuBarController.prototype.handleKeyDown = function(e) {\n  var keyCodes = this.$mdConstant.KEY_CODE;\n  var currentMenu = this.currentlyOpenMenu;\n  var wasOpen = currentMenu && currentMenu.isOpen;\n  this.setKeyboardMode(true);\n  var handled, newMenu, newMenuCtrl;\n  switch (e.keyCode) {\n    case keyCodes.DOWN_ARROW:\n      if (currentMenu) {\n        currentMenu.focusMenuContainer();\n      } else {\n        this.openFocusedMenu();\n      }\n      handled = true;\n      break;\n    case keyCodes.UP_ARROW:\n      currentMenu && currentMenu.close();\n      handled = true;\n      break;\n    case keyCodes.LEFT_ARROW:\n      newMenu = this.focusMenu(-1);\n      if (wasOpen) {\n        newMenuCtrl = angular.element(newMenu).controller('mdMenu');\n        this.scheduleOpenMenu(newMenuCtrl);\n      }\n      handled = true;\n      break;\n    case keyCodes.RIGHT_ARROW:\n      newMenu = this.focusMenu(+1);\n      if (wasOpen) {\n        newMenuCtrl = angular.element(newMenu).controller('mdMenu');\n        this.scheduleOpenMenu(newMenuCtrl);\n      }\n      handled = true;\n      break;\n  }\n  if (handled) {\n    e && e.preventDefault && e.preventDefault();\n    e && e.stopImmediatePropagation && e.stopImmediatePropagation();\n  }\n};\n\nMenuBarController.prototype.focusMenu = function(direction) {\n  var menus = this.getMenus();\n  var focusedIndex = this.getFocusedMenuIndex();\n\n  if (focusedIndex == -1) { focusedIndex = this.getOpenMenuIndex(); }\n\n  var changed = false;\n\n  if (focusedIndex == -1) { focusedIndex = 0; changed = true; }\n  else if (\n    direction < 0 && focusedIndex > 0 ||\n    direction > 0 && focusedIndex < menus.length - direction\n  ) {\n    focusedIndex += direction;\n    changed = true;\n  }\n  if (changed) {\n    menus[focusedIndex].querySelector('button').focus();\n    return menus[focusedIndex];\n  }\n};\n\nMenuBarController.prototype.openFocusedMenu = function() {\n  var menu = this.getFocusedMenu();\n  menu && angular.element(menu).controller('mdMenu').open();\n};\n\nMenuBarController.prototype.getMenus = function() {\n  var $element = this.$element;\n  return this.$mdUtil.nodesToArray($element[0].children)\n    .filter(function(el) { return el.nodeName == 'MD-MENU'; });\n};\n\nMenuBarController.prototype.getFocusedMenu = function() {\n  return this.getMenus()[this.getFocusedMenuIndex()];\n};\n\nMenuBarController.prototype.getFocusedMenuIndex = function() {\n  var $mdUtil = this.$mdUtil;\n  var focusedEl = $mdUtil.getClosest(\n    this.$document[0].activeElement,\n    'MD-MENU'\n  );\n  if (!focusedEl) return -1;\n\n  var focusedIndex = this.getMenus().indexOf(focusedEl);\n  return focusedIndex;\n};\n\nMenuBarController.prototype.getOpenMenuIndex = function() {\n  var menus = this.getMenus();\n  for (var i = 0; i < menus.length; ++i) {\n    if (menus[i].classList.contains('md-open')) return i;\n  }\n  return -1;\n};\n\nMenuBarController.prototype.handleParentClick = function(event) {\n  var openMenu = this.querySelector('md-menu.md-open');\n\n  if (openMenu && !openMenu.contains(event.target)) {\n    angular.element(openMenu).controller('mdMenu').close(true, {\n      closeAll: true\n    });\n  }\n};\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc directive\n * @name mdMenuBar\n * @module material.components.menuBar\n * @restrict E\n * @description\n *\n * Menu bars are containers that hold multiple menus. They change the behavior and appearance\n * of the `md-menu` directive to behave similar to an operating system provided menu.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-menu-bar>\n *   <md-menu>\n *     <button ng-click=\"$mdMenu.open()\">\n *       File\n *     </button>\n *     <md-menu-content>\n *       <md-menu-item>\n *         <md-button ng-click=\"ctrl.sampleAction('share', $event)\">\n *           Share...\n *         </md-button>\n *       </md-menu-item>\n *       <md-menu-divider></md-menu-divider>\n *       <md-menu-item>\n *       <md-menu-item>\n *         <md-menu>\n *           <md-button ng-click=\"$mdMenu.open()\">New</md-button>\n *           <md-menu-content>\n *             <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Document', $event)\">Document</md-button></md-menu-item>\n *             <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Spreadsheet', $event)\">Spreadsheet</md-button></md-menu-item>\n *             <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Presentation', $event)\">Presentation</md-button></md-menu-item>\n *             <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Form', $event)\">Form</md-button></md-menu-item>\n *             <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Drawing', $event)\">Drawing</md-button></md-menu-item>\n *           </md-menu-content>\n *         </md-menu>\n *       </md-menu-item>\n *     </md-menu-content>\n *   </md-menu>\n * </md-menu-bar>\n * </hljs>\n *\n * ## Menu Bar Controls\n *\n * You may place `md-menu-item`s that function as controls within menu bars.\n * There are two modes that are exposed via the `type` attribute of the `md-menu-item`.\n * `type=\"checkbox\"` will function as a boolean control for the `ng-model` attribute of the\n * `md-menu-item`. `type=\"radio\"` will function like a radio button, setting the `ngModel`\n * to the `string` value of the `value` attribute. If you need non-string values, you can use\n * `ng-value` to provide an expression (this is similar to how angular's native `input[type=radio]`\n * works.\n *\n * If you want either to disable closing the opened menu when clicked, you can add the\n * `md-prevent-menu-close` attribute to the `md-menu-item`. The attribute will be forwarded to the\n * `button` element that is generated.\n *\n * <hljs lang=\"html\">\n * <md-menu-bar>\n *  <md-menu>\n *    <button ng-click=\"$mdMenu.open()\">\n *      Sample Menu\n *    </button>\n *    <md-menu-content>\n *      <md-menu-item type=\"checkbox\" ng-model=\"settings.allowChanges\" md-prevent-menu-close>\n *        Allow changes\n *      </md-menu-item>\n *      <md-menu-divider></md-menu-divider>\n *      <md-menu-item type=\"radio\" ng-model=\"settings.mode\" ng-value=\"1\">Mode 1</md-menu-item>\n *      <md-menu-item type=\"radio\" ng-model=\"settings.mode\" ng-value=\"2\">Mode 2</md-menu-item>\n *      <md-menu-item type=\"radio\" ng-model=\"settings.mode\" ng-value=\"3\">Mode 3</md-menu-item>\n *    </md-menu-content>\n *  </md-menu>\n * </md-menu-bar>\n * </hljs>\n *\n *\n * ### Nesting Menus\n *\n * Menus may be nested within menu bars. This is commonly called cascading menus.\n * To nest a menu place the nested menu inside the content of the `md-menu-item`.\n * <hljs lang=\"html\">\n * <md-menu-item>\n *   <md-menu>\n *     <button ng-click=\"$mdMenu.open()\">New</md-button>\n *     <md-menu-content>\n *       <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Document', $event)\">Document</md-button></md-menu-item>\n *       <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Spreadsheet', $event)\">Spreadsheet</md-button></md-menu-item>\n *       <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Presentation', $event)\">Presentation</md-button></md-menu-item>\n *       <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Form', $event)\">Form</md-button></md-menu-item>\n *       <md-menu-item><md-button ng-click=\"ctrl.sampleAction('New Drawing', $event)\">Drawing</md-button></md-menu-item>\n *     </md-menu-content>\n *   </md-menu>\n * </md-menu-item>\n * </hljs>\n *\n */\n\nMenuBarDirective.$inject = [\"$mdUtil\", \"$mdTheming\"];\nangular\n  .module('material.components.menuBar')\n  .directive('mdMenuBar', MenuBarDirective);\n\n/* @ngInject */\nfunction MenuBarDirective($mdUtil, $mdTheming) {\n  return {\n    restrict: 'E',\n    require: 'mdMenuBar',\n    controller: 'MenuBarController',\n\n    compile: function compile(templateEl, templateAttrs) {\n      if (!templateAttrs.ariaRole) {\n        templateEl[0].setAttribute('role', 'menubar');\n      }\n      angular.forEach(templateEl[0].children, function(menuEl) {\n        if (menuEl.nodeName == 'MD-MENU') {\n          if (!menuEl.hasAttribute('md-position-mode')) {\n            menuEl.setAttribute('md-position-mode', 'left bottom');\n\n            // Since we're in the compile function and actual `md-buttons` are not compiled yet,\n            // we need to query for possible `md-buttons` as well.\n            menuEl.querySelector('button, a, md-button').setAttribute('role', 'menuitem');\n          }\n          var contentEls = $mdUtil.nodesToArray(menuEl.querySelectorAll('md-menu-content'));\n          angular.forEach(contentEls, function(contentEl) {\n            contentEl.classList.add('md-menu-bar-menu');\n            contentEl.classList.add('md-dense');\n            if (!contentEl.hasAttribute('width')) {\n              contentEl.setAttribute('width', 5);\n            }\n          });\n        }\n      });\n\n      // Mark the child menu items that they're inside a menu bar. This is necessary,\n      // because mnMenuItem has special behaviour during compilation, depending on\n      // whether it is inside a mdMenuBar. We can usually figure this out via the DOM,\n      // however if a directive that uses documentFragment is applied to the child (e.g. ngRepeat),\n      // the element won't have a parent and won't compile properly.\n      templateEl.find('md-menu-item').addClass('md-in-menu-bar');\n\n      return function postLink(scope, el, attr, ctrl) {\n        el.addClass('_md');     // private md component indicator for styling\n        $mdTheming(scope, el);\n        ctrl.init();\n      };\n    }\n  };\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nangular\n  .module('material.components.menuBar')\n  .directive('mdMenuDivider', MenuDividerDirective);\n\n\nfunction MenuDividerDirective() {\n  return {\n    restrict: 'E',\n    compile: function(templateEl, templateAttrs) {\n      if (!templateAttrs.role) {\n        templateEl[0].setAttribute('role', 'separator');\n      }\n    }\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMenuItemController.$inject = [\"$scope\", \"$element\", \"$attrs\"];\nangular\n  .module('material.components.menuBar')\n  .controller('MenuItemController', MenuItemController);\n\n\n/**\n * @ngInject\n */\nfunction MenuItemController($scope, $element, $attrs) {\n  this.$element = $element;\n  this.$attrs = $attrs;\n  this.$scope = $scope;\n}\n\nMenuItemController.prototype.init = function(ngModel) {\n  var $element = this.$element;\n  var $attrs = this.$attrs;\n\n  this.ngModel = ngModel;\n  if ($attrs.type == 'checkbox' || $attrs.type == 'radio') {\n    this.mode  = $attrs.type;\n    this.iconEl = $element[0].children[0];\n    this.buttonEl = $element[0].children[1];\n    if (ngModel) {\n      // Clear ngAria set attributes\n      this.initClickListeners();\n    }\n  }\n};\n\n// ngAria auto sets attributes on a menu-item with a ngModel.\n// We don't want this because our content (buttons) get the focus\n// and set their own aria attributes appropritately. Having both\n// breaks NVDA / JAWS. This undeoes ngAria's attrs.\nMenuItemController.prototype.clearNgAria = function() {\n  var el = this.$element[0];\n  var clearAttrs = ['role', 'tabindex', 'aria-invalid', 'aria-checked'];\n  angular.forEach(clearAttrs, function(attr) {\n    el.removeAttribute(attr);\n  });\n};\n\nMenuItemController.prototype.initClickListeners = function() {\n  var self = this;\n  var ngModel = this.ngModel;\n  var $scope = this.$scope;\n  var $attrs = this.$attrs;\n  var $element = this.$element;\n  var mode = this.mode;\n\n  this.handleClick = angular.bind(this, this.handleClick);\n\n  var icon = this.iconEl;\n  var button = angular.element(this.buttonEl);\n  var handleClick = this.handleClick;\n\n  $attrs.$observe('disabled', setDisabled);\n  setDisabled($attrs.disabled);\n\n  ngModel.$render = function render() {\n    self.clearNgAria();\n    if (isSelected()) {\n      icon.style.display = '';\n      button.attr('aria-checked', 'true');\n    } else {\n      icon.style.display = 'none';\n      button.attr('aria-checked', 'false');\n    }\n  };\n\n  $scope.$$postDigest(ngModel.$render);\n\n  function isSelected() {\n    if (mode == 'radio') {\n      var val = $attrs.ngValue ? $scope.$eval($attrs.ngValue) : $attrs.value;\n      return ngModel.$modelValue == val;\n    } else {\n      return ngModel.$modelValue;\n    }\n  }\n\n  function setDisabled(disabled) {\n    if (disabled) {\n      button.off('click', handleClick);\n    } else {\n      button.on('click', handleClick);\n    }\n  }\n};\n\nMenuItemController.prototype.handleClick = function(e) {\n  var mode = this.mode;\n  var ngModel = this.ngModel;\n  var $attrs = this.$attrs;\n  var newVal;\n  if (mode == 'checkbox') {\n    newVal = !ngModel.$modelValue;\n  } else if (mode == 'radio') {\n    newVal = $attrs.ngValue ? this.$scope.$eval($attrs.ngValue) : $attrs.value;\n  }\n  ngModel.$setViewValue(newVal);\n  ngModel.$render();\n};\n\n})();\n(function(){\n\"use strict\";\n\n\nMenuItemDirective.$inject = [\"$mdUtil\", \"$mdConstant\", \"$$mdSvgRegistry\"];\nangular\n  .module('material.components.menuBar')\n  .directive('mdMenuItem', MenuItemDirective);\n\n /* @ngInject */\nfunction MenuItemDirective($mdUtil, $mdConstant, $$mdSvgRegistry) {\n  return {\n    controller: 'MenuItemController',\n    require: ['mdMenuItem', '?ngModel'],\n    priority: $mdConstant.BEFORE_NG_ARIA,\n    compile: function(templateEl, templateAttrs) {\n      var type = templateAttrs.type;\n      var inMenuBarClass = 'md-in-menu-bar';\n\n      // Note: This allows us to show the `check` icon for the md-menu-bar items.\n      // The `md-in-menu-bar` class is set by the mdMenuBar directive.\n      if ((type === 'checkbox' || type === 'radio') && templateEl.hasClass(inMenuBarClass)) {\n        var text = templateEl[0].textContent;\n        var buttonEl = angular.element('<md-button type=\"button\"></md-button>');\n        var iconTemplate = '<md-icon md-svg-src=\"' + $$mdSvgRegistry.mdChecked + '\"></md-icon>';\n\n        buttonEl.html(text);\n        buttonEl.attr('tabindex', '0');\n\n        if (angular.isDefined(templateAttrs.mdPreventMenuClose)) {\n          buttonEl.attr('md-prevent-menu-close', templateAttrs.mdPreventMenuClose);\n        }\n\n        templateEl.html('');\n        templateEl.append(angular.element(iconTemplate));\n        templateEl.append(buttonEl);\n        templateEl.addClass('md-indent').removeClass(inMenuBarClass);\n\n        setDefault('role', type === 'checkbox' ? 'menuitemcheckbox' : 'menuitemradio', buttonEl);\n        moveAttrToButton('ng-disabled');\n\n      } else {\n        setDefault('role', 'menuitem', templateEl[0].querySelector('md-button, button, a'));\n      }\n\n\n      return function(scope, el, attrs, ctrls) {\n        var ctrl = ctrls[0];\n        var ngModel = ctrls[1];\n        ctrl.init(ngModel);\n      };\n\n      function setDefault(attr, val, el) {\n        el = el || templateEl;\n        if (el instanceof angular.element) {\n          el = el[0];\n        }\n        if (!el.hasAttribute(attr)) {\n          el.setAttribute(attr, val);\n        }\n      }\n\n      function moveAttrToButton(attribute) {\n        var attributes = $mdUtil.prefixer(attribute);\n\n        angular.forEach(attributes, function(attr) {\n          if (templateEl[0].hasAttribute(attr)) {\n            var val = templateEl[0].getAttribute(attr);\n            buttonEl[0].setAttribute(attr, val);\n            templateEl[0].removeAttribute(attr);\n          }\n        });\n      }\n    }\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.navBar\n */\nMdNavBar.$inject = [\"$mdAria\", \"$mdTheming\", \"$window\", \"$mdUtil\"];\nMdNavBarController.$inject = [\"$element\", \"$scope\", \"$timeout\", \"$mdConstant\"];\nMdNavItem.$inject = [\"$mdAria\", \"$$rAF\", \"$mdUtil\", \"$window\"];\nMdNavItemController.$inject = [\"$element\"];\nangular.module('material.components.navBar', ['material.core'])\n    .controller('MdNavBarController', MdNavBarController)\n    .directive('mdNavBar', MdNavBar)\n    .controller('MdNavItemController', MdNavItemController)\n    .directive('mdNavItem', MdNavItem);\n\n/**\n * @ngdoc directive\n * @name mdNavBar\n * @module material.components.navBar\n *\n * @restrict E\n *\n * @description\n * The `<md-nav-bar>` directive renders a list of material tabs that can be used\n * for top-level page navigation. Unlike `<md-tabs>`, it has no concept of a tab\n * body and no bar pagination.\n *\n * Because it deals with page navigation, certain routing concepts are built-in.\n * Route changes via `ng-href`, `ui-sref`, or `ng-click` events are supported.\n * Alternatively, the user could simply watch the value of `md-selected-nav-item`\n * (`currentNavItem` in the below example) for changes.\n *\n * Accessibility functionality is implemented as a\n * <a href=\"https://www.w3.org/TR/wai-aria-1.0/complete#tablist\">\n *   tablist</a> with\n * <a href=\"https://www.w3.org/TR/wai-aria-1.0/complete#tab\">tabs</a>.\n * We've kept the `role=\"navigation\"` on the `<nav>`, for backwards compatibility, even though\n *  it is not required in the\n * <a href=\"https://www.w3.org/TR/wai-aria-practices/#aria_lh_navigation\">\n *   latest Working Group Note from December 2017</a>.\n *\n * <h3>Keyboard Navigation</h3>\n * - `Tab`/`Shift+Tab` moves the focus to the next/previous interactive element on the page\n * - `Enter`/`Space` selects the focused nav item and navigates to display the item's contents\n * - `Right`/`Down` moves focus to the next nav item, wrapping at the end\n * - `Left`/`Up` moves focus to the previous nav item, wrapping at the end\n * - `Home`/`End` moves the focus to the first/last nav item\n *\n * @param {string=} md-selected-nav-item The name of the current tab; this must\n *     match the `name` attribute of `<md-nav-item>`.\n * @param {boolean=} md-no-ink-bar If set to true, the ink bar will be hidden.\n * @param {string=} nav-bar-aria-label An `aria-label` applied to the `md-nav-bar`'s tablist\n * for accessibility.\n *\n * @usage\n * <hljs lang=\"html\">\n *  <md-nav-bar md-selected-nav-item=\"currentNavItem\">\n *    <md-nav-item md-nav-click=\"goto('page1')\" name=\"page1\">\n *      Page One\n *    </md-nav-item>\n *    <md-nav-item md-nav-href=\"#page2\" name=\"page3\">Page Two</md-nav-item>\n *    <md-nav-item md-nav-sref=\"page3\" name=\"page2\">Page Three</md-nav-item>\n *    <md-nav-item\n *      md-nav-sref=\"app.page4\"\n *      sref-opts=\"{reload: true, notify: true}\"\n *      name=\"page4\">\n *      Page Four\n *    </md-nav-item>\n *  </md-nav-bar>\n *</hljs>\n * <hljs lang=\"js\">\n * (function() {\n *   'use strict';\n *\n *    $rootScope.$on('$routeChangeSuccess', function(event, current) {\n *      $scope.currentLink = getCurrentLinkFromRoute(current);\n *    });\n * });\n * </hljs>\n */\n/**\n * @param $mdAria\n * @param $mdTheming\n * @param $window\n * @param $mdUtil\n * @constructor\n * @ngInject\n */\nfunction MdNavBar($mdAria, $mdTheming, $window, $mdUtil) {\n  return {\n    restrict: 'E',\n    transclude: true,\n    controller: MdNavBarController,\n    controllerAs: 'ctrl',\n    bindToController: true,\n    scope: {\n      'mdSelectedNavItem': '=?',\n      'mdNoInkBar': '=?',\n      'navBarAriaLabel': '@?',\n    },\n    template:\n      '<div class=\"md-nav-bar\">' +\n        '<nav role=\"navigation\">' +\n          '<ul class=\"_md-nav-bar-list\" ng-transclude role=\"tablist\" ' +\n            'ng-focus=\"ctrl.onFocus()\" ' + // Deprecated but kept for now in order to not break tests\n            'aria-label=\"{{ctrl.navBarAriaLabel}}\">' +\n          '</ul>' +\n        '</nav>' +\n        '<md-nav-ink-bar ng-hide=\"ctrl.mdNoInkBar\"></md-nav-ink-bar>' +\n      '</div>',\n    link: function(scope, element, attrs, ctrl) {\n\n      ctrl.width = $window.innerWidth;\n\n      function onResize() {\n        if (ctrl.width !== $window.innerWidth) {\n          ctrl.updateSelectedTabInkBar();\n          ctrl.width = $window.innerWidth;\n          scope.$digest();\n        }\n      }\n\n      function cleanUp() {\n        angular.element($window).off('resize', onResize);\n      }\n\n      angular.element($window).on('resize', $mdUtil.debounce(onResize, 300));\n      scope.$on('$destroy', cleanUp);\n\n      $mdTheming(element);\n      if (!ctrl.navBarAriaLabel) {\n        $mdAria.expectAsync(element, 'aria-label', angular.noop);\n      }\n    },\n  };\n}\n\n/**\n * Controller for the nav-bar component.\n * Accessibility functionality is implemented as a tablist\n * (https://www.w3.org/TR/wai-aria-1.0/complete#tablist) and\n * tabs (https://www.w3.org/TR/wai-aria-1.0/complete#tab).\n *\n * @param {!JQLite} $element\n * @param {!IScope} $scope\n * @param {!ITimeoutService} $timeout\n * @param {!Object} $mdConstant\n * @constructor\n * @final\n * @ngInject\n */\nfunction MdNavBarController($element, $scope, $timeout, $mdConstant) {\n  // Injected variables\n  /**\n   * @private @const\n   * @type {!ITimeoutService}\n   */\n  this._$timeout = $timeout;\n\n  /**\n   * @private @const\n   * @type {!IScope}\n   */\n  this._$scope = $scope;\n\n  /**\n   * @private @const\n   * @type {!Object}\n   */\n  this._$mdConstant = $mdConstant;\n\n  // Data-bound variables.\n  /** @type {?string} */\n  this.mdSelectedNavItem;\n\n  /** @type {?string} */\n  this.navBarAriaLabel;\n\n  // State variables.\n  /** @type {?HTMLElement} */\n  this._navBarEl = $element[0];\n\n  /** @type {?JQLite} */\n  this._inkbar;\n\n  var self = this;\n  // need to wait for transcluded content to be available\n  var deregisterTabWatch = this._$scope.$watch(function() {\n    return self._navBarEl.querySelectorAll('._md-nav-button').length;\n  },\n  function(newLength) {\n    if (newLength > 0) {\n      self._initTabs();\n      deregisterTabWatch();\n    }\n  });\n}\n\n/**\n * Initializes the tab components once they exist.\n * @private\n */\nMdNavBarController.prototype._initTabs = function() {\n  this._inkbar = angular.element(this._navBarEl.querySelector('md-nav-ink-bar'));\n\n  var self = this;\n  this._$timeout(function() {\n    self._updateTabs(self.mdSelectedNavItem, null);\n  });\n\n  this._$scope.$watch('ctrl.mdSelectedNavItem', function(newValue, oldValue) {\n    // Wait a digest before update tabs for products doing\n    // anything dynamic in the template.\n    self._$timeout(function() {\n      self._updateTabs(newValue, oldValue);\n    });\n  });\n};\n\n/**\n * Set the current tab to be selected.\n * @param {string|undefined} newValue New current tab name.\n * @param {string|undefined|null} oldValue Previous tab name.\n * @private\n */\nMdNavBarController.prototype._updateTabs = function(newValue, oldValue) {\n  var self = this;\n  var tabs = this._getTabs();\n  var sameTab = newValue === oldValue;\n\n  // this._getTabs can return null if nav-bar has not yet been initialized\n  if (!tabs) return;\n\n  var newIndex = -1;\n  var newTab = this._getTabByName(newValue);\n  var oldTab = this._getTabByName(oldValue);\n\n  if (oldTab) {\n    oldTab.setSelected(false);\n  }\n\n  if (newTab) {\n    newTab.setSelected(true);\n    newIndex = tabs.indexOf(newTab);\n  }\n\n  this._$timeout(function() {\n    self._updateInkBarStyles(newTab, newIndex);\n    // Don't change focus when there is no newTab, the new and old tabs are the same, or when\n    // called from MdNavBarController._initTabs() which would have no oldTab defined.\n    if (newTab && oldTab && !sameTab) {\n      self._moveFocus(oldTab, newTab);\n    }\n  });\n};\n\n/**\n * Repositions the ink bar to the selected tab.\n * @param {MdNavItemController} tab the nav item that should have ink bar styles applied\n * @param {number=} newIndex the index of the newly selected nav item\n * @private\n */\nMdNavBarController.prototype._updateInkBarStyles = function(tab, newIndex) {\n  this._inkbar.css({display: newIndex < 0 ? 'none' : ''});\n\n  if (tab) {\n    var tabEl = tab.getButtonEl();\n    var left = tabEl.offsetLeft;\n    var tabWidth = tabEl.offsetWidth;\n    var navBarWidth = this._navBarEl.getBoundingClientRect().width;\n    var scale = tabWidth / navBarWidth;\n    var translate = left / navBarWidth * 100;\n\n    this._inkbar.css({ transform: 'translateX(' + translate + '%) scaleX(' + scale + ')' });\n  }\n};\n\n/**\n * Updates ink bar to match current tab.\n */\nMdNavBarController.prototype.updateSelectedTabInkBar = function() {\n  this._updateInkBarStyles(this._getSelectedTab());\n};\n\n/**\n * Returns an array of the current tabs.\n * @return {Array<!MdNavItemController>}\n * @private\n */\nMdNavBarController.prototype._getTabs = function() {\n  var controllers = Array.prototype.slice.call(\n    this._navBarEl.querySelectorAll('.md-nav-item'))\n    .map(function(el) {\n      return angular.element(el).controller('mdNavItem');\n    });\n  return controllers.indexOf(undefined) ? controllers : [];\n};\n\n/**\n * Returns the tab with the specified name.\n * @param {string} name The name of the tab, found in its name attribute.\n * @return {MdNavItemController}\n * @private\n */\nMdNavBarController.prototype._getTabByName = function(name) {\n  return this._findTab(function(tab) {\n    return tab.getName() === name;\n  });\n};\n\n/**\n * Returns the selected tab.\n * @return {MdNavItemController}\n * @private\n */\nMdNavBarController.prototype._getSelectedTab = function() {\n  return this._findTab(function(tab) {\n    return tab.isSelected();\n  });\n};\n\n/**\n * Returns the focused tab.\n * @return {MdNavItemController}\n */\nMdNavBarController.prototype.getFocusedTab = function() {\n  return this._findTab(function(tab) {\n    return tab.hasFocus();\n  });\n};\n\n/**\n * Find a tab that matches the specified function, starting from the first tab.\n * @param {Function} fn\n * @param {number=} startIndex index to start at. Defaults to 0.\n * @returns {MdNavItemController|null}\n * @private\n */\nMdNavBarController.prototype._findTab = function(fn, startIndex) {\n  var tabs = this._getTabs(), i;\n  if (startIndex == null) {\n    startIndex = 0;\n  }\n  for (i = startIndex; i < tabs.length; i++) {\n    if (fn(tabs[i])) {\n      return tabs[i];\n    }\n  }\n  return null;\n};\n\n/**\n * Find a tab that matches the specified function, going backwards from the end of the list.\n * @param {Function} fn\n * @param {number=} startIndex index to start at. Defaults to tabs.length - 1.\n * @returns {MdNavItemController}\n * @private\n */\nMdNavBarController.prototype._findTabReverse = function(fn, startIndex) {\n  var tabs = this._getTabs();\n  if (startIndex === undefined || startIndex === null) {\n    startIndex = tabs.length - 1;\n  }\n  for (var i = startIndex; i >= 0 ; i--) {\n    if (fn(tabs[i])) {\n      return tabs[i];\n    }\n  }\n  return null;\n};\n\n/**\n * Direct focus to the selected tab when focus enters the nav bar.\n */\nMdNavBarController.prototype.onFocus = function() {\n  var tab = this._getSelectedTab();\n  if (tab && !tab.isFocused) {\n    tab.setFocused(true);\n  }\n};\n\n/**\n * Move focus from oldTab to newTab.\n * @param {!MdNavItemController} oldTab\n * @param {!MdNavItemController} newTab\n * @private\n */\nMdNavBarController.prototype._moveFocus = function(oldTab, newTab) {\n  oldTab.setFocused(false);\n  newTab.setFocused(true);\n};\n\n/**\n * Focus the first tab.\n * @private\n */\nMdNavBarController.prototype._focusFirstTab = function() {\n  var tabs = this._getTabs();\n  if (!tabs) return;\n  var tabToFocus = this._findTab(function(tab) {\n    return tab._isEnabled();\n  });\n  if (tabToFocus) {\n    this._moveFocus(this.getFocusedTab(), tabToFocus);\n  }\n};\n\n/**\n * Focus the last tab.\n * @private\n */\nMdNavBarController.prototype._focusLastTab = function() {\n  var tabs = this._getTabs();\n  if (!tabs) return;\n  var tabToFocus = this._findTabReverse(function(tab) {\n    return tab._isEnabled();\n  });\n  if (tabToFocus) {\n    this._moveFocus(this.getFocusedTab(), tabToFocus);\n  }\n};\n\n/**\n * Focus the next non-disabled tab.\n * @param {number} focusedTabIndex the index of the currently focused tab\n * @private\n */\nMdNavBarController.prototype._focusNextTab = function(focusedTabIndex) {\n  var tabs = this._getTabs();\n  if (!tabs) return;\n  var tabToFocus = this._findTab(function(tab) {\n    return tab._isEnabled();\n  }, focusedTabIndex + 1);\n  if (tabToFocus) {\n    this._moveFocus(this.getFocusedTab(), tabToFocus);\n  } else {\n    this._focusFirstTab();\n  }\n};\n\n/**\n * Focus the previous non-disabled tab.\n * @param {number} focusedTabIndex the index of the currently focused tab\n * @private\n */\nMdNavBarController.prototype._focusPreviousTab = function(focusedTabIndex) {\n  var tabs = this._getTabs();\n  if (!tabs) return;\n  var tabToFocus = this._findTabReverse(function(tab) {\n    return tab._isEnabled();\n  }, focusedTabIndex - 1);\n  if (tabToFocus) {\n    this._moveFocus(this.getFocusedTab(), tabToFocus);\n  } else {\n    this._focusLastTab();\n  }\n};\n\n/**\n * Responds to keydown events.\n * Calls to preventDefault() stop the page from scrolling when changing focus in the nav-bar.\n * @param {!KeyboardEvent} e\n */\nMdNavBarController.prototype.onKeydown = function(e) {\n  var keyCodes = this._$mdConstant.KEY_CODE;\n  var tabs = this._getTabs();\n  var focusedTab = this.getFocusedTab();\n  if (!focusedTab || !tabs) return;\n\n  var focusedTabIndex = tabs.indexOf(focusedTab);\n\n  // use arrow keys to navigate between tabs\n  switch (e.keyCode) {\n    case keyCodes.UP_ARROW:\n    case keyCodes.LEFT_ARROW:\n      e.preventDefault();\n      this._focusPreviousTab(focusedTabIndex);\n      break;\n    case keyCodes.DOWN_ARROW:\n    case keyCodes.RIGHT_ARROW:\n      e.preventDefault();\n      this._focusNextTab(focusedTabIndex);\n      break;\n    case keyCodes.SPACE:\n    case keyCodes.ENTER:\n      // timeout to avoid a \"digest already in progress\" console error\n      this._$timeout(function() {\n        focusedTab.getButtonEl().click();\n      });\n      break;\n    case keyCodes.HOME:\n      e.preventDefault();\n      this._focusFirstTab();\n      break;\n    case keyCodes.END:\n      e.preventDefault();\n      this._focusLastTab();\n      break;\n  }\n};\n\n/**\n * @ngdoc directive\n * @name mdNavItem\n * @module material.components.navBar\n *\n * @restrict E\n *\n * @description\n * `<md-nav-item>` describes a page navigation link within the `<md-nav-bar>` component.\n * It renders an `<md-button>` as the actual link.\n *\n * Exactly one of the `md-nav-click`, `md-nav-href`, or `md-nav-sref` attributes are required\n * to be specified.\n *\n * @param {string=} nav-item-aria-label Allows setting or overriding the label that is announced by\n *     a screen reader for the nav item's button. If this is not set, the nav item's transcluded\n *     content will be announced. Make sure to set this if the nav item's transcluded content does\n *     not include descriptive text, for example only an icon.\n * @param {expression=} md-nav-click Expression which will be evaluated when the\n *     link is clicked to change the page. Renders as an `ng-click`.\n * @param {string=} md-nav-href url to transition to when this link is clicked.\n *     Renders as an `ng-href`.\n * @param {string=} md-nav-sref UI-Router state to transition to when this link is\n *     clicked. Renders as a `ui-sref`.\n * @param {string} name The name of this link. Used by the nav bar to know\n *     which link is currently selected.\n * @param {!object=} sref-opts UI-Router options that are passed to the `$state.go()` function. See\n *     the <a ng-href=\"https://ui-router.github.io/docs/latest/interfaces/transition.transitionoptions.html\"\n *     target=\"_blank\">UI-Router documentation for details</a>.\n *\n * @usage\n * See <a ng-href=\"api/directive/mdNavBar\">md-nav-bar</a> for usage.\n */\n/**\n * @param $mdAria\n * @param $$rAF\n * @param $mdUtil\n * @param $window\n * @constructor\n * @ngInject\n */\nfunction MdNavItem($mdAria, $$rAF, $mdUtil, $window) {\n  return {\n    restrict: 'E',\n    require: ['mdNavItem', '^mdNavBar'],\n    controller: MdNavItemController,\n    bindToController: true,\n    controllerAs: 'ctrl',\n    replace: true,\n    transclude: true,\n    template: function(tElement, tAttrs) {\n      var hasNavClick = tAttrs.mdNavClick;\n      var hasNavHref = tAttrs.mdNavHref;\n      var hasNavSref = tAttrs.mdNavSref;\n      var hasSrefOpts = tAttrs.srefOpts;\n      var navigationAttribute;\n      var navigationOptions;\n      var buttonTemplate;\n\n      // Cannot specify more than one nav attribute\n      if ((hasNavClick ? 1 : 0) + (hasNavHref ? 1 : 0) + (hasNavSref ? 1 : 0) > 1) {\n        throw Error(\n          'Please do not specify more than one of the md-nav-click, md-nav-href, ' +\n          'or md-nav-sref attributes per nav-item directive.'\n        );\n      }\n\n      if (hasNavClick !== undefined && hasNavClick !== null) {\n        navigationAttribute = 'ng-click=\"ctrl.mdNavClick()\"';\n      } else if (hasNavHref !== undefined && hasNavHref !== null) {\n        navigationAttribute = 'ng-href=\"{{ctrl.mdNavHref}}\"';\n      } else if (hasNavSref !== undefined && hasNavSref !== null) {\n        navigationAttribute = 'ui-sref=\"{{ctrl.mdNavSref}}\"';\n      } else {\n        throw Error(\n          'Please specify at least one of the md-nav-click, md-nav-href, or md-nav-sref ' +\n          'attributes per nav-item directive.');\n      }\n\n      navigationOptions = hasSrefOpts ? 'ui-sref-opts=\"{{ctrl.srefOpts}}\" ' : '';\n\n      if (navigationAttribute) {\n        buttonTemplate = '' +\n          '<md-button class=\"_md-nav-button md-accent\" ' +\n            'ng-class=\"ctrl.getNgClassMap()\" ' +\n            'ng-blur=\"ctrl.setFocused(false)\" ' +\n            'ng-disabled=\"ctrl.disabled\" ' +\n            'tabindex=\"-1\" ' +\n            'role=\"tab\" ' +\n            'ng-attr-aria-label=\"{{ctrl.navItemAriaLabel ? ctrl.navItemAriaLabel : undefined}}\" ' +\n            'aria-selected=\"{{ctrl.isSelected()}}\" ' +\n            navigationOptions +\n            navigationAttribute + '>' +\n            '<span ng-transclude class=\"_md-nav-button-text\"></span>' +\n          '</md-button>';\n      }\n\n      return '' +\n        '<li class=\"md-nav-item\" ' +\n          'role=\"presentation\">' +\n          (buttonTemplate || '') +\n        '</li>';\n    },\n    scope: {\n      'mdNavClick': '&?',\n      'mdNavHref': '@?',\n      'mdNavSref': '@?',\n      'srefOpts': '=?',\n      'name': '@',\n      'navItemAriaLabel': '@?',\n    },\n    link: function(scope, element, attrs, controllers) {\n      var disconnect;\n      var mdNavItem;\n      var mdNavBar;\n      var navButton;\n\n      // When accessing the element's contents synchronously, they\n      // may not be defined yet because of transclusion. There is a higher\n      // chance that it will be accessible if we wait one frame.\n      $$rAF(function() {\n        mdNavItem = controllers[0];\n        mdNavBar = controllers[1];\n        navButton = angular.element(element[0].querySelector('._md-nav-button'));\n\n        if (!mdNavItem.name) {\n          mdNavItem.name = angular.element(element[0]\n              .querySelector('._md-nav-button-text')).text().trim();\n        }\n\n        navButton.on('keydown', function($event) {\n          mdNavBar.onKeydown($event);\n        });\n\n        navButton.on('focus', function() {\n          mdNavItem._focused = true;\n        });\n\n        navButton.on('click', function() {\n          // This triggers a watcher on mdNavBar.mdSelectedNavItem which calls\n          // MdNavBarController._updateTabs() after a $timeout. That function calls\n          // MdNavItemController.setSelected() for the old tab with false and the new tab with true.\n          mdNavBar.mdSelectedNavItem = mdNavItem.name;\n          scope.$apply();\n        });\n\n        // Get the disabled attribute value first, then setup observing of value changes\n        mdNavItem.disabled = $mdUtil.parseAttributeBoolean(attrs['disabled'], false);\n        if ('MutationObserver' in $window) {\n          var config = {attributes: true, attributeFilter: ['disabled']};\n          var targetNode = element[0];\n          var mutationCallback = function(mutationList) {\n            $mdUtil.nextTick(function() {\n              mdNavItem.disabled = $mdUtil.parseAttributeBoolean(attrs[mutationList[0].attributeName], false);\n            });\n          };\n          var observer = new MutationObserver(mutationCallback);\n          observer.observe(targetNode, config);\n          disconnect = observer.disconnect.bind(observer);\n        } else {\n          attrs.$observe('disabled', function (value) {\n            mdNavItem.disabled = $mdUtil.parseAttributeBoolean(value, false);\n          });\n        }\n\n        if (!mdNavItem.navItemAriaLabel) {\n          $mdAria.expectWithText(navButton, 'aria-label');\n        }\n      });\n\n      scope.$on('destroy', function() {\n        navButton.off('keydown');\n        navButton.off('focus');\n        navButton.off('click');\n        disconnect();\n      });\n    }\n  };\n}\n\n/**\n * Controller for the nav-item component.\n * @param {!JQLite} $element\n * @constructor\n * @final\n * @ngInject\n */\nfunction MdNavItemController($element) {\n\n  /**\n   * @private @const\n   * @type {!JQLite}\n   */\n  this._$element = $element;\n\n  // Data-bound variables\n\n  /**\n   * @const\n   * @type {?Function}\n   */\n  this.mdNavClick;\n\n  /**\n   * @const\n   * @type {?string}\n   */\n  this.mdNavHref;\n\n  /**\n   * @const\n   * @type {?string}\n   */\n  this.mdNavSref;\n  /**\n   * @const\n   * @type {?Object}\n   */\n  this.srefOpts;\n  /**\n   * @const\n   * @type {?string}\n   */\n  this.name;\n\n  /**\n   * @const\n   * @type {string}\n   */\n  this.navItemAriaLabel;\n\n  // State variables\n  /**\n   * @private\n   * @type {boolean}\n   */\n  this._selected = false;\n\n  /**\n   * @type {boolean}\n   */\n  this.isFocused = false;\n}\n\n/**\n * Returns a map of class names and values for use by ng-class.\n * @return {!Object<string,boolean>}\n */\nMdNavItemController.prototype.getNgClassMap = function() {\n  return {\n    'md-active': this._selected,\n    'md-primary': this._selected,\n    'md-unselected': !this._selected,\n    'md-focused': this.isFocused,\n  };\n};\n\n/**\n * Get the name attribute of the tab.\n * @return {string}\n */\nMdNavItemController.prototype.getName = function() {\n  return this.name;\n};\n\n/**\n * Get the button element associated with the tab.\n * @return {!Element}\n */\nMdNavItemController.prototype.getButtonEl = function() {\n  return this._$element[0].querySelector('._md-nav-button');\n};\n\n/**\n * Set the selected state of the tab and updates the tabindex.\n * This function is called for the oldTab and newTab when selection changes.\n * @param {boolean} isSelected true to select the tab, false to deselect the tab\n */\nMdNavItemController.prototype.setSelected = function(isSelected) {\n  this._selected = isSelected;\n  if (isSelected) {\n    // https://www.w3.org/TR/wai-aria-practices/examples/tabs/tabs-2/tabs.html suggests that we call\n    // removeAttribute('tabindex') here, but that causes our unit tests to fail due to\n    // document.activeElement staying set to the body instead of the focused nav button.\n    this.getButtonEl().setAttribute('tabindex', '0');\n  } else {\n    this.getButtonEl().setAttribute('tabindex', '-1');\n  }\n};\n\n/**\n * @return {boolean}\n */\nMdNavItemController.prototype.isSelected = function() {\n  return this._selected;\n};\n\n/**\n * Set the focused state of the tab.\n * @param {boolean} isFocused\n */\nMdNavItemController.prototype.setFocused = function(isFocused) {\n  this.isFocused = isFocused;\n\n  if (isFocused) {\n    this.getButtonEl().focus();\n  }\n};\n\n/**\n * @return {boolean} true if the tab has focus, false if not.\n */\nMdNavItemController.prototype.hasFocus = function() {\n  return this.isFocused;\n};\n\n/**\n * @return {boolean} true if the tab is enabled, false if disabled.\n * @private\n */\nMdNavItemController.prototype._isEnabled = function() {\n  return !this._$element.attr('disabled');\n};\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.panel\n */\nMdPanelService.$inject = [\"presets\", \"$rootElement\", \"$rootScope\", \"$injector\", \"$window\"];\nangular\n  .module('material.components.panel', [\n    'material.core',\n    'material.components.backdrop'\n  ])\n  .provider('$mdPanel', MdPanelProvider);\n\n\n/*****************************************************************************\n *                            PUBLIC DOCUMENTATION                           *\n *****************************************************************************/\n\n\n/**\n * @ngdoc service\n * @name $mdPanelProvider\n * @module material.components.panel\n *\n * @description\n * `$mdPanelProvider` allows users to create configuration presets that will be\n * stored within a cached presets object. When the configuration is needed, the\n * user can request the preset by passing it as the first parameter in the\n * `$mdPanel.create` or `$mdPanel.open` methods.\n *\n * @usage\n * <hljs lang=\"js\">\n * (function(angular, undefined) {\n *   'use strict';\n *\n *   angular\n *       .module('demoApp', ['ngMaterial'])\n *       .config(DemoConfig)\n *       .controller('DemoCtrl', DemoCtrl)\n *       .controller('DemoMenuCtrl', DemoMenuCtrl);\n *\n *   function DemoConfig($mdPanelProvider) {\n *     $mdPanelProvider.definePreset('demoPreset', {\n *       attachTo: angular.element(document.body),\n *       controller: DemoMenuCtrl,\n *       controllerAs: 'ctrl',\n *       template: '' +\n *           '<div class=\"menu-panel\" md-whiteframe=\"4\">' +\n *           '  <div class=\"menu-content\">' +\n *           '    <div class=\"menu-item\" ng-repeat=\"item in ctrl.items\">' +\n *           '      <button class=\"md-button\">' +\n *           '        <span>{{item}}</span>' +\n *           '      </button>' +\n *           '    </div>' +\n *           '    <md-divider></md-divider>' +\n *           '    <div class=\"menu-item\">' +\n *           '      <button class=\"md-button\" ng-click=\"ctrl.closeMenu()\">' +\n *           '        <span>Close Menu</span>' +\n *           '      </button>' +\n *           '    </div>' +\n *           '  </div>' +\n *           '</div>',\n *       panelClass: 'menu-panel-container',\n *       focusOnOpen: false,\n *       zIndex: 100,\n *       propagateContainerEvents: true,\n *       groupName: 'menus'\n *     });\n *   }\n *\n *   function PanelProviderCtrl($mdPanel) {\n *     this.navigation = {\n *       name: 'navigation',\n *       items: [\n *         'Home',\n *         'About',\n *         'Contact'\n *       ]\n *     };\n *     this.favorites = {\n *       name: 'favorites',\n *       items: [\n *         'Add to Favorites'\n *       ]\n *     };\n *     this.more = {\n *       name: 'more',\n *       items: [\n *         'Account',\n *         'Sign Out'\n *       ]\n *     };\n *\n *     $mdPanel.newPanelGroup('menus', {\n *       maxOpen: 2\n *     });\n *\n *     this.showMenu = function($event, menu) {\n *       $mdPanel.open('demoPreset', {\n *         id: 'menu_' + menu.name,\n *         position: $mdPanel.newPanelPosition()\n *             .relativeTo($event.target)\n *             .addPanelPosition(\n *               $mdPanel.xPosition.ALIGN_START,\n *               $mdPanel.yPosition.BELOW\n *             ),\n *         locals: {\n *           items: menu.items\n *         },\n *         openFrom: $event\n *       });\n *     };\n *   }\n *\n *   function PanelMenuCtrl(mdPanelRef) {\n *     // 'mdPanelRef' is injected in the controller.\n *     this.closeMenu = function() {\n *       if (mdPanelRef) {\n *         mdPanelRef.close();\n *       }\n *     };\n *   }\n * })(angular);\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdPanelProvider#definePreset\n * @description\n * Takes the passed in preset name and preset configuration object and adds it\n * to the `_presets` object of the provider. This `_presets` object is then\n * passed along to the `$mdPanel` service.\n *\n * @param {string} name Preset name.\n * @param {!Object} preset Specific configuration object that can contain any\n *     and all of the parameters available within the `$mdPanel.create` method.\n *     However, parameters that pertain to id, position, animation, and user\n *     interaction are not allowed and will be removed from the preset\n *     configuration.\n */\n\n\n/*****************************************************************************\n *                               MdPanel Service                             *\n *****************************************************************************/\n\n\n/**\n * @ngdoc service\n * @name $mdPanel\n * @module material.components.panel\n *\n * @description\n * `$mdPanel` is a robust, low-level service for creating floating panels on\n * the screen. It can be used to implement tooltips, dialogs, pop-ups, etc.\n *\n * The following types, referenced below, have separate documentation:\n * - <a ng-href=\"api/type/MdPanelAnimation\">MdPanelAnimation</a> from `$mdPanel.newPanelAnimation()`\n * - <a ng-href=\"api/type/MdPanelPosition\">MdPanelPosition</a> from `$mdPanel.newPanelPosition()`\n * - <a ng-href=\"api/type/MdPanelRef\">MdPanelRef</a> from the `$mdPanel.open()` Promise or\n * injected in the panel's controller\n *\n * @usage\n * <hljs lang=\"js\">\n * (function(angular, undefined) {\n *   'use strict';\n *\n *   angular\n *       .module('demoApp', ['ngMaterial'])\n *       .controller('DemoDialogController', DialogController)\n *       .controller('DemoCtrl', function($mdPanel) {\n *\n *     var panelRef;\n *\n *     function showPanel($event) {\n *       var panelPosition = $mdPanel.newPanelPosition()\n *           .absolute()\n *           .top('50%')\n *           .left('50%');\n *\n *       var panelAnimation = $mdPanel.newPanelAnimation()\n *           .openFrom($event)\n *           .duration(200)\n *           .closeTo('.show-button')\n *           .withAnimation($mdPanel.animation.SCALE);\n *\n *       var config = {\n *         attachTo: angular.element(document.body),\n *         controller: DialogController,\n *         controllerAs: 'ctrl',\n *         position: panelPosition,\n *         animation: panelAnimation,\n *         targetEvent: $event,\n *         templateUrl: 'dialog-template.html',\n *         clickOutsideToClose: true,\n *         escapeToClose: true,\n *         focusOnOpen: true\n *       };\n *\n *       $mdPanel.open(config)\n *           .then(function(result) {\n *             panelRef = result;\n *           });\n *     }\n *   }\n *\n *   function DialogController(MdPanelRef) {\n *     function closeDialog() {\n *       if (MdPanelRef) MdPanelRef.close();\n *     }\n *   }\n * })(angular);\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdPanel#create\n * @description\n * Creates a panel with the specified options.\n *\n * @param {!Object=} config Specific configuration object that may contain the\n *     following properties:\n *\n *   - `id` - `{string=}`: An ID to track the panel by. When an ID is provided,\n *     the created panel is added to a tracked panels object. Any subsequent\n *     requests made to create a panel with that ID are ignored. This is useful\n *     in having the panel service not open multiple panels from the same user\n *     interaction when there is no backdrop and events are propagated. Defaults\n *     to an arbitrary string that is not tracked.\n *   - `template` - `{string=}`: HTML template to show in the panel. This\n *     **must** be trusted HTML with respect to AngularJS’s\n *     [$sce service](https://docs.angularjs.org/api/ng/service/$sce).\n *   - `templateUrl` - `{string=}`: The URL that will be used as the content of\n *     the panel.\n *   - `contentElement` - `{(string|!JQLite|!Element)=}`: Pre-compiled\n *     element to be used as the panel's content.\n *   - `controller` - `{(function|string)=}`: The controller to associate with\n *     the panel. The controller can inject a reference to the returned\n *     panelRef, which allows the panel to be closed, hidden, and shown. Any\n *     fields passed in through locals or resolve will be bound to the\n *     controller.\n *   - `controllerAs` - `{string=}`: An alias to assign the controller to on\n *     the scope.\n *   - `bindToController` - `{boolean=}`: Binds locals to the controller\n *     instead of passing them in. Defaults to true, as this is a best\n *     practice.\n *   - `locals` - `{Object=}`: An object containing key/value pairs. The keys\n *     will be used as names of values to inject into the controller. For\n *     example, `locals: {three: 3}` would inject `three` into the controller,\n *     with the value 3. 'mdPanelRef' is a reserved key, and will always\n *     be set to the created `MdPanelRef` instance.\n *   - `resolve` - `{Object=}`: Similar to locals, except it takes promises as\n *     values. The panel will not open until all of the promises resolve.\n *   - `attachTo` - `{(string|!JQLite|!Element)=}`: The element to\n *     attach the panel to. Defaults to appending to the root element of the\n *     application.\n *   - `propagateContainerEvents` - `{boolean=}`: Whether pointer or touch\n *     events should be allowed to propagate 'go through' the container, aka the\n *     wrapper, of the panel. Defaults to false.\n *   - `panelClass` - `{string=}`: A css class to apply to the panel element.\n *     This class should define any borders, box-shadow, etc. for the panel.\n *   - `zIndex` - `{number=}`: The z-index to place the panel at.\n *     Defaults to 80.\n *   - `position` - `{MdPanelPosition=}`: An MdPanelPosition object that\n *     specifies the alignment of the panel. For more information, see\n *     `MdPanelPosition`.\n *   - `clickOutsideToClose` - `{boolean=}`: Whether the user can click\n *     outside the panel to close it. Defaults to false.\n *   - `escapeToClose` - `{boolean=}`: Whether the user can press escape to\n *     close the panel. Defaults to false.\n *   - `onCloseSuccess` - `{function(!panelRef, string)=}`: Function that is\n *     called after the close successfully finishes. The first parameter passed\n *     into this function is the current panelRef and the 2nd is an optional\n *     string explaining the close reason. The currently supported closeReasons\n *     can be found in the `MdPanelRef.closeReasons` enum. These are by default\n *     passed along by the panel.\n *   - `trapFocus` - `{boolean=}`: Whether focus should be trapped within the\n *     panel. If `trapFocus` is true, the user will not be able to interact\n *     with the rest of the page until the panel is dismissed. Defaults to\n *     false.\n *   - `focusOnOpen` - `{boolean=}`: An option to override focus behavior on\n *     open. Only disable if focusing some other way, as focus management is\n *     required for panels to be accessible. Defaults to true.\n *   - `fullscreen` - `{boolean=}`: Whether the panel should be full screen.\n *     Applies the class `._md-panel-fullscreen` to the panel on open. Defaults\n *     to false.\n *   - `animation` - `{MdPanelAnimation=}`: An MdPanelAnimation object that\n *     specifies the animation of the panel. For more information, see\n *     `MdPanelAnimation`.\n *   - `hasBackdrop` - `{boolean=}`: Whether there should be an opaque backdrop\n *     behind the panel. Defaults to false.\n *   - `disableParentScroll` - `{boolean=}`: Whether the user can scroll the\n *     page behind the panel. Defaults to false.\n *   - `onDomAdded` - `{function=}`: Callback function used to announce when\n *     the panel is added to the DOM.\n *   - `onOpenComplete` - `{function=}`: Callback function used to announce\n *     when the open() action is finished.\n *   - `onRemoving` - `{function=}`: Callback function used to announce the\n *     close/hide() action is starting.\n *   - `onDomRemoved` - `{function=}`: Callback function used to announce when\n *     the panel is removed from the DOM.\n *   - `origin` - `{(string|!JQLite|!Element)=}`: The element to focus\n *     on when the panel closes. This is commonly the element which triggered\n *     the opening of the panel. If you do not use `origin`, you need to control\n *     the focus manually.\n *   - `groupName` - `{(string|!Array<string>)=}`: A group name or an array of\n *     group names. The group name is used for creating a group of panels. The\n *     group is used for configuring the number of open panels and identifying\n *     specific behaviors for groups. For instance, all tooltips could be\n *     identified using the same groupName.\n *\n * @returns {!MdPanelRef} panelRef\n */\n\n/**\n * @ngdoc method\n * @name $mdPanel#open\n * @description\n * Calls the create method above, then opens the panel. This is a shortcut for\n * creating and then calling open manually. If custom methods need to be\n * called when the panel is added to the DOM or opened, do not use this method.\n * Instead create the panel, chain promises on the domAdded and openComplete\n * methods, and call open from the returned panelRef.\n *\n * @param {!Object=} config Specific configuration object that may contain\n *     the properties defined in `$mdPanel.create`.\n * @returns {!Q.IPromise<!MdPanelRef>} panelRef A promise that resolves\n *     to an instance of the panel.\n */\n\n/**\n * @ngdoc method\n * @name $mdPanel#newPanelPosition\n * @description\n * Returns a new instance of the MdPanelPosition object. Use this to create\n * the position config object.\n *\n * @returns {!MdPanelPosition} panelPosition\n */\n\n/**\n * @ngdoc method\n * @name $mdPanel#newPanelAnimation\n * @description\n * Returns a new instance of the MdPanelAnimation object. Use this to create\n * the animation config object.\n *\n * @returns {!MdPanelAnimation} panelAnimation\n */\n\n/**\n * @ngdoc method\n * @name $mdPanel#setGroupMaxOpen\n * @description\n * Sets the maximum number of panels in a group that can be opened at a given\n * time.\n *\n * @param {string} groupName The name of the group to configure.\n * @param {number} maxOpen The maximum number of panels that can be\n *     opened. Infinity can be passed in to remove the maxOpen limit.\n */\n\n\n/*****************************************************************************\n *                                 MdPanelRef                                *\n *****************************************************************************/\n\n\n/**\n * @ngdoc type\n * @name MdPanelRef\n * @module material.components.panel\n * @description\n * A reference to a created panel. This reference contains a unique id for the\n * panel, along with the following properties:\n *\n *   - `id` - `{string}`: The unique id for the panel. This id is used to track\n *     when a panel was interacted with.\n *   - `config` - `{!Object=}`: The entire config object that was used in\n *     create.\n *   - `isAttached` - `{boolean}`: Whether the panel is attached to the DOM.\n *     Visibility to the user does not factor into isAttached.\n *   - `panelContainer` - `{JQLite}`: The wrapper element containing the\n *     panel. This property is added in order to have access to the `addClass`,\n *     `removeClass`, `toggleClass`, etc methods.\n *   - `panelEl` - `{JQLite}`: The panel element. This property is added\n *     in order to have access to the `addClass`, `removeClass`, `toggleClass`,\n *     etc methods.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#open\n * @description\n * Attaches and shows the panel.\n *\n * @returns {!Q.IPromise} A promise that is resolved when the panel is\n *     opened.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#close\n * @description\n * Hides and detaches the panel. Note that this will **not** destroy the panel.\n * If you don't intend on using the panel again, call the {@link #destroy\n * destroy} method afterwards.\n *\n * @returns {!Q.IPromise} A promise that is resolved when the panel is\n *     closed.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#attach\n * @description\n * Create the panel elements and attach them to the DOM. The panel will be\n * hidden by default.\n *\n * @returns {!Q.IPromise} A promise that is resolved when the panel is\n *     attached.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#detach\n * @description\n * Removes the panel from the DOM. This will NOT hide the panel before removing\n * it.\n *\n * @returns {!Q.IPromise} A promise that is resolved when the panel is\n *     detached.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#show\n * @description\n * Shows the panel.\n *\n * @returns {!Q.IPromise} A promise that is resolved when the panel has\n *     shown and animations are completed.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#hide\n * @description\n * Hides the panel.\n *\n * @returns {!Q.IPromise} A promise that is resolved when the panel has\n *     hidden and animations are completed.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#destroy\n * @description\n * Destroys the panel. The panel cannot be opened again after this is called.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#updatePosition\n * @description\n * Updates the position configuration of a panel. Use this to update the\n * position of a panel that is open, without having to close and re-open the\n * panel.\n *\n * @param {!MdPanelPosition} position\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#addToGroup\n * @description\n * Adds a panel to a group if the panel does not exist within the group already.\n * A panel can only exist within a single group.\n *\n * @param {string} groupName The name of the group to add the panel to.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#removeFromGroup\n * @description\n * Removes a panel from a group if the panel exists within that group. The group\n * must be created ahead of time.\n *\n * @param {string} groupName The name of the group.\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#registerInterceptor\n * @description\n * Registers an interceptor with the panel. The callback should return a promise,\n * which will allow the action to continue when it gets resolved, or will\n * prevent an action if it is rejected. The interceptors are called sequentially\n * and it reverse order. `type` must be one of the following\n * values available on `$mdPanel.interceptorTypes`:\n * * `CLOSE` - Gets called before the panel begins closing.\n *\n * @param {string} type Type of interceptor.\n * @param {!Q.IPromise<any>} callback Callback to be registered.\n * @returns {!MdPanelRef}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#removeInterceptor\n * @description\n * Removes a registered interceptor.\n *\n * @param {string} type Type of interceptor to be removed.\n * @param {function(): !Q.IPromise<any>} callback Interceptor to be removed.\n * @returns {!MdPanelRef}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#removeAllInterceptors\n * @description\n * Removes all interceptors. If a type is supplied, only the\n * interceptors of that type will be cleared.\n *\n * @param {string=} type Type of interceptors to be removed.\n * @returns {!MdPanelRef}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelRef#updateAnimation\n * @description\n * Updates the animation configuration for a panel. You can use this to change\n * the panel's animation without having to re-create it.\n *\n * @param {!MdPanelAnimation} animation\n */\n\n\n/*****************************************************************************\n *                               MdPanelPosition                            *\n *****************************************************************************/\n\n\n/**\n * @ngdoc type\n * @name MdPanelPosition\n * @module material.components.panel\n * @description\n *\n * Object for configuring the position of the panel.\n *\n * @usage\n *\n * #### Centering the panel\n *\n * <hljs lang=\"js\">\n * new MdPanelPosition().absolute().center();\n * </hljs>\n *\n * #### Overlapping the panel with an element\n *\n * <hljs lang=\"js\">\n * new MdPanelPosition()\n *     .relativeTo(someElement)\n *     .addPanelPosition(\n *       $mdPanel.xPosition.ALIGN_START,\n *       $mdPanel.yPosition.ALIGN_TOPS\n *     );\n * </hljs>\n *\n * #### Aligning the panel with the bottom of an element\n *\n * <hljs lang=\"js\">\n * new MdPanelPosition()\n *     .relativeTo(someElement)\n *     .addPanelPosition($mdPanel.xPosition.CENTER, $mdPanel.yPosition.BELOW);\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#absolute\n * @description\n * Positions the panel absolutely relative to the parent element. If the parent\n * is document.body, this is equivalent to positioning the panel absolutely\n * within the viewport.\n *\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#relativeTo\n * @description\n * Positions the panel relative to a specific element.\n *\n * @param {string|!Element|!JQLite} element Query selector, DOM element,\n *     or angular element to position the panel with respect to.\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#top\n * @description\n * Sets the value of `top` for the panel. Clears any previously set vertical\n * position.\n *\n * @param {string=} top Value of `top`. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#bottom\n * @description\n * Sets the value of `bottom` for the panel. Clears any previously set vertical\n * position.\n *\n * @param {string=} bottom Value of `bottom`. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#start\n * @description\n * Sets the panel to the start of the page - `left` if `ltr` or `right` for\n * `rtl`. Clears any previously set horizontal position.\n *\n * @param {string=} start Value of position. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#end\n * @description\n * Sets the panel to the end of the page - `right` if `ltr` or `left` for `rtl`.\n * Clears any previously set horizontal position.\n *\n * @param {string=} end Value of position. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#left\n * @description\n * Sets the value of `left` for the panel. Clears any previously set\n * horizontal position.\n *\n * @param {string=} left Value of `left`. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#right\n * @description\n * Sets the value of `right` for the panel. Clears any previously set\n * horizontal position.\n *\n * @param {string=} right Value of `right`. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#centerHorizontally\n * @description\n * Centers the panel horizontally in the viewport. Clears any previously set\n * horizontal position.\n *\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#centerVertically\n * @description\n * Centers the panel vertically in the viewport. Clears any previously set\n * vertical position.\n *\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#center\n * @description\n * Centers the panel horizontally and vertically in the viewport. This is\n * equivalent to calling both `centerHorizontally` and `centerVertically`.\n * Clears any previously set horizontal and vertical positions.\n *\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#addPanelPosition\n * @description\n * Sets the x and y position for the panel relative to another element. Can be\n * called multiple times to specify an ordered list of panel positions. The\n * first position which allows the panel to be completely on-screen will be\n * chosen; the last position will be chose whether it is on-screen or not.\n *\n * xPosition must be one of the following values available on\n * $mdPanel.xPosition:\n *\n *\n * CENTER | ALIGN_START | ALIGN_END | OFFSET_START | OFFSET_END\n *\n * <pre>\n *    *************\n *    *           *\n *    *   PANEL   *\n *    *           *\n *    *************\n *   A B    C    D E\n *\n * A: OFFSET_START (for LTR displays)\n * B: ALIGN_START (for LTR displays)\n * C: CENTER\n * D: ALIGN_END (for LTR displays)\n * E: OFFSET_END (for LTR displays)\n * </pre>\n *\n * yPosition must be one of the following values available on\n * $mdPanel.yPosition:\n *\n * CENTER | ALIGN_TOPS | ALIGN_BOTTOMS | ABOVE | BELOW\n *\n * <pre>\n *   F\n *   G *************\n *     *           *\n *   H *   PANEL   *\n *     *           *\n *   I *************\n *   J\n *\n * F: BELOW\n * G: ALIGN_TOPS\n * H: CENTER\n * I: ALIGN_BOTTOMS\n * J: ABOVE\n * </pre>\n *\n * @param {string} xPosition\n * @param {string} yPosition\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#withOffsetX\n * @description\n * Sets the value of the offset in the x-direction.\n *\n * @param {string|number} offsetX\n * @returns {!MdPanelPosition}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelPosition#withOffsetY\n * @description\n * Sets the value of the offset in the y-direction.\n *\n * @param {string|number} offsetY\n * @returns {!MdPanelPosition}\n */\n\n\n/*****************************************************************************\n *                               MdPanelAnimation                            *\n *****************************************************************************/\n\n\n/**\n * @ngdoc type\n * @name MdPanelAnimation\n * @module material.components.panel\n * @description\n * Animation configuration object. To use, create an MdPanelAnimation with the\n * desired properties, then pass the object as part of $mdPanel creation.\n *\n * @usage\n *\n * <hljs lang=\"js\">\n * var panelAnimation = new MdPanelAnimation()\n *     .openFrom(myButtonEl)\n *     .duration(1337)\n *     .closeTo('.my-button')\n *     .withAnimation($mdPanel.animation.SCALE);\n *\n * $mdPanel.create({\n *   animation: panelAnimation\n * });\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name MdPanelAnimation#openFrom\n * @description\n * Specifies where to start the open animation. `openFrom` accepts a\n * click event object, query selector, DOM element, or a Rect object that\n * is used to determine the bounds. When passed a click event, the location\n * of the click will be used as the position to start the animation.\n *\n * @param {string|!Element|!Event|{top: number, left: number}}\n * @returns {!MdPanelAnimation}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelAnimation#closeTo\n * @description\n * Specifies where to animate the panel close. `closeTo` accepts a\n * query selector, DOM element, or a Rect object that is used to determine\n * the bounds.\n *\n * @param {string|!Element|{top: number, left: number}}\n * @returns {!MdPanelAnimation}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelAnimation#withAnimation\n * @description\n * Specifies the animation class.\n *\n * There are several default animations that can be used: `$mdPanel.animation.`\n *  - `SLIDE`: The panel slides in and out from the specified\n *       elements. It will not fade in or out.\n *  - `SCALE`: The panel scales in and out. Slide and fade are\n *       included in this animation.\n *  - `FADE`: The panel fades in and out.\n *\n * Custom classes will by default fade in and out unless\n * `transition: opacity 1ms` is added to the to custom class.\n *\n * @param {string|{open: string, close: string}} cssClass\n * @returns {!MdPanelAnimation}\n */\n\n/**\n * @ngdoc method\n * @name MdPanelAnimation#duration\n * @description\n * Specifies the duration of the animation in milliseconds. The `duration`\n * method accepts either a number or an object with separate open and close\n * durations.\n *\n * @param {number|{open: number, close: number}} duration\n * @returns {!MdPanelAnimation}\n */\n\n\n/*****************************************************************************\n *                            PUBLIC DOCUMENTATION                           *\n *****************************************************************************/\n\n\nvar MD_PANEL_Z_INDEX = 80;\nvar MD_PANEL_HIDDEN = '_md-panel-hidden';\nvar FOCUS_TRAP_TEMPLATE = angular.element(\n    '<div class=\"_md-panel-focus-trap\" tabindex=\"0\"></div>');\n\nvar _presets = {};\n\n\n/**\n * A provider that is used for creating presets for the panel API.\n * @final @constructor @ngInject\n */\nfunction MdPanelProvider() {\n  return {\n    'definePreset': definePreset,\n    'getAllPresets': getAllPresets,\n    'clearPresets': clearPresets,\n    '$get': $getProvider()\n  };\n}\n\n\n/**\n * Takes the passed in panel configuration object and adds it to the `_presets`\n * object at the specified name.\n * @param {string} name Name of the preset to set.\n * @param {!Object} preset Specific configuration object that can contain any\n *     and all of the parameters available within the `$mdPanel.create` method.\n *     However, parameters that pertain to id, position, animation, and user\n *     interaction are not allowed and will be removed from the preset\n *     configuration.\n */\nfunction definePreset(name, preset) {\n  if (!name || !preset) {\n    throw new Error('mdPanelProvider: The panel preset definition is ' +\n        'malformed. The name and preset object are required.');\n  } else if (_presets.hasOwnProperty(name)) {\n    throw new Error('mdPanelProvider: The panel preset you have requested ' +\n        'has already been defined.');\n  }\n\n  // Delete any property on the preset that is not allowed.\n  delete preset.id;\n  delete preset.position;\n  delete preset.animation;\n\n  _presets[name] = preset;\n}\n\n\n/**\n * Gets a clone of the `_presets`.\n * @return {!Object}\n */\nfunction getAllPresets() {\n  return angular.copy(_presets);\n}\n\n\n/**\n * Clears all of the stored presets.\n */\nfunction clearPresets() {\n  _presets = {};\n}\n\n\n/**\n * Represents the `$get` method of the AngularJS provider. From here, a new\n * reference to the MdPanelService is returned where the needed arguments are\n * passed in including the MdPanelProvider `_presets`.\n * @param {!Object} _presets\n * @param {!JQLite} $rootElement\n * @param {!angular.Scope} $rootScope\n * @param {!IInjectorService} $injector\n * @param {!IWindowService} $window\n */\nfunction $getProvider() {\n  return [\n    '$rootElement', '$rootScope', '$injector', '$window',\n    function($rootElement, $rootScope, $injector, $window) {\n      return new MdPanelService(_presets, $rootElement, $rootScope,\n          $injector, $window);\n    }\n  ];\n}\n\n/**\n * @param {string|[]} value\n * @returns {[]} the input string wrapped in an Array or the original Array\n */\nfunction coerceToArray(value) {\n  if (angular.isString(value)) {\n    value = [value];\n  }\n  return value;\n}\n\n/*****************************************************************************\n *                               MdPanel Service                             *\n *****************************************************************************/\n\n\n/**\n * A service that is used for controlling/displaying panels on the screen.\n * @param {!Object} presets\n * @param {!JQLite} $rootElement\n * @param {!angular.Scope} $rootScope\n * @param {!IInjectorService} $injector\n * @param {!IWindowService} $window\n * @final @constructor @ngInject\n */\nfunction MdPanelService(presets, $rootElement, $rootScope, $injector, $window) {\n  /**\n   * Default config options for the panel.\n   * Anything angular related needs to be done later. Therefore\n   *     scope: $rootScope.$new(true),\n   *     attachTo: $rootElement,\n   * are added later.\n   * @private {!Object}\n   */\n  this._defaultConfigOptions = {\n    bindToController: true,\n    clickOutsideToClose: false,\n    disableParentScroll: false,\n    escapeToClose: false,\n    focusOnOpen: true,\n    fullscreen: false,\n    hasBackdrop: false,\n    propagateContainerEvents: false,\n    transformTemplate: angular.bind(this, this._wrapTemplate),\n    trapFocus: false,\n    zIndex: MD_PANEL_Z_INDEX\n  };\n\n  /** @private {!Object} */\n  this._config = {};\n\n  /** @private {!Object} */\n  this._presets = presets;\n\n  /** @private @const */\n  this._$rootElement = $rootElement;\n\n  /** @private @const */\n  this._$rootScope = $rootScope;\n\n  /** @private @const */\n  this._$injector = $injector;\n\n  /** @private @const */\n  this._$window = $window;\n\n  /** @private @const */\n  this._$mdUtil = this._$injector.get('$mdUtil');\n\n  /** @private {!Object<string, !MdPanelRef>} */\n  this._trackedPanels = {};\n\n  /**\n   * @private {!Object<string,\n   *     {panels: !Array<!MdPanelRef>,\n   *     openPanels: !Array<!MdPanelRef>,\n   *     maxOpen: number}>}\n   */\n  this._groups = Object.create(null);\n\n  /**\n   * Default animations that can be used within the panel.\n   * @type {enum}\n   */\n  this.animation = MdPanelAnimation.animation;\n\n  /**\n   * Possible values of xPosition for positioning the panel relative to\n   * another element.\n   * @type {enum}\n   */\n  this.xPosition = MdPanelPosition.xPosition;\n\n  /**\n   * Possible values of yPosition for positioning the panel relative to\n   * another element.\n   * @type {enum}\n   */\n  this.yPosition = MdPanelPosition.yPosition;\n\n  /**\n   * Possible values for the interceptors that can be registered on a panel.\n   * @type {enum}\n   */\n  this.interceptorTypes = MdPanelRef.interceptorTypes;\n\n  /**\n   * Possible values for closing of a panel.\n   * @type {enum}\n   */\n  this.closeReasons = MdPanelRef.closeReasons;\n\n  /**\n   * Possible values of absolute position.\n   * @type {enum}\n   */\n  this.absPosition = MdPanelPosition.absPosition;\n}\n\n\n/**\n * Creates a panel with the specified options.\n * @param {string|Object=} preset Name of a preset configuration that can be used to\n *     extend the panel configuration.\n * @param {!Object=} config Configuration object for the panel.\n * @returns {!MdPanelRef}\n */\nMdPanelService.prototype.create = function(preset, config) {\n  if (typeof preset === 'string') {\n    preset = this._getPresetByName(preset);\n  } else if (typeof preset === 'object' &&\n      (angular.isUndefined(config) || !config)) {\n    config = preset;\n    preset = {};\n  }\n\n  preset = preset || {};\n  config = config || {};\n\n  // If the passed-in config contains an ID and the ID is within _trackedPanels,\n  // return the tracked panel after updating its config with the passed-in\n  // config.\n  if (angular.isDefined(config.id) && this._trackedPanels[config.id]) {\n    var trackedPanel = this._trackedPanels[config.id];\n    angular.extend(trackedPanel.config, config);\n    return trackedPanel;\n  }\n\n  // Combine the passed-in config, the _defaultConfigOptions, and the preset\n  // configuration into the `_config`.\n  this._config = angular.extend({\n    // If no ID is set within the passed-in config, then create an arbitrary ID.\n    id: config.id || 'panel_' + this._$mdUtil.nextUid(),\n    scope: this._$rootScope.$new(true),\n    attachTo: this._$rootElement\n  }, this._defaultConfigOptions, config, preset);\n\n  // Create the panelRef and add it to the `_trackedPanels` object.\n  var panelRef = new MdPanelRef(this._config, this._$injector);\n  this._trackedPanels[this._config.id] = panelRef;\n\n  // Add the panel to each of its requested groups.\n  if (this._config.groupName) {\n    this._config.groupName = coerceToArray(this._config.groupName);\n    angular.forEach(this._config.groupName, function(group) {\n      panelRef.addToGroup(group);\n    });\n  }\n\n  this._config.scope.$on('$destroy', angular.bind(panelRef, panelRef.detach));\n\n  return panelRef;\n};\n\n\n/**\n * Creates and opens a panel with the specified options.\n * @param {string=} preset Name of a preset configuration that can be used to\n *     extend the panel configuration.\n * @param {!Object=} config Configuration object for the panel.\n * @returns {!Q.IPromise<!MdPanelRef>} The panel created from create.\n */\nMdPanelService.prototype.open = function(preset, config) {\n  var panelRef = this.create(preset, config);\n  return panelRef.open().then(function() {\n    return panelRef;\n  });\n};\n\n\n/**\n * Gets a specific preset configuration object saved within `_presets`.\n * @param {string} preset Name of the preset to search for.\n * @returns {!Object} The preset configuration object.\n */\nMdPanelService.prototype._getPresetByName = function(preset) {\n  if (!this._presets[preset]) {\n    throw new Error('mdPanel: The panel preset configuration that you ' +\n        'requested does not exist. Use the $mdPanelProvider to create a ' +\n        'preset before requesting one.');\n  }\n  return this._presets[preset];\n};\n\n\n/**\n * Returns a new instance of the MdPanelPosition. Use this to create the\n * positioning object.\n * @returns {!MdPanelPosition}\n */\nMdPanelService.prototype.newPanelPosition = function() {\n  return new MdPanelPosition(this._$injector);\n};\n\n\n/**\n * Returns a new instance of the MdPanelAnimation. Use this to create the\n * animation object.\n * @returns {!MdPanelAnimation}\n */\nMdPanelService.prototype.newPanelAnimation = function() {\n  return new MdPanelAnimation(this._$injector);\n};\n\n\n/**\n * @ngdoc method\n * @name $mdPanel#newPanelGroup\n * @description\n * Creates a panel group and adds it to a tracked list of panel groups.\n * @param {string} groupName Name of the group to create.\n * @param {{maxOpen: number}=} config Configuration object that may contain the following\n *  properties:\n *\n *   - `maxOpen`: The maximum number of panels that are allowed open within a defined panel group.\n *\n * @returns {!{panels: !Array<!MdPanelRef>, openPanels: !Array<!MdPanelRef>, maxOpen: number}}\n *  the new panel group\n */\nMdPanelService.prototype.newPanelGroup = function(groupName, config) {\n  if (!this._groups[groupName]) {\n    config = config || {};\n    this._groups[groupName] = {\n      panels: [],\n      openPanels: [],\n      maxOpen: config.maxOpen > 0 ? config.maxOpen : Infinity\n    };\n  }\n  return this._groups[groupName];\n};\n\n\n/**\n * Sets the maximum number of panels in a group that can be opened at a given\n * time.\n * @param {string} groupName The name of the group to configure.\n * @param {number} maxOpen The maximum number of panels that can be\n *     opened. Infinity can be passed in to remove the maxOpen limit.\n */\nMdPanelService.prototype.setGroupMaxOpen = function(groupName, maxOpen) {\n  if (this._groups[groupName]) {\n    this._groups[groupName].maxOpen = maxOpen;\n  } else {\n    throw new Error('mdPanel: Group does not exist yet. Call newPanelGroup().');\n  }\n};\n\n\n/**\n * Determines if the current number of open panels within a group exceeds the\n * limit of allowed open panels.\n * @param {string} groupName The name of the group to check.\n * @returns {boolean} true if open count does exceed maxOpen and false if not.\n * @private\n */\nMdPanelService.prototype._openCountExceedsMaxOpen = function(groupName) {\n  if (this._groups[groupName]) {\n    var group = this._groups[groupName];\n    return group.maxOpen > 0 && group.openPanels.length > group.maxOpen;\n  }\n  return false;\n};\n\n\n/**\n * Closes the first open panel within a specific group.\n * @param {string} groupName The name of the group.\n * @private\n */\nMdPanelService.prototype._closeFirstOpenedPanel = function(groupName) {\n  var group = this._groups[groupName];\n  if (group && group.openPanels.length) {\n    group.openPanels[0].close();\n  }\n};\n\n\n/**\n * Wraps the user's template in three elements:\n * - md-panel-outer-wrapper - covers the entire `attachTo` element.\n * - md-panel-inner-wrapper - handles the positioning.\n * - md-panel - contains the user's content and deals with the animations.\n * @param {string} origTemplate The original template.\n * @returns {string} The wrapped template.\n * @private\n */\nMdPanelService.prototype._wrapTemplate = function(origTemplate) {\n  var template = origTemplate || '';\n\n  // The panel should be initially rendered offscreen so we can calculate\n  // height and width for positioning.\n  return '' +\n      '<div class=\"md-panel-outer-wrapper\">' +\n        '<div class=\"md-panel-inner-wrapper _md-panel-offscreen\">' +\n          '<div class=\"md-panel _md-panel-offscreen\">' + template + '</div>' +\n        '</div>' +\n      '</div>';\n};\n\n\n/**\n * Wraps a content element in a `md-panel-outer-wrapper`, as well as\n * a `md-panel-inner-wrapper`, and positions it off-screen. Allows for\n * proper control over positioning and animations.\n * @param {!JQLite} contentElement Element to be wrapped.\n * @return {!JQLite} Wrapper element.\n * @private\n */\nMdPanelService.prototype._wrapContentElement = function(contentElement) {\n  var outerWrapper = angular.element(\n    '<div class=\"md-panel-outer-wrapper\">' +\n      '<div class=\"md-panel-inner-wrapper _md-panel-offscreen\"></div>' +\n    '</div>'\n  );\n\n  contentElement.addClass('md-panel _md-panel-offscreen');\n  outerWrapper.children().eq(0).append(contentElement);\n\n  return outerWrapper;\n};\n\n\n/*****************************************************************************\n *                                 MdPanelRef                                *\n *****************************************************************************/\n\n\n/**\n * A reference to a created panel. This reference contains a unique id for the\n * panel, along with properties/functions used to control the panel.\n * @param {!Object} config\n * @param {!IInjectorService} $injector\n * @final @constructor\n */\nfunction MdPanelRef(config, $injector) {\n  // Injected variables.\n  /** @private @const {!IQService} */\n  this._$q = $injector.get('$q');\n\n  /** @private @const {!angular.$mdCompiler} */\n  this._$mdCompiler = $injector.get('$mdCompiler');\n\n  /** @private @const {!angular.$mdConstant} */\n  this._$mdConstant = $injector.get('$mdConstant');\n\n  /** @private @const {!angular.$mdUtil} */\n  this._$mdUtil = $injector.get('$mdUtil');\n\n  /** @private @const {!angular.$mdTheming} */\n  this._$mdTheming = $injector.get('$mdTheming');\n\n  /** @private @const {!IRootScopeService} */\n  this._$rootScope = $injector.get('$rootScope');\n\n  /** @private @const {!angular.$animate} */\n  this._$animate = $injector.get('$animate');\n\n  /** @private @const {!MdPanelRef} */\n  this._$mdPanel = $injector.get('$mdPanel');\n\n  /** @private @const {!ILogService} */\n  this._$log = $injector.get('$log');\n\n  /** @private @const {!IWindowService} */\n  this._$window = $injector.get('$window');\n\n  /** @private @const {!Function} */\n  this._$$rAF = $injector.get('$$rAF');\n\n  // Public variables.\n  /**\n   * Unique id for the panelRef.\n   * @type {string}\n   */\n  this.id = config.id;\n\n  /** @type {!Object} */\n  this.config = config;\n\n  /** @type {!JQLite|undefined} */\n  this.panelContainer = undefined;\n\n  /** @type {!JQLite|undefined} */\n  this.panelEl = undefined;\n\n  /** @type {!JQLite|undefined} */\n  this.innerWrapper = undefined;\n\n  /**\n   * Whether the panel is attached. This is synchronous. When attach is called,\n   * isAttached is set to true. When detach is called, isAttached is set to\n   * false.\n   * @type {boolean}\n   */\n  this.isAttached = false;\n\n  // Private variables.\n  /** @private {Array<function()>} */\n  this._removeListeners = [];\n\n  /** @private {!JQLite|undefined} */\n  this._topFocusTrap = undefined;\n\n  /** @private {!JQLite|undefined} */\n  this._bottomFocusTrap = undefined;\n\n  /** @private {!$mdPanel|undefined} */\n  this._backdropRef = undefined;\n\n  /** @private {Function?} */\n  this._restoreScroll = null;\n\n  /**\n   * Keeps track of all the panel interceptors.\n   * @private {!Object}\n   */\n  this._interceptors = Object.create(null);\n\n  /**\n   * Cleanup function, provided by `$mdCompiler` and assigned after the element\n   * has been compiled. When `contentElement` is used, the function is used to\n   * restore the element to it's proper place in the DOM.\n   * @private {Function|null}\n   */\n  this._compilerCleanup = null;\n\n  /**\n   * Cache for saving and restoring element inline styles, CSS classes etc.\n   * @type {{styles: string, classes: string}}\n   */\n  this._restoreCache = {\n    styles: '',\n    classes: ''\n  };\n}\n\n\nMdPanelRef.interceptorTypes = {\n  CLOSE: 'onClose'\n};\n\n\n/**\n * Opens an already created and configured panel. If the panel is already\n * visible, does nothing.\n * @returns {!Q.IPromise<!MdPanelRef>} A promise that is resolved when\n *     the panel is opened and animations finish.\n */\nMdPanelRef.prototype.open = function() {\n  var self = this;\n  return this._$q(function(resolve, reject) {\n    var done = self._done(resolve, self);\n    var show = self._simpleBind(self.show, self);\n    var checkGroupMaxOpen = function() {\n      if (self.config.groupName) {\n        self.config.groupName = coerceToArray(self.config.groupName);\n        angular.forEach(self.config.groupName, function(group) {\n          if (self._$mdPanel._openCountExceedsMaxOpen(group)) {\n            self._$mdPanel._closeFirstOpenedPanel(group);\n          }\n        });\n      }\n    };\n\n    self.attach()\n        .then(show)\n        .then(checkGroupMaxOpen)\n        .then(done)\n        .catch(reject);\n  });\n};\n\n\n/**\n * Closes the panel.\n * @param {string} closeReason The event type that triggered the close.\n * @returns {!Q.IPromise<!MdPanelRef>} A promise that is resolved when\n *     the panel is closed and animations finish.\n */\nMdPanelRef.prototype.close = function(closeReason) {\n  var self = this;\n\n  return this._$q(function(resolve, reject) {\n    self._callInterceptors(MdPanelRef.interceptorTypes.CLOSE).then(function() {\n      var done = self._done(resolve, self);\n      var detach = self._simpleBind(self.detach, self);\n      var onCloseSuccess = self.config['onCloseSuccess'] || angular.noop;\n      onCloseSuccess = angular.bind(self, onCloseSuccess, self, closeReason);\n\n      self.hide()\n          .then(detach)\n          .then(done)\n          .then(onCloseSuccess)\n          .catch(reject);\n    }, reject);\n  });\n};\n\n\n/**\n * Attaches the panel. The panel will be hidden afterwards.\n * @returns {!Q.IPromise<!MdPanelRef>} A promise that is resolved when\n *     the panel is attached.\n */\nMdPanelRef.prototype.attach = function() {\n  if (this.isAttached && this.panelEl) {\n    return this._$q.when(this);\n  }\n\n  var self = this;\n  return this._$q(function(resolve, reject) {\n    var done = self._done(resolve, self);\n    var onDomAdded = self.config['onDomAdded'] || angular.noop;\n    var addListeners = function(response) {\n      self.isAttached = true;\n      self._addEventListeners();\n      return response;\n    };\n\n    self._$q.all([\n        self._createBackdrop(),\n        self._createPanel()\n            .then(addListeners)\n            .catch(reject)\n    ]).then(onDomAdded)\n      .then(done)\n      .catch(reject);\n  });\n};\n\n\n/**\n * Only detaches the panel. Will NOT hide the panel first.\n * @returns {!Q.IPromise<!MdPanelRef>} A promise that is resolved when\n *     the panel is detached.\n */\nMdPanelRef.prototype.detach = function() {\n  if (!this.isAttached) {\n    return this._$q.when(this);\n  }\n\n  var self = this;\n  var onDomRemoved = self.config['onDomRemoved'] || angular.noop;\n\n  var detachFn = function() {\n    self._removeEventListeners();\n\n    // Remove the focus traps that we added earlier for keeping focus within\n    // the panel.\n    if (self._topFocusTrap && self._topFocusTrap.parentNode) {\n      self._topFocusTrap.parentNode.removeChild(self._topFocusTrap);\n    }\n\n    if (self._bottomFocusTrap && self._bottomFocusTrap.parentNode) {\n      self._bottomFocusTrap.parentNode.removeChild(self._bottomFocusTrap);\n    }\n\n    if (self._restoreCache.classes) {\n      self.panelEl[0].className = self._restoreCache.classes;\n    }\n\n    // Either restore the saved styles or clear the ones set by mdPanel.\n    self.panelEl[0].style.cssText = self._restoreCache.styles || '';\n\n    self._compilerCleanup();\n    self.panelContainer.remove();\n    self.isAttached = false;\n    return self._$q.when(self);\n  };\n\n  if (this._restoreScroll) {\n    this._restoreScroll();\n    this._restoreScroll = null;\n  }\n\n  return this._$q(function(resolve, reject) {\n    var done = self._done(resolve, self);\n\n    self._$q.all([\n      detachFn(),\n      self._backdropRef ? self._backdropRef.detach() : true\n    ]).then(onDomRemoved)\n      .then(done)\n      .catch(reject);\n  });\n};\n\n\n/**\n * Destroys the panel. The Panel cannot be opened again after this.\n */\nMdPanelRef.prototype.destroy = function() {\n  var self = this;\n  if (this.config.groupName) {\n    this.config.groupName = coerceToArray(this.config.groupName);\n    angular.forEach(this.config.groupName, function(group) {\n      self.removeFromGroup(group);\n    });\n  }\n  this.config.scope.$destroy();\n  this.config.locals = null;\n  this.config.onDomAdded = null;\n  this.config.onDomRemoved = null;\n  this.config.onRemoving = null;\n  this.config.onOpenComplete = null;\n  this._interceptors = undefined;\n};\n\n\n/**\n * Shows the panel.\n * @returns {!Q.IPromise<!MdPanelRef>} A promise that is resolved when\n *     the panel has shown and animations finish.\n */\nMdPanelRef.prototype.show = function() {\n  if (!this.panelContainer) {\n    return this._$q(function(resolve, reject) {\n      reject('mdPanel: Panel does not exist yet. Call open() or attach().');\n    });\n  }\n\n  if (!this.panelContainer.hasClass(MD_PANEL_HIDDEN)) {\n    return this._$q.when(this);\n  }\n\n  var self = this;\n  var animatePromise = function() {\n    self.panelContainer.removeClass(MD_PANEL_HIDDEN);\n    return self._animateOpen();\n  };\n\n  return this._$q(function(resolve, reject) {\n    var done = self._done(resolve, self);\n    var onOpenComplete = self.config['onOpenComplete'] || angular.noop;\n    var addToGroupOpen = function() {\n      if (self.config.groupName) {\n        self.config.groupName = coerceToArray(self.config.groupName);\n        angular.forEach(self.config.groupName, function(group) {\n          group = self._$mdPanel._groups[group];\n          if (group) {\n            group.openPanels.push(self);\n          }\n        });\n      }\n    };\n\n    self._$q.all([\n      self._backdropRef ? self._backdropRef.show() : self,\n      animatePromise().then(function() { self._focusOnOpen(); }, reject)\n    ]).then(onOpenComplete)\n      .then(addToGroupOpen)\n      .then(done)\n      .catch(reject);\n  });\n};\n\n\n/**\n * Hides the panel.\n * @returns {!Q.IPromise<!MdPanelRef>} A promise that is resolved when\n *     the panel has hidden and animations finish.\n */\nMdPanelRef.prototype.hide = function() {\n  if (!this.panelContainer) {\n    return this._$q(function(resolve, reject) {\n      reject('mdPanel: Panel does not exist yet. Call open() or attach().');\n    });\n  }\n\n  if (this.panelContainer.hasClass(MD_PANEL_HIDDEN)) {\n    return this._$q.when(this);\n  }\n\n  var self = this;\n\n  return this._$q(function(resolve, reject) {\n    var done = self._done(resolve, self);\n    var onRemoving = self.config['onRemoving'] || angular.noop;\n    var hidePanel = function() {\n      self.panelContainer.addClass(MD_PANEL_HIDDEN);\n    };\n    var removeFromGroupOpen = function() {\n      if (self.config.groupName) {\n        var index;\n        self.config.groupName = coerceToArray(self.config.groupName);\n        angular.forEach(self.config.groupName, function(group) {\n          group = self._$mdPanel._groups[group];\n          index = group.openPanels.indexOf(self);\n          if (index > -1) {\n            group.openPanels.splice(index, 1);\n          }\n        });\n      }\n    };\n    var focusOnOrigin = function() {\n      var origin = self.config['origin'];\n      if (origin) {\n        getElement(origin).focus();\n      }\n    };\n\n    self._$q.all([\n      self._backdropRef ? self._backdropRef.hide() : self,\n      self._animateClose()\n          .then(onRemoving)\n          .then(hidePanel)\n          .then(removeFromGroupOpen)\n          .then(focusOnOrigin)\n          .catch(reject)\n    ]).then(done, reject);\n  });\n};\n\n/**\n * Compiles the panel, according to the passed in config and appends it to\n * the DOM. Helps normalize differences in the compilation process between\n * using a string template and a content element.\n * @returns {!Q.IPromise<!MdPanelRef>} Promise that is resolved when\n *     the element has been compiled and added to the DOM.\n * @private\n */\nMdPanelRef.prototype._compile = function() {\n  var self = this;\n\n  // Compile the element via $mdCompiler. Note that when using a\n  // contentElement, the element isn't actually being compiled, rather the\n  // compiler saves it's place in the DOM and provides a way of restoring it.\n  return self._$mdCompiler.compile(self.config).then(function(compileData) {\n    var config = self.config;\n\n    if (config.contentElement) {\n      var panelEl = compileData.element;\n\n      // Since mdPanel modifies the inline styles and CSS classes, we need\n      // to save them in order to be able to restore on close.\n      self._restoreCache.styles = panelEl[0].style.cssText;\n      self._restoreCache.classes = panelEl[0].className;\n\n      self.panelContainer = self._$mdPanel._wrapContentElement(panelEl);\n      self.panelEl = panelEl;\n    } else {\n      self.panelContainer = compileData.link(config['scope']);\n      self.panelEl = angular.element(\n        self.panelContainer[0].querySelector('.md-panel')\n      );\n    }\n\n    // Save a reference to the inner wrapper.\n    self.innerWrapper = angular.element(\n      self.panelContainer[0].querySelector('.md-panel-inner-wrapper')\n    );\n\n    // Save a reference to the cleanup function from the compiler.\n    self._compilerCleanup = compileData.cleanup;\n\n    // Attach the panel to the proper place in the DOM.\n    getElement(self.config['attachTo']).append(self.panelContainer);\n\n    return self;\n  });\n};\n\n\n/**\n * Creates a panel and adds it to the dom.\n * @returns {!Q.IPromise} A promise that is resolved when the panel is\n *     created.\n * @private\n */\nMdPanelRef.prototype._createPanel = function() {\n  var self = this;\n\n  return this._$q(function(resolve, reject) {\n    if (!self.config.locals) {\n      self.config.locals = {};\n    }\n\n    self.config.locals.mdPanelRef = self;\n\n    self._compile().then(function() {\n      if (self.config['disableParentScroll']) {\n        self._restoreScroll = self._$mdUtil.disableScrollAround(\n          null,\n          self.panelContainer,\n          { disableScrollMask: true }\n        );\n      }\n\n      // Add a custom CSS class to the panel element.\n      if (self.config['panelClass']) {\n        self.panelEl.addClass(self.config['panelClass']);\n      }\n\n      // Handle click and touch events for the panel container.\n      if (self.config['propagateContainerEvents']) {\n        self.panelContainer.css('pointer-events', 'none');\n        self.panelEl.css('pointer-events', 'all');\n      }\n\n      // Panel may be outside the $rootElement, tell ngAnimate to animate\n      // regardless.\n      if (self._$animate.pin) {\n        self._$animate.pin(\n          self.panelContainer,\n          getElement(self.config['attachTo'])\n        );\n      }\n\n      self._configureTrapFocus();\n      self._addStyles().then(function() {\n        resolve(self);\n      }, reject);\n    }, reject);\n\n  });\n};\n\n\n/**\n * Adds the styles for the panel, such as positioning and z-index. Also,\n * themes the panel element and panel container using `$mdTheming`.\n * @returns {!Q.IPromise<!MdPanelRef>}\n * @private\n */\nMdPanelRef.prototype._addStyles = function() {\n  var self = this;\n  return this._$q(function(resolve) {\n    self.panelContainer.css('z-index', self.config['zIndex']);\n    self.innerWrapper.css('z-index', self.config['zIndex'] + 1);\n\n    var hideAndResolve = function() {\n      // Theme the element and container.\n      self._setTheming();\n\n      // Remove offscreen classes and add hidden class.\n      self.panelEl.removeClass('_md-panel-offscreen');\n      self.innerWrapper.removeClass('_md-panel-offscreen');\n      self.panelContainer.addClass(MD_PANEL_HIDDEN);\n\n      resolve(self);\n    };\n\n    if (self.config['fullscreen']) {\n      self.panelEl.addClass('_md-panel-fullscreen');\n      hideAndResolve();\n      return; // Don't setup positioning.\n    }\n\n    var positionConfig = self.config['position'];\n    if (!positionConfig) {\n      hideAndResolve();\n      return; // Don't setup positioning.\n    }\n\n    // Wait for angular to finish processing the template\n    self._$rootScope['$$postDigest'](function() {\n      // Position it correctly. This is necessary so that the panel will have a\n      // defined height and width.\n      self._updatePosition(true);\n\n      // Theme the element and container.\n      self._setTheming();\n\n      resolve(self);\n    });\n  });\n};\n\n\n/**\n * Sets the `$mdTheming` classes on the `panelContainer` and `panelEl`.\n * @private\n */\nMdPanelRef.prototype._setTheming = function() {\n  this._$mdTheming(this.panelEl);\n  this._$mdTheming(this.panelContainer);\n};\n\n\n/**\n * Updates the position configuration of a panel\n * @param {!MdPanelPosition} position\n */\nMdPanelRef.prototype.updatePosition = function(position) {\n  if (!this.panelContainer) {\n    throw new Error(\n        'mdPanel: Panel does not exist yet. Call open() or attach().');\n  }\n\n  this.config['position'] = position;\n  this._updatePosition();\n};\n\n\n/**\n * Calculates and updates the position of the panel.\n * @param {boolean=} init\n * @private\n */\nMdPanelRef.prototype._updatePosition = function(init) {\n  var positionConfig = this.config['position'];\n\n  if (positionConfig) {\n    positionConfig._setPanelPosition(this.innerWrapper);\n\n    // Hide the panel now that position is known.\n    if (init) {\n      this.panelEl.removeClass('_md-panel-offscreen');\n      this.innerWrapper.removeClass('_md-panel-offscreen');\n      this.panelContainer.addClass(MD_PANEL_HIDDEN);\n    }\n\n    this.innerWrapper.css(\n      MdPanelPosition.absPosition.TOP,\n      positionConfig.getTop()\n    );\n    this.innerWrapper.css(\n      MdPanelPosition.absPosition.BOTTOM,\n      positionConfig.getBottom()\n    );\n    this.innerWrapper.css(\n      MdPanelPosition.absPosition.LEFT,\n      positionConfig.getLeft()\n    );\n    this.innerWrapper.css(\n      MdPanelPosition.absPosition.RIGHT,\n      positionConfig.getRight()\n    );\n  }\n};\n\n\n/**\n * Focuses on the panel or the first focus target.\n * @private\n */\nMdPanelRef.prototype._focusOnOpen = function() {\n  if (this.config['focusOnOpen']) {\n    // Wait for the template to finish rendering to guarantee md-autofocus has\n    // finished adding the class md-autofocus, otherwise the focusable element\n    // isn't available to focus.\n    var self = this;\n    this._$rootScope['$$postDigest'](function() {\n      var target = self._$mdUtil.findFocusTarget(self.panelEl) ||\n          self.panelEl;\n      target.focus();\n    });\n  }\n};\n\n\n/**\n * Shows the backdrop.\n * @returns {!Q.IPromise} A promise that is resolved when the backdrop\n *     is created and attached.\n * @private\n */\nMdPanelRef.prototype._createBackdrop = function() {\n  if (this.config.hasBackdrop) {\n    if (!this._backdropRef) {\n      var backdropAnimation = this._$mdPanel.newPanelAnimation()\n          .openFrom(this.config.attachTo)\n          .withAnimation({\n            open: '_md-opaque-enter',\n            close: '_md-opaque-leave'\n          });\n\n      if (this.config.animation) {\n        backdropAnimation.duration(this.config.animation._rawDuration);\n      }\n\n      var backdropConfig = {\n        animation: backdropAnimation,\n        attachTo: this.config.attachTo,\n        focusOnOpen: false,\n        panelClass: '_md-panel-backdrop',\n        zIndex: this.config.zIndex - 1\n      };\n\n      this._backdropRef = this._$mdPanel.create(backdropConfig);\n    }\n    if (!this._backdropRef.isAttached) {\n      return this._backdropRef.attach();\n    }\n  }\n};\n\n\n/**\n * Listen for escape keys and outside clicks to auto close.\n * @private\n */\nMdPanelRef.prototype._addEventListeners = function() {\n  this._configureEscapeToClose();\n  this._configureClickOutsideToClose();\n  this._configureScrollListener();\n};\n\n\n/**\n * Remove event listeners added in _addEventListeners.\n * @private\n */\nMdPanelRef.prototype._removeEventListeners = function() {\n  this._removeListeners && this._removeListeners.forEach(function(removeFn) {\n    removeFn();\n  });\n  this._removeListeners = [];\n};\n\n\n/**\n * Setup the escapeToClose event listeners.\n * @private\n */\nMdPanelRef.prototype._configureEscapeToClose = function() {\n  if (this.config['escapeToClose']) {\n    var parentTarget = getElement(this.config['attachTo']);\n    var self = this;\n\n    var keyHandlerFn = function(ev) {\n      if (ev.keyCode === self._$mdConstant.KEY_CODE.ESCAPE) {\n        ev.stopPropagation();\n        ev.preventDefault();\n\n        self.close(MdPanelRef.closeReasons.ESCAPE);\n      }\n    };\n\n    // Add keydown listeners\n    this.panelContainer.on('keydown', keyHandlerFn);\n    parentTarget.on('keydown', keyHandlerFn);\n\n    // Queue remove listeners function\n    this._removeListeners.push(function() {\n      self.panelContainer.off('keydown', keyHandlerFn);\n      parentTarget.off('keydown', keyHandlerFn);\n    });\n  }\n};\n\n\n/**\n * Setup the clickOutsideToClose event listeners.\n * @private\n */\nMdPanelRef.prototype._configureClickOutsideToClose = function() {\n  if (this.config['clickOutsideToClose']) {\n    var target = this.config['propagateContainerEvents'] ?\n        angular.element(document.body) :\n        this.panelContainer;\n    var sourceEl;\n\n    // Keep track of the element on which the mouse originally went down\n    // so that we can only close the backdrop when the 'click' started on it.\n    // A simple 'click' handler does not work, it sets the target object as the\n    // element the mouse went down on.\n    var mousedownHandler = function(ev) {\n      sourceEl = ev.target;\n    };\n\n    // We check if our original element and the target is the backdrop\n    // because if the original was the backdrop and the target was inside the\n    // panel we don't want to panel to close.\n    var self = this;\n    var mouseupHandler = function(ev) {\n      if (self.config['propagateContainerEvents']) {\n\n        // We check if the sourceEl of the event is the panel element or one\n        // of it's children. If it is not, then close the panel.\n        if (sourceEl !== self.panelEl[0] && !self.panelEl[0].contains(sourceEl)) {\n          self.close();\n        }\n\n      } else if (sourceEl === target[0] && ev.target === target[0]) {\n        ev.stopPropagation();\n        ev.preventDefault();\n\n        self.close(MdPanelRef.closeReasons.CLICK_OUTSIDE);\n      }\n    };\n\n    // Add listeners\n    target.on('mousedown', mousedownHandler);\n    target.on('mouseup', mouseupHandler);\n\n    // Queue remove listeners function\n    this._removeListeners.push(function() {\n      target.off('mousedown', mousedownHandler);\n      target.off('mouseup', mouseupHandler);\n    });\n  }\n};\n\n\n/**\n * Configures the listeners for updating the panel position on scroll.\n * @private\n*/\nMdPanelRef.prototype._configureScrollListener = function() {\n  // No need to bind the event if scrolling is disabled.\n  if (!this.config['disableParentScroll']) {\n    var updatePosition = angular.bind(this, this._updatePosition);\n    var debouncedUpdatePosition = this._$$rAF.throttle(updatePosition);\n    var self = this;\n\n    var onScroll = function() {\n      debouncedUpdatePosition();\n    };\n\n    // Add listeners.\n    this._$window.addEventListener('scroll', onScroll, true);\n\n    // Queue remove listeners function.\n    this._removeListeners.push(function() {\n      self._$window.removeEventListener('scroll', onScroll, true);\n    });\n  }\n};\n\n\n/**\n * Setup the focus traps. These traps will wrap focus when tabbing past the\n * panel. When shift-tabbing, the focus will stick in place.\n * @private\n */\nMdPanelRef.prototype._configureTrapFocus = function() {\n  // Focus doesn't remain inside of the panel without this.\n  this.panelEl.attr('tabIndex', '-1');\n  if (this.config['trapFocus']) {\n    var element = this.panelEl;\n    // Set up elements before and after the panel to capture focus and\n    // redirect back into the panel.\n    this._topFocusTrap = FOCUS_TRAP_TEMPLATE.clone()[0];\n    this._bottomFocusTrap = FOCUS_TRAP_TEMPLATE.clone()[0];\n\n    // When focus is about to move out of the panel, we want to intercept it\n    // and redirect it back to the panel element.\n    var focusHandler = function() {\n      element.focus();\n    };\n    this._topFocusTrap.addEventListener('focus', focusHandler);\n    this._bottomFocusTrap.addEventListener('focus', focusHandler);\n\n    // Queue remove listeners function\n    this._removeListeners.push(this._simpleBind(function() {\n      this._topFocusTrap.removeEventListener('focus', focusHandler);\n      this._bottomFocusTrap.removeEventListener('focus', focusHandler);\n    }, this));\n\n    // The top focus trap inserted immediately before the md-panel element (as\n    // a sibling). The bottom focus trap inserted immediately after the\n    // md-panel element (as a sibling).\n    element[0].parentNode.insertBefore(this._topFocusTrap, element[0]);\n    element.after(this._bottomFocusTrap);\n  }\n};\n\n\n/**\n * Updates the animation of a panel.\n * @param {!MdPanelAnimation} animation\n */\nMdPanelRef.prototype.updateAnimation = function(animation) {\n  this.config['animation'] = animation;\n\n  if (this._backdropRef) {\n    this._backdropRef.config.animation.duration(animation._rawDuration);\n  }\n};\n\n\n/**\n * Animate the panel opening.\n * @returns {!Q.IPromise} A promise that is resolved when the panel has\n *     animated open.\n * @private\n */\nMdPanelRef.prototype._animateOpen = function() {\n  this.panelContainer.addClass('md-panel-is-showing');\n  var animationConfig = this.config['animation'];\n  if (!animationConfig) {\n    // Promise is in progress, return it.\n    this.panelContainer.addClass('_md-panel-shown');\n    return this._$q.when(this);\n  }\n\n  var self = this;\n  return this._$q(function(resolve) {\n    var done = self._done(resolve, self);\n    var warnAndOpen = function() {\n      self._$log.warn(\n          'mdPanel: MdPanel Animations failed. ' +\n          'Showing panel without animating.');\n      done();\n    };\n\n    animationConfig.animateOpen(self.panelEl)\n        .then(done, warnAndOpen);\n  });\n};\n\n\n/**\n * Animate the panel closing.\n * @returns {!Q.IPromise} A promise that is resolved when the panel has animated closed.\n * @private\n */\nMdPanelRef.prototype._animateClose = function() {\n  var self = this;\n  var animationConfig = this.config['animation'];\n\n  if (!animationConfig) {\n    this.panelContainer.removeClass('md-panel-is-showing');\n    this.panelContainer.removeClass('_md-panel-shown');\n    return this._$q.when(this);\n  } else {\n    return this._$q(function (resolve) {\n      var done = function () {\n        self.panelContainer.removeClass('md-panel-is-showing');\n        // Remove the transform so that re-used panels don't accumulate transforms.\n        self.panelEl.css('transform', '');\n        resolve(self);\n      };\n      var warnAndClose = function () {\n        self._$log.warn(\n          'mdPanel: MdPanel Animations failed. Hiding panel without animating.');\n        done();\n      };\n\n      animationConfig.animateClose(self.panelEl).then(done, warnAndClose);\n    });\n  }\n};\n\n\n/**\n * Registers a interceptor with the panel. The callback should return a promise,\n * which will allow the action to continue when it gets resolved, or will\n * prevent an action if it is rejected.\n * @param {string} type Type of interceptor.\n * @param {!Q.IPromise<!any>} callback Callback to be registered.\n * @returns {!MdPanelRef}\n */\nMdPanelRef.prototype.registerInterceptor = function(type, callback) {\n  var error = null;\n\n  if (!angular.isString(type)) {\n    error = 'Interceptor type must be a string, instead got ' + typeof type;\n  } else if (!angular.isFunction(callback)) {\n    error = 'Interceptor callback must be a function, instead got ' + typeof callback;\n  }\n\n  if (error) {\n    throw new Error('MdPanel: ' + error);\n  }\n\n  var interceptors = this._interceptors[type] = this._interceptors[type] || [];\n\n  if (interceptors.indexOf(callback) === -1) {\n    interceptors.push(callback);\n  }\n\n  return this;\n};\n\n\n/**\n * Removes a registered interceptor.\n * @param {string} type Type of interceptor to be removed.\n * @param {Function} callback Interceptor to be removed.\n * @returns {!MdPanelRef}\n */\nMdPanelRef.prototype.removeInterceptor = function(type, callback) {\n  var index = this._interceptors[type] ?\n    this._interceptors[type].indexOf(callback) : -1;\n\n  if (index > -1) {\n    this._interceptors[type].splice(index, 1);\n  }\n\n  return this;\n};\n\n\n/**\n * Removes all interceptors.\n * @param {string=} type Type of interceptors to be removed.\n *     If ommited, all interceptors types will be removed.\n * @returns {!MdPanelRef}\n */\nMdPanelRef.prototype.removeAllInterceptors = function(type) {\n  if (type) {\n    this._interceptors[type] = [];\n  } else {\n    this._interceptors = Object.create(null);\n  }\n\n  return this;\n};\n\n\n/**\n * Invokes all the interceptors of a certain type sequantially in\n *     reverse order. Works in a similar way to `$q.all`, except it\n *     respects the order of the functions.\n * @param {string} type Type of interceptors to be invoked.\n * @returns {!Q.IPromise<!MdPanelRef>}\n * @private\n */\nMdPanelRef.prototype._callInterceptors = function(type) {\n  var self = this;\n  var $q = self._$q;\n  var interceptors = self._interceptors && self._interceptors[type] || [];\n\n  return interceptors.reduceRight(function(promise, interceptor) {\n    var isPromiseLike = interceptor && angular.isFunction(interceptor.then);\n    var response = isPromiseLike ? interceptor : null;\n\n    /**\n    * For interceptors to reject/cancel subsequent portions of the chain, simply\n    * return a `$q.reject(<value>)`\n    */\n    return promise.then(function() {\n      if (!response) {\n        try {\n          response = interceptor(self);\n        } catch (e) {\n          response = $q.reject(e);\n        }\n      }\n\n     return response;\n    });\n  }, $q.resolve(self));\n};\n\n\n/**\n * Faster, more basic than angular.bind\n * http://jsperf.com/angular-bind-vs-custom-vs-native\n * @param {function} callback\n * @param {!Object} self\n * @return {function} Callback function with a bound self.\n */\nMdPanelRef.prototype._simpleBind = function(callback, self) {\n  return function(value) {\n    return callback.apply(self, value);\n  };\n};\n\n\n/**\n * @param {function|IQResolveReject} callback\n * @param {!Object} self\n * @return {function} Callback function with a self param.\n */\nMdPanelRef.prototype._done = function(callback, self) {\n  return function() {\n    callback(self);\n  };\n};\n\n\n/**\n * Adds a panel to a group if the panel does not exist within the group already.\n * A panel can only exist within a single group.\n * @param {string} groupName The name of the group.\n */\nMdPanelRef.prototype.addToGroup = function(groupName) {\n  if (!this._$mdPanel._groups[groupName]) {\n    this._$mdPanel.newPanelGroup(groupName);\n  }\n\n  var group = this._$mdPanel._groups[groupName];\n  var index = group.panels.indexOf(this);\n\n  if (index < 0) {\n    group.panels.push(this);\n  }\n};\n\n\n/**\n * Removes a panel from a group if the panel exists within that group. The group\n * must be created ahead of time.\n * @param {string} groupName The name of the group.\n */\nMdPanelRef.prototype.removeFromGroup = function(groupName) {\n  if (!this._$mdPanel._groups[groupName]) {\n    throw new Error('mdPanel: The group ' + groupName + ' does not exist.');\n  }\n\n  var group = this._$mdPanel._groups[groupName];\n  var index = group.panels.indexOf(this);\n\n  if (index > -1) {\n    group.panels.splice(index, 1);\n  }\n};\n\n\n/**\n * Possible default closeReasons for the close function.\n * @enum {string}\n */\nMdPanelRef.closeReasons = {\n  CLICK_OUTSIDE: 'clickOutsideToClose',\n  ESCAPE: 'escapeToClose',\n};\n\n\n/*****************************************************************************\n *                               MdPanelPosition                             *\n *****************************************************************************/\n\n\n/**\n * Position configuration object. To use, create an MdPanelPosition with the\n * desired properties, then pass the object as part of $mdPanel creation.\n *\n * Example:\n *\n * var panelPosition = new MdPanelPosition()\n *     .relativeTo(myButtonEl)\n *     .addPanelPosition(\n *       $mdPanel.xPosition.CENTER,\n *       $mdPanel.yPosition.ALIGN_TOPS\n *     );\n *\n * $mdPanel.create({\n *   position: panelPosition\n * });\n *\n * @param {!IInjectorService} $injector\n * @final @constructor\n */\nfunction MdPanelPosition($injector) {\n  /** @private @const {!IWindowService} */\n  this._$window = $injector.get('$window');\n\n  /** @private {boolean} */\n  this._isRTL = $injector.get('$mdUtil').isRtl();\n\n  /** @private @const {!angular.$mdConstant} */\n  this._$mdConstant = $injector.get('$mdConstant');\n\n  /** @private {boolean} */\n  this._absolute = false;\n\n  /** @private {!JQLite} */\n  this._relativeToEl = undefined;\n\n  /** @private {string} */\n  this._top = '';\n\n  /** @private {string} */\n  this._bottom = '';\n\n  /** @private {string} */\n  this._left = '';\n\n  /** @private {string} */\n  this._right = '';\n\n  /** @private {!Array<string>} */\n  this._translateX = [];\n\n  /** @private {!Array<string>} */\n  this._translateY = [];\n\n  /** @private {!Array<{x:string, y:string}>} */\n  this._positions = [];\n\n  /** @private {?{x:string, y:string}} */\n  this._actualPosition = undefined;\n}\n\n\n/**\n * Possible values of xPosition.\n * @enum {string}\n */\nMdPanelPosition.xPosition = {\n  CENTER: 'center',\n  ALIGN_START: 'align-start',\n  ALIGN_END: 'align-end',\n  OFFSET_START: 'offset-start',\n  OFFSET_END: 'offset-end'\n};\n\n\n/**\n * Possible values of yPosition.\n * @enum {string}\n */\nMdPanelPosition.yPosition = {\n  CENTER: 'center',\n  ALIGN_TOPS: 'align-tops',\n  ALIGN_BOTTOMS: 'align-bottoms',\n  ABOVE: 'above',\n  BELOW: 'below'\n};\n\n\n/**\n * Possible values of absolute position.\n * @enum {string}\n */\nMdPanelPosition.absPosition = {\n  TOP: 'top',\n  RIGHT: 'right',\n  BOTTOM: 'bottom',\n  LEFT: 'left'\n};\n\n/**\n * Margin between the edges of a panel and the viewport.\n * @const {number}\n */\nMdPanelPosition.viewportMargin = 8;\n\n\n/**\n * Sets absolute positioning for the panel.\n * @return {!MdPanelPosition}\n */\nMdPanelPosition.prototype.absolute = function() {\n  this._absolute = true;\n  return this;\n};\n\n\n/**\n * Sets the value of a position for the panel. Clears any previously set\n * position.\n * @param {string} position Position to set\n * @param {string=} value Value of the position. Defaults to '0'.\n * @returns {!MdPanelPosition}\n * @private\n */\nMdPanelPosition.prototype._setPosition = function(position, value) {\n  if (position === MdPanelPosition.absPosition.RIGHT ||\n      position === MdPanelPosition.absPosition.LEFT) {\n    this._left = this._right = '';\n  } else if (\n      position === MdPanelPosition.absPosition.BOTTOM ||\n      position === MdPanelPosition.absPosition.TOP) {\n    this._top = this._bottom = '';\n  } else {\n    var positions = Object.keys(MdPanelPosition.absPosition).join()\n        .toLowerCase();\n\n    throw new Error('mdPanel: Position must be one of ' + positions + '.');\n  }\n\n  this['_' +  position] = angular.isString(value) ? value : '0';\n\n  return this;\n};\n\n\n/**\n * Sets the value of `top` for the panel. Clears any previously set vertical\n * position.\n * @param {string=} top Value of `top`. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.top = function(top) {\n  return this._setPosition(MdPanelPosition.absPosition.TOP, top);\n};\n\n\n/**\n * Sets the value of `bottom` for the panel. Clears any previously set vertical\n * position.\n * @param {string=} bottom Value of `bottom`. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.bottom = function(bottom) {\n  return this._setPosition(MdPanelPosition.absPosition.BOTTOM, bottom);\n};\n\n\n/**\n * Sets the panel to the start of the page - `left` if `ltr` or `right` for\n * `rtl`. Clears any previously set horizontal position.\n * @param {string=} start Value of position. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.start = function(start) {\n  var position = this._isRTL ? MdPanelPosition.absPosition.RIGHT : MdPanelPosition.absPosition.LEFT;\n  return this._setPosition(position, start);\n};\n\n\n/**\n * Sets the panel to the end of the page - `right` if `ltr` or `left` for `rtl`.\n * Clears any previously set horizontal position.\n * @param {string=} end Value of position. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.end = function(end) {\n  var position = this._isRTL ? MdPanelPosition.absPosition.LEFT : MdPanelPosition.absPosition.RIGHT;\n  return this._setPosition(position, end);\n};\n\n\n/**\n * Sets the value of `left` for the panel. Clears any previously set\n * horizontal position.\n * @param {string=} left Value of `left`. Defaults to '0'.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.left = function(left) {\n  return this._setPosition(MdPanelPosition.absPosition.LEFT, left);\n};\n\n\n/**\n * Sets the value of `right` for the panel. Clears any previously set\n * horizontal position.\n * @param {string=} right Value of `right`. Defaults to '0'.\n * @returns {!MdPanelPosition}\n*/\nMdPanelPosition.prototype.right = function(right) {\n  return this._setPosition(MdPanelPosition.absPosition.RIGHT, right);\n};\n\n\n/**\n * Centers the panel horizontally in the viewport. Clears any previously set\n * horizontal position.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.centerHorizontally = function() {\n  this._left = '50%';\n  this._right = '';\n  this._translateX = ['-50%'];\n  return this;\n};\n\n\n/**\n * Centers the panel vertically in the viewport. Clears any previously set\n * vertical position.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.centerVertically = function() {\n  this._top = '50%';\n  this._bottom = '';\n  this._translateY = ['-50%'];\n  return this;\n};\n\n\n/**\n * Centers the panel horizontally and vertically in the viewport. This is\n * equivalent to calling both `centerHorizontally` and `centerVertically`.\n * Clears any previously set horizontal and vertical positions.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.center = function() {\n  return this.centerHorizontally().centerVertically();\n};\n\n\n/**\n * Sets element for relative positioning.\n * @param {string|!Element|!JQLite} element Query selector, DOM element,\n *     or angular element to set the panel relative to.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.relativeTo = function(element) {\n  this._absolute = false;\n  this._relativeToEl = getElement(element);\n  return this;\n};\n\n\n/**\n * Sets the x and y positions for the panel relative to another element.\n * @param {string} xPosition must be one of the MdPanelPosition.xPosition\n *     values.\n * @param {string} yPosition must be one of the MdPanelPosition.yPosition\n *     values.\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.addPanelPosition = function(xPosition, yPosition) {\n  if (!this._relativeToEl) {\n    throw new Error('mdPanel: addPanelPosition can only be used with ' +\n        'relative positioning. Set relativeTo first.');\n  }\n\n  validatePosition(MdPanelPosition.xPosition, xPosition);\n  validatePosition(MdPanelPosition.yPosition, yPosition);\n\n  this._positions.push({\n    x: xPosition,\n    y: yPosition\n  });\n\n  return this;\n};\n\n\n/**\n * Sets the value of the offset in the x-direction. This will add to any\n * previously set offsets.\n * @param {string|number|function(MdPanelPosition): string} offsetX\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.withOffsetX = function(offsetX) {\n  this._translateX.push(addUnits(offsetX));\n  return this;\n};\n\n\n/**\n * Sets the value of the offset in the y-direction. This will add to any\n * previously set offsets.\n * @param {string|number|function(MdPanelPosition): string} offsetY\n * @returns {!MdPanelPosition}\n */\nMdPanelPosition.prototype.withOffsetY = function(offsetY) {\n  this._translateY.push(addUnits(offsetY));\n  return this;\n};\n\n\n/**\n * Gets the value of `top` for the panel.\n * @returns {string}\n */\nMdPanelPosition.prototype.getTop = function() {\n  return this._top;\n};\n\n\n/**\n * Gets the value of `bottom` for the panel.\n * @returns {string}\n */\nMdPanelPosition.prototype.getBottom = function() {\n  return this._bottom;\n};\n\n\n/**\n * Gets the value of `left` for the panel.\n * @returns {string}\n */\nMdPanelPosition.prototype.getLeft = function() {\n  return this._left;\n};\n\n\n/**\n * Gets the value of `right` for the panel.\n * @returns {string}\n */\nMdPanelPosition.prototype.getRight = function() {\n  return this._right;\n};\n\n\n/**\n * Gets the value of `transform` for the panel.\n * @returns {string} representation of the translateX and translateY rules and values\n */\nMdPanelPosition.prototype.getTransform = function() {\n  var translateX = this._reduceTranslateValues('translateX', this._translateX);\n  var translateY = this._reduceTranslateValues('translateY', this._translateY);\n\n  // It's important to trim the result, because the browser will ignore the set\n  // operation if the string contains only whitespace.\n  return (translateX + ' ' + translateY).trim();\n};\n\n\n/**\n * Sets the `transform` value for an element.\n * @param {!JQLite} el\n * @returns {!JQLite}\n * @private\n */\nMdPanelPosition.prototype._setTransform = function(el) {\n  return el.css(this._$mdConstant.CSS.TRANSFORM, this.getTransform());\n};\n\n\n/**\n * True if the panel is completely on-screen with this positioning; false\n * otherwise.\n * @param {!JQLite} el\n * @return {boolean}\n * @private\n */\nMdPanelPosition.prototype._isOnscreen = function(el) {\n  // this works because we always use fixed positioning for the panel,\n  // which is relative to the viewport.\n  var left = parseInt(this.getLeft());\n  var top = parseInt(this.getTop());\n\n  if (this._translateX.length || this._translateY.length) {\n    var prefixedTransform = this._$mdConstant.CSS.TRANSFORM;\n    var offsets = getComputedTranslations(el, prefixedTransform);\n    left += offsets.x;\n    top += offsets.y;\n  }\n\n  var right = left + el[0].offsetWidth;\n  var bottom = top + el[0].offsetHeight;\n\n  return (left >= 0) &&\n    (top >= 0) &&\n    (bottom <= this._$window.innerHeight) &&\n    (right <= this._$window.innerWidth);\n};\n\n\n/**\n * Gets the first x/y position that can fit on-screen.\n * @returns {{x: string, y: string}}\n */\nMdPanelPosition.prototype.getActualPosition = function() {\n  return this._actualPosition;\n};\n\n\n/**\n * Reduces a list of translate values to a string that can be used within\n * transform.\n * @param {string} translateFn\n * @param {!Array<string>} values\n * @returns {string}\n * @private\n */\nMdPanelPosition.prototype._reduceTranslateValues =\n    function(translateFn, values) {\n      return values.map(function(translation) {\n        var translationValue = angular.isFunction(translation) ?\n            addUnits(translation(this)) : translation;\n        return translateFn + '(' + translationValue + ')';\n      }, this).join(' ');\n    };\n\n\n/**\n * Sets the panel position based on the created panel element and best x/y\n * positioning.\n * @param {!JQLite} el\n * @private\n */\nMdPanelPosition.prototype._setPanelPosition = function(el) {\n  // Remove the class in case it has been added before.\n  el.removeClass('_md-panel-position-adjusted');\n\n  // Only calculate the position if necessary.\n  if (this._absolute) {\n    this._setTransform(el);\n    return;\n  }\n\n  if (this._actualPosition) {\n    this._calculatePanelPosition(el, this._actualPosition);\n    this._setTransform(el);\n    this._constrainToViewport(el);\n    return;\n  }\n\n  for (var i = 0; i < this._positions.length; i++) {\n    this._actualPosition = this._positions[i];\n    this._calculatePanelPosition(el, this._actualPosition);\n    this._setTransform(el);\n\n    if (this._isOnscreen(el)) {\n      return;\n    }\n  }\n\n  this._constrainToViewport(el);\n};\n\n\n/**\n * Constrains a panel's position to the viewport.\n * @param {!JQLite} el\n * @private\n */\nMdPanelPosition.prototype._constrainToViewport = function(el) {\n  var margin = MdPanelPosition.viewportMargin;\n  var initialTop = this._top;\n  var initialLeft = this._left;\n\n  if (this.getTop()) {\n    var top = parseInt(this.getTop());\n    var bottom = el[0].offsetHeight + top;\n    var viewportHeight = this._$window.innerHeight;\n\n    if (top < margin) {\n      this._top = margin + 'px';\n    } else if (bottom > viewportHeight) {\n      this._top = top - (bottom - viewportHeight + margin) + 'px';\n    }\n  }\n\n  if (this.getLeft()) {\n    var left = parseInt(this.getLeft());\n    var right = el[0].offsetWidth + left;\n    var viewportWidth = this._$window.innerWidth;\n\n    if (left < margin) {\n      this._left = margin + 'px';\n    } else if (right > viewportWidth) {\n      this._left = left - (right - viewportWidth + margin) + 'px';\n    }\n  }\n\n  // Class that can be used to re-style the panel if it was repositioned.\n  el.toggleClass(\n    '_md-panel-position-adjusted',\n    this._top !== initialTop || this._left !== initialLeft\n  );\n};\n\n\n/**\n * Switches between 'start' and 'end'.\n * @param {string} position Horizontal position of the panel\n * @returns {string} Reversed position\n * @private\n */\nMdPanelPosition.prototype._reverseXPosition = function(position) {\n  if (position === MdPanelPosition.xPosition.CENTER) {\n    return position;\n  }\n\n  var start = 'start';\n  var end = 'end';\n\n  return position.indexOf(start) > -1 ? position.replace(start, end) : position.replace(end, start);\n};\n\n\n/**\n * Handles horizontal positioning in rtl or ltr environments.\n * @param {string} position Horizontal position of the panel\n * @returns {string} The correct position according the page direction\n * @private\n */\nMdPanelPosition.prototype._bidi = function(position) {\n  return this._isRTL ? this._reverseXPosition(position) : position;\n};\n\n\n/**\n * Calculates the panel position based on the created panel element and the\n * provided positioning.\n * @param {!JQLite} el\n * @param {!{x:string, y:string}} position\n * @private\n */\nMdPanelPosition.prototype._calculatePanelPosition = function(el, position) {\n\n  var panelBounds = el[0].getBoundingClientRect();\n  var panelWidth = Math.max(panelBounds.width, el[0].clientWidth);\n  var panelHeight = Math.max(panelBounds.height, el[0].clientHeight);\n\n  var targetBounds = this._relativeToEl[0].getBoundingClientRect();\n\n  var targetLeft = targetBounds.left;\n  var targetRight = targetBounds.right;\n  var targetWidth = targetBounds.width;\n\n  switch (this._bidi(position.x)) {\n    case MdPanelPosition.xPosition.OFFSET_START:\n      this._left = targetLeft - panelWidth + 'px';\n      break;\n    case MdPanelPosition.xPosition.ALIGN_END:\n      this._left = targetRight - panelWidth + 'px';\n      break;\n    case MdPanelPosition.xPosition.CENTER:\n      var left = targetLeft + (0.5 * targetWidth) - (0.5 * panelWidth);\n      this._left = left + 'px';\n      break;\n    case MdPanelPosition.xPosition.ALIGN_START:\n      this._left = targetLeft + 'px';\n      break;\n    case MdPanelPosition.xPosition.OFFSET_END:\n      this._left = targetRight + 'px';\n      break;\n  }\n\n  var targetTop = targetBounds.top;\n  var targetBottom = targetBounds.bottom;\n  var targetHeight = targetBounds.height;\n\n  switch (position.y) {\n    case MdPanelPosition.yPosition.ABOVE:\n      this._top = targetTop - panelHeight + 'px';\n      break;\n    case MdPanelPosition.yPosition.ALIGN_BOTTOMS:\n      this._top = targetBottom - panelHeight + 'px';\n      break;\n    case MdPanelPosition.yPosition.CENTER:\n      var top = targetTop + (0.5 * targetHeight) - (0.5 * panelHeight);\n      this._top = top + 'px';\n      break;\n    case MdPanelPosition.yPosition.ALIGN_TOPS:\n      this._top = targetTop + 'px';\n      break;\n    case MdPanelPosition.yPosition.BELOW:\n      this._top = targetBottom + 'px';\n      break;\n  }\n};\n\n\n/*****************************************************************************\n *                               MdPanelAnimation                            *\n *****************************************************************************/\n\n\n/**\n * Animation configuration object. To use, create an MdPanelAnimation with the\n * desired properties, then pass the object as part of $mdPanel creation.\n *\n * Example:\n *\n * var panelAnimation = new MdPanelAnimation()\n *     .openFrom(myButtonEl)\n *     .closeTo('.my-button')\n *     .withAnimation($mdPanel.animation.SCALE);\n *\n * $mdPanel.create({\n *   animation: panelAnimation\n * });\n *\n * @param {!IInjectorService} $injector\n * @final @constructor\n */\nfunction MdPanelAnimation($injector) {\n  /** @private @const {!angular.$mdUtil} */\n  this._$mdUtil = $injector.get('$mdUtil');\n\n  /**\n   * @private {{element: !JQLite|undefined, bounds: !DOMRect}|\n   *     undefined}\n   */\n  this._openFrom;\n\n  /**\n   * @private {{element: !JQLite|undefined, bounds: !DOMRect}|\n   *     undefined}\n   */\n  this._closeTo;\n\n  /** @private {string|{open: string, close: string}} */\n  this._animationClass = '';\n\n  /** @private {number} */\n  this._openDuration;\n\n  /** @private {number} */\n  this._closeDuration;\n\n  /** @private {number|{open: number, close: number}} */\n  this._rawDuration;\n}\n\n\n/**\n * Possible default animations.\n * @enum {string}\n */\nMdPanelAnimation.animation = {\n  SLIDE: 'md-panel-animate-slide',\n  SCALE: 'md-panel-animate-scale',\n  FADE: 'md-panel-animate-fade'\n};\n\n\n/**\n * Specifies where to start the open animation. `openFrom` accepts a\n * click event object, query selector, DOM element, or a Rect object that\n * is used to determine the bounds. When passed a click event, the location\n * of the click will be used as the position to start the animation.\n * @param {string|!Element|!Event|{top: number, left: number}} openFrom\n * @returns {!MdPanelAnimation}\n */\nMdPanelAnimation.prototype.openFrom = function(openFrom) {\n  // Check if 'openFrom' is an Event.\n  openFrom = openFrom.target ? openFrom.target : openFrom;\n\n  this._openFrom = this._getPanelAnimationTarget(openFrom);\n\n  if (!this._closeTo) {\n    this._closeTo = this._openFrom;\n  }\n  return this;\n};\n\n\n/**\n * Specifies where to animate the panel close. `closeTo` accepts a\n * query selector, DOM element, or a Rect object that is used to determine\n * the bounds.\n * @param {string|!Element|{top: number, left: number}} closeTo\n * @returns {!MdPanelAnimation}\n */\nMdPanelAnimation.prototype.closeTo = function(closeTo) {\n  this._closeTo = this._getPanelAnimationTarget(closeTo);\n  return this;\n};\n\n\n/**\n * Specifies the duration of the animation in milliseconds.\n * @param {number|{open: number, close: number}} duration\n * @returns {!MdPanelAnimation}\n */\nMdPanelAnimation.prototype.duration = function(duration) {\n  if (duration) {\n    if (angular.isNumber(duration)) {\n      this._openDuration = this._closeDuration = toSeconds(duration);\n    } else if (angular.isObject(duration)) {\n      this._openDuration = toSeconds(duration.open);\n      this._closeDuration = toSeconds(duration.close);\n    }\n  }\n\n  // Save the original value so it can be passed to the backdrop.\n  this._rawDuration = duration;\n\n  return this;\n\n  function toSeconds(value) {\n    if (angular.isNumber(value)) return value / 1000;\n  }\n};\n\n\n/**\n * Returns the element and bounds for the animation target.\n * @param {string|!Element|{top: number, left: number}} location\n * @returns {{element: !JQLite|undefined, bounds: !DOMRect}}\n * @private\n */\nMdPanelAnimation.prototype._getPanelAnimationTarget = function(location) {\n  if (angular.isDefined(location.top) || angular.isDefined(location.left)) {\n    return {\n      element: undefined,\n      bounds: {\n        top: location.top || 0,\n        left: location.left || 0\n      }\n    };\n  } else {\n    return this._getBoundingClientRect(getElement(location));\n  }\n};\n\n\n/**\n * Specifies the animation class.\n *\n * There are several default animations that can be used:\n * (MdPanelAnimation.animation)\n *   SLIDE: The panel slides in and out from the specified\n *        elements.\n *   SCALE: The panel scales in and out.\n *   FADE: The panel fades in and out.\n *\n * @param {string|{open: string, close: string}} cssClass\n * @returns {!MdPanelAnimation}\n */\nMdPanelAnimation.prototype.withAnimation = function(cssClass) {\n  this._animationClass = cssClass;\n  return this;\n};\n\n\n/**\n * Animate the panel open.\n * @param {!JQLite} panelEl\n * @returns {!Q.IPromise} A promise that is resolved when the open\n *     animation is complete.\n */\nMdPanelAnimation.prototype.animateOpen = function(panelEl) {\n  var animator = this._$mdUtil.dom.animator;\n\n  this._fixBounds(panelEl);\n  var animationOptions = {};\n\n  // Include the panel transformations when calculating the animations.\n  var panelTransform = panelEl[0].style.transform || '';\n\n  var openFrom = animator.toTransformCss(panelTransform);\n  var openTo = animator.toTransformCss(panelTransform);\n\n  switch (this._animationClass) {\n    case MdPanelAnimation.animation.SLIDE:\n      // Slide should start with opacity: 1.\n      panelEl.css('opacity', '1');\n\n      animationOptions = {\n        transitionInClass: '_md-panel-animate-enter',\n        transitionOutClass: '_md-panel-animate-leave',\n      };\n\n      var openSlide = animator.calculateSlideToOrigin(\n              panelEl, this._openFrom) || '';\n      openFrom = animator.toTransformCss(openSlide + ' ' + panelTransform);\n      break;\n\n    case MdPanelAnimation.animation.SCALE:\n      animationOptions = {\n        transitionInClass: '_md-panel-animate-enter'\n      };\n\n      var openScale = animator.calculateZoomToOrigin(\n              panelEl, this._openFrom) || '';\n      openFrom = animator.toTransformCss(panelTransform + ' ' + openScale);\n      break;\n\n    case MdPanelAnimation.animation.FADE:\n      animationOptions = {\n        transitionInClass: '_md-panel-animate-enter'\n      };\n      break;\n\n    default:\n      if (angular.isString(this._animationClass)) {\n        animationOptions = {\n          transitionInClass: this._animationClass\n        };\n      } else {\n        animationOptions = {\n          transitionInClass: this._animationClass['open'],\n          transitionOutClass: this._animationClass['close'],\n        };\n      }\n  }\n\n  animationOptions.duration = this._openDuration;\n\n  return animator\n      .translate3d(panelEl, openFrom, openTo, animationOptions);\n};\n\n\n/**\n * Animate the panel close.\n * @param {!JQLite} panelEl\n * @returns {!Q.IPromise} A promise that resolves when the close animation is complete.\n */\nMdPanelAnimation.prototype.animateClose = function(panelEl) {\n  var animator = this._$mdUtil.dom.animator;\n  var reverseAnimationOptions = {};\n\n  // Include the panel transformations when calculating the animations.\n  var panelTransform = panelEl[0].style.transform || '';\n\n  var closeFrom = animator.toTransformCss(panelTransform);\n  var closeTo = animator.toTransformCss(panelTransform);\n\n  switch (this._animationClass) {\n    case MdPanelAnimation.animation.SLIDE:\n      // Slide should start with opacity: 1.\n      panelEl.css('opacity', '1');\n      reverseAnimationOptions = {\n        transitionInClass: '_md-panel-animate-leave',\n        transitionOutClass: '_md-panel-animate-enter _md-panel-animate-leave'\n      };\n\n      var closeSlide = animator.calculateSlideToOrigin(panelEl, this._closeTo) || '';\n      closeTo = animator.toTransformCss(closeSlide + ' ' + panelTransform);\n      break;\n\n    case MdPanelAnimation.animation.SCALE:\n      reverseAnimationOptions = {\n        transitionInClass: '_md-panel-animate-scale-out _md-panel-animate-leave',\n        transitionOutClass: '_md-panel-animate-scale-out _md-panel-animate-enter _md-panel-animate-leave'\n      };\n\n      var closeScale = animator.calculateZoomToOrigin(panelEl, this._closeTo) || '';\n      closeTo = animator.toTransformCss(panelTransform + ' ' + closeScale);\n      break;\n\n    case MdPanelAnimation.animation.FADE:\n      reverseAnimationOptions = {\n        transitionInClass: '_md-panel-animate-fade-out _md-panel-animate-leave',\n        transitionOutClass: '_md-panel-animate-fade-out _md-panel-animate-enter _md-panel-animate-leave'\n      };\n      break;\n\n    default:\n      if (angular.isString(this._animationClass)) {\n        reverseAnimationOptions = {\n          transitionOutClass: this._animationClass\n        };\n      } else {\n        reverseAnimationOptions = {\n          transitionInClass: this._animationClass['close'],\n          transitionOutClass: this._animationClass['open']\n        };\n      }\n  }\n\n  reverseAnimationOptions.duration = this._closeDuration;\n\n  return animator\n      .translate3d(panelEl, closeFrom, closeTo, reverseAnimationOptions);\n};\n\n\n/**\n * Set the height and width to match the panel if not provided.\n * @param {!JQLite} panelEl\n * @private\n */\nMdPanelAnimation.prototype._fixBounds = function(panelEl) {\n  var panelWidth = panelEl[0].offsetWidth;\n  var panelHeight = panelEl[0].offsetHeight;\n\n  if (this._openFrom && this._openFrom.bounds.height == null) {\n    this._openFrom.bounds.height = panelHeight;\n  }\n  if (this._openFrom && this._openFrom.bounds.width == null) {\n    this._openFrom.bounds.width = panelWidth;\n  }\n  if (this._closeTo && this._closeTo.bounds.height == null) {\n    this._closeTo.bounds.height = panelHeight;\n  }\n  if (this._closeTo && this._closeTo.bounds.width == null) {\n    this._closeTo.bounds.width = panelWidth;\n  }\n};\n\n\n/**\n * Identify the bounding RECT for the target element.\n * @param {!JQLite} element\n * @returns {{element: !JQLite|undefined, bounds: !DOMRect}}\n * @private\n */\nMdPanelAnimation.prototype._getBoundingClientRect = function(element) {\n  if (element instanceof angular.element) {\n    return {\n      element: element,\n      bounds: element[0].getBoundingClientRect()\n    };\n  }\n};\n\n\n/*****************************************************************************\n *                                Util Methods                               *\n *****************************************************************************/\n\n\n/**\n * Returns the angular element associated with a css selector or element.\n * @param el {string|!JQLite|!Element}\n * @returns {!JQLite}\n */\nfunction getElement(el) {\n  var queryResult = angular.isString(el) ?\n      document.querySelector(el) : el;\n  return angular.element(queryResult);\n}\n\n/**\n * Gets the computed values for an element's translateX and translateY in px.\n * @param {!JQLite|!Element} el the element to evaluate\n * @param {string} property\n * @return {{x: number, y: number}} an element's translateX and translateY in px\n */\nfunction getComputedTranslations(el, property) {\n  // The transform being returned by `getComputedStyle` is in the format:\n  // `matrix(a, b, c, d, translateX, translateY)` if defined and `none`\n  // if the element doesn't have a transform.\n  var transform = getComputedStyle(el[0] || el)[property];\n  var openIndex = transform.indexOf('(');\n  var closeIndex = transform.lastIndexOf(')');\n  var output = { x: 0, y: 0 };\n\n  if (openIndex > -1 && closeIndex > -1) {\n    var parsedValues = transform\n      .substring(openIndex + 1, closeIndex)\n      .split(', ')\n      .slice(-2);\n\n    output.x = parseInt(parsedValues[0]);\n    output.y = parseInt(parsedValues[1]);\n  }\n\n  return output;\n}\n\n/*\n * Ensures that a value is a valid position name. Throw an exception if not.\n * @param {Object} positionMap Object against which the value will be checked.\n * @param {string} value\n */\nfunction validatePosition(positionMap, value) {\n  // empty is ok\n  if (value === null || angular.isUndefined(value)) {\n    return;\n  }\n\n  var positionKeys = Object.keys(positionMap);\n  var positionValues = [];\n\n  for (var key, i = 0; key = positionKeys[i]; i++) {\n    var position = positionMap[key];\n    positionValues.push(position);\n\n    if (position === value) {\n      return;\n    }\n  }\n\n  throw new Error('Panel position only accepts the following values:\\n' +\n    positionValues.join(' | '));\n}\n\n/**\n * Adds units to a number value.\n * @param {string|number} value\n * @return {string}\n */\nfunction addUnits(value) {\n  return angular.isNumber(value) ? value + 'px' : value;\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.progressCircular\n * @description Module for a circular progressbar\n */\n\nangular.module('material.components.progressCircular', ['material.core']);\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc directive\n * @name mdProgressCircular\n * @module material.components.progressCircular\n * @restrict E\n *\n * @description\n * The circular progress directive is used to make loading content in your app as delightful and\n * painless as possible by minimizing the amount of visual change a user sees before they can view\n * and interact with content.\n *\n * For operations where the percentage of the operation completed can be determined, use a\n * determinate indicator. They give users a quick sense of how long an operation will take.\n *\n * For operations where the user is asked to wait a moment while something finishes up, and it’s\n * not necessary to expose what's happening behind the scenes and how long it will take, use an\n * indeterminate indicator.\n *\n * @param {string} md-mode Select from one of two modes: **'determinate'** and **'indeterminate'**.\n *\n * Note: if the `md-mode` value is set as undefined or specified as not 1 of the two (2) valid modes, then **'indeterminate'**\n * will be auto-applied as the mode.\n *\n * Note: if not configured, the `md-mode=\"indeterminate\"` will be auto injected as an attribute.\n * If `value=\"\"` is also specified, however, then `md-mode=\"determinate\"` would be auto-injected instead.\n * @param {number=} value In determinate mode, this number represents the percentage of the\n *     circular progress. Default: 0\n * @param {number=} md-diameter This specifies the diameter of the circular progress. The value\n * should be a pixel-size value (eg '100'). If this attribute is\n * not present then a default value of '50px' is assumed.\n *\n * @param {boolean=} ng-disabled Determines whether to disable the progress element.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-progress-circular md-mode=\"determinate\" value=\"...\"></md-progress-circular>\n *\n * <md-progress-circular md-mode=\"determinate\" ng-value=\"...\"></md-progress-circular>\n *\n * <md-progress-circular md-mode=\"determinate\" value=\"...\" md-diameter=\"100\"></md-progress-circular>\n *\n * <md-progress-circular md-mode=\"indeterminate\"></md-progress-circular>\n * </hljs>\n */\n\nMdProgressCircularDirective.$inject = [\"$window\", \"$mdProgressCircular\", \"$mdTheming\", \"$mdUtil\", \"$interval\", \"$log\"];\nangular\n  .module('material.components.progressCircular')\n  .directive('mdProgressCircular', MdProgressCircularDirective);\n\n/* @ngInject */\nfunction MdProgressCircularDirective($window, $mdProgressCircular, $mdTheming,\n                                     $mdUtil, $interval, $log) {\n\n  // Note that this shouldn't use use $$rAF, because it can cause an infinite loop\n  // in any tests that call $animate.flush.\n  var rAF = $window.requestAnimationFrame ||\n            $window.webkitRequestAnimationFrame ||\n            angular.noop;\n\n  var cAF = $window.cancelAnimationFrame ||\n            $window.webkitCancelAnimationFrame ||\n            $window.webkitCancelRequestAnimationFrame ||\n            angular.noop;\n\n  var MODE_DETERMINATE = 'determinate';\n  var MODE_INDETERMINATE = 'indeterminate';\n  var DISABLED_CLASS = '_md-progress-circular-disabled';\n  var INDETERMINATE_CLASS = 'md-mode-indeterminate';\n\n  return {\n    restrict: 'E',\n    scope: {\n      value: '@',\n      mdDiameter: '@',\n      mdMode: '@'\n    },\n    template:\n      '<svg xmlns=\"http://www.w3.org/2000/svg\">' +\n        '<path fill=\"none\"/>' +\n      '</svg>',\n    compile: function(element, attrs) {\n      element.attr({\n        'aria-valuemin': 0,\n        'aria-valuemax': 100,\n        'role': 'progressbar'\n      });\n\n      if (angular.isUndefined(attrs.mdMode)) {\n        var mode = attrs.hasOwnProperty('value') ? MODE_DETERMINATE : MODE_INDETERMINATE;\n        attrs.$set('mdMode', mode);\n      } else {\n        attrs.$set('mdMode', attrs.mdMode.trim());\n      }\n\n      return MdProgressCircularLink;\n    }\n  };\n\n  function MdProgressCircularLink(scope, element, attrs) {\n    var node = element[0];\n    var svg = angular.element(node.querySelector('svg'));\n    var path = angular.element(node.querySelector('path'));\n    var startIndeterminate = $mdProgressCircular.startIndeterminate;\n    var endIndeterminate = $mdProgressCircular.endIndeterminate;\n    var iterationCount = 0;\n    var lastAnimationId = 0;\n    var lastDrawFrame;\n    var interval;\n\n    $mdTheming(element);\n    element.toggleClass(DISABLED_CLASS, attrs.hasOwnProperty('disabled'));\n\n    // If the mode is indeterminate, it doesn't need to\n    // wait for the next digest. It can start right away.\n    if (scope.mdMode === MODE_INDETERMINATE){\n      startIndeterminateAnimation();\n    }\n\n    scope.$on('$destroy', function(){\n      cleanupIndeterminateAnimation();\n\n      if (lastDrawFrame) {\n        cAF(lastDrawFrame);\n      }\n    });\n\n    scope.$watchGroup(['value', 'mdMode', function() {\n      var isDisabled = node.disabled;\n\n      // Sometimes the browser doesn't return a boolean, in\n      // which case we should check whether the attribute is\n      // present.\n      if (isDisabled === true || isDisabled === false){\n        return isDisabled;\n      }\n\n      return angular.isDefined(element.attr('disabled'));\n    }], function(newValues, oldValues) {\n      var mode = newValues[1];\n      var isDisabled = newValues[2];\n      var wasDisabled = oldValues[2];\n      var diameter = 0;\n      var strokeWidth = 0;\n\n      if (isDisabled !== wasDisabled) {\n        element.toggleClass(DISABLED_CLASS, !!isDisabled);\n      }\n\n      if (isDisabled) {\n        cleanupIndeterminateAnimation();\n      } else {\n        if (mode !== MODE_DETERMINATE && mode !== MODE_INDETERMINATE) {\n          mode = MODE_INDETERMINATE;\n          attrs.$set('mdMode', mode);\n        }\n\n        if (mode === MODE_INDETERMINATE) {\n          if (oldValues[1] === MODE_DETERMINATE) {\n            diameter = getSize(scope.mdDiameter);\n            strokeWidth = getStroke(diameter);\n            path.attr('d', getSvgArc(diameter, strokeWidth, true));\n            path.attr('stroke-dasharray', getDashLength(diameter, strokeWidth, 75));\n          }\n          startIndeterminateAnimation();\n        } else {\n          var newValue = clamp(newValues[0]);\n          var oldValue = clamp(oldValues[0]);\n\n          cleanupIndeterminateAnimation();\n\n          if (oldValues[1] === MODE_INDETERMINATE) {\n            diameter = getSize(scope.mdDiameter);\n            strokeWidth = getStroke(diameter);\n            path.attr('d', getSvgArc(diameter, strokeWidth, false));\n            path.attr('stroke-dasharray', getDashLength(diameter, strokeWidth, 100));\n          }\n\n          element.attr('aria-valuenow', newValue);\n          renderCircle(oldValue, newValue);\n        }\n      }\n\n    });\n\n    // This is in a separate watch in order to avoid layout, unless\n    // the value has actually changed.\n    scope.$watch('mdDiameter', function(newValue) {\n      var diameter = getSize(newValue);\n      var strokeWidth = getStroke(diameter);\n      var value = clamp(scope.value);\n      var transformOrigin = (diameter / 2) + 'px';\n      var dimensions = {\n        width: diameter + 'px',\n        height: diameter + 'px'\n      };\n\n      // The viewBox has to be applied via setAttribute, because it is\n      // case-sensitive. If jQuery is included in the page, `.attr` lowercases\n      // all attribute names.\n      svg[0].setAttribute('viewBox', '0 0 ' + diameter + ' ' + diameter);\n\n      // Usually viewBox sets the dimensions for the SVG, however that doesn't\n      // seem to be the case on IE10.\n      // Important! The transform origin has to be set from here and it has to\n      // be in the format of \"Ypx Ypx Ypx\", otherwise the rotation wobbles in\n      // IE and Edge, because they don't account for the stroke width when\n      // rotating. Also \"center\" doesn't help in this case, it has to be a\n      // precise value.\n      svg\n        .css(dimensions)\n        .css('transform-origin', transformOrigin + ' ' + transformOrigin + ' ' + transformOrigin);\n\n      element.css(dimensions);\n\n      path.attr('stroke-width', strokeWidth);\n      path.attr('stroke-linecap', 'square');\n      if (scope.mdMode == MODE_INDETERMINATE) {\n        path.attr('d', getSvgArc(diameter, strokeWidth, true));\n        path.attr('stroke-dasharray', getDashLength(diameter, strokeWidth, 75));\n        path.attr('stroke-dashoffset', getDashOffset(diameter, strokeWidth, 1, 75));\n      } else {\n        path.attr('d', getSvgArc(diameter, strokeWidth, false));\n        path.attr('stroke-dasharray', getDashLength(diameter, strokeWidth, 100));\n        path.attr('stroke-dashoffset', getDashOffset(diameter, strokeWidth, 0, 100));\n        renderCircle(value, value);\n      }\n\n    });\n\n    function renderCircle(animateFrom, animateTo, easing, duration, iterationCount, maxValue) {\n      var id = ++lastAnimationId;\n      var startTime = $mdUtil.now();\n      var changeInValue = animateTo - animateFrom;\n      var diameter = getSize(scope.mdDiameter);\n      var strokeWidth = getStroke(diameter);\n      var ease = easing || $mdProgressCircular.easeFn;\n      var animationDuration = duration || $mdProgressCircular.duration;\n      var rotation = -90 * (iterationCount || 0);\n      var dashLimit = maxValue || 100;\n\n      // No need to animate it if the values are the same\n      if (animateTo === animateFrom) {\n        renderFrame(animateTo);\n      } else {\n        lastDrawFrame = rAF(function animation() {\n          var currentTime = $window.Math.max(0, $window.Math.min($mdUtil.now() - startTime, animationDuration));\n\n          renderFrame(ease(currentTime, animateFrom, changeInValue, animationDuration));\n\n          // Do not allow overlapping animations\n          if (id === lastAnimationId && currentTime < animationDuration) {\n            lastDrawFrame = rAF(animation);\n          }\n        });\n      }\n\n      function renderFrame(value) {\n        path.attr('stroke-dashoffset', getDashOffset(diameter, strokeWidth, value, dashLimit));\n        path.attr('transform','rotate(' + (rotation) + ' ' + diameter/2 + ' ' + diameter/2 + ')');\n      }\n    }\n\n    function animateIndeterminate() {\n      renderCircle(\n        startIndeterminate,\n        endIndeterminate,\n        $mdProgressCircular.easeFnIndeterminate,\n        $mdProgressCircular.durationIndeterminate,\n        iterationCount,\n        75\n      );\n\n      // The %4 technically isn't necessary, but it keeps the rotation\n      // under 360, instead of becoming a crazy large number.\n      iterationCount = ++iterationCount % 4;\n\n    }\n\n    function startIndeterminateAnimation() {\n      if (!interval) {\n        // Note that this interval isn't supposed to trigger a digest.\n        interval = $interval(\n          animateIndeterminate,\n          $mdProgressCircular.durationIndeterminate,\n          0,\n          false\n        );\n\n        animateIndeterminate();\n\n        element\n          .addClass(INDETERMINATE_CLASS)\n          .removeAttr('aria-valuenow');\n      }\n    }\n\n    function cleanupIndeterminateAnimation() {\n      if (interval) {\n        $interval.cancel(interval);\n        interval = null;\n        element.removeClass(INDETERMINATE_CLASS);\n      }\n    }\n  }\n\n  /**\n   * Returns SVG path data for progress circle\n   * Syntax spec: https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands\n   *\n   * @param {number} diameter Diameter of the container.\n   * @param {number} strokeWidth Stroke width to be used when drawing circle\n   * @param {boolean} indeterminate Use if progress circle will be used for indeterminate\n   *\n   * @returns {string} String representation of an SVG arc.\n   */\n  function getSvgArc(diameter, strokeWidth, indeterminate) {\n    var radius = diameter / 2;\n    var offset = strokeWidth / 2;\n    var start = radius + ',' + offset; // ie: (25, 2.5) or 12 o'clock\n    var end = offset + ',' + radius;   // ie: (2.5, 25) or  9 o'clock\n    var arcRadius = radius - offset;\n    return 'M' + start\n         + 'A' + arcRadius + ',' + arcRadius + ' 0 1 1 ' + end // 75% circle\n         + (indeterminate ? '' : 'A' + arcRadius + ',' + arcRadius + ' 0 0 1 ' + start); // loop to start\n  }\n\n  /**\n   * Return stroke length for progress circle\n   *\n   * @param {number} diameter Diameter of the container.\n   * @param {number} strokeWidth Stroke width to be used when drawing circle\n   * @param {number} value Percentage of circle (between 0 and 100)\n   * @param {number} maxArcLength Maximum length of arc as a percentage of circle (between 0 and 100)\n   *\n   * @returns {number} Stroke length for progress circle\n   */\n  function getDashOffset(diameter, strokeWidth, value, maxArcLength) {\n    return getSpinnerCircumference(diameter, strokeWidth) * ((maxArcLength - value) / 100);\n  }\n\n  /**\n   * Limits a value between 0 and 100.\n   */\n  function clamp(value) {\n    return $window.Math.max(0, $window.Math.min(value || 0, 100));\n  }\n\n  /**\n   * Determines the size of a progress circle, based on the provided\n   * value in the following formats: `X`, `Ypx`, `Z%`.\n   */\n  function getSize(value) {\n    var defaultValue = $mdProgressCircular.progressSize;\n\n    if (value) {\n      var parsed = parseFloat(value);\n\n      if (value.lastIndexOf('%') === value.length - 1) {\n        parsed = (parsed / 100) * defaultValue;\n      }\n\n      return parsed;\n    }\n\n    return defaultValue;\n  }\n\n  /**\n   * Determines the circle's stroke width, based on\n   * the provided diameter.\n   */\n  function getStroke(diameter) {\n    return $mdProgressCircular.strokeWidth / 100 * diameter;\n  }\n\n  /**\n   * Return length of the dash\n   *\n   * @param {number} diameter Diameter of the container.\n   * @param {number} strokeWidth Stroke width to be used when drawing circle\n   * @param {number} value Percentage of circle (between 0 and 100)\n   *\n   * @returns {number} Length of the dash\n   */\n  function getDashLength(diameter, strokeWidth, value) {\n    return getSpinnerCircumference(diameter, strokeWidth) * (value / 100);\n  }\n\n  /**\n   * Return circumference of the spinner\n   *\n   * @param {number} diameter Diameter of the container.\n   * @param {number} strokeWidth Stroke width to be used when drawing circle\n   *\n   * @returns {number} Circumference of the spinner\n   */\n  function getSpinnerCircumference(diameter, strokeWidth) {\n    return ((diameter - strokeWidth) * $window.Math.PI);\n  }\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc service\n * @name $mdProgressCircular\n * @module material.components.progressCircular\n *\n * @description\n * Allows the user to specify the default options for the `progressCircular` directive.\n *\n * @property {number} progressSize Diameter of the progress circle in pixels.\n * @property {number} strokeWidth Width of the circle's stroke as a percentage of the circle's size.\n * @property {number} duration Length of the circle animation in milliseconds.\n * @property {function} easeFn Default easing animation function.\n * @property {object} easingPresets Collection of pre-defined easing functions.\n *\n * @property {number} durationIndeterminate Duration of the indeterminate animation.\n * @property {number} startIndeterminate Indeterminate animation start point.\n * @property {number} endIndeterminate Indeterminate animation end point.\n * @property {function} easeFnIndeterminate Easing function to be used when animating\n * between the indeterminate values.\n *\n * @property {(function(object): object)} configure Used to modify the default options.\n *\n * @usage\n * <hljs lang=\"js\">\n *   myAppModule.config(function($mdProgressCircularProvider) {\n *\n *     // Example of changing the default progress options.\n *     $mdProgressCircularProvider.configure({\n *       progressSize: 100,\n *       strokeWidth: 20,\n *       duration: 800\n *     });\n * });\n * </hljs>\n *\n */\n\nangular\n  .module('material.components.progressCircular')\n  .provider(\"$mdProgressCircular\", MdProgressCircularProvider);\n\nfunction MdProgressCircularProvider() {\n  var progressConfig = {\n    progressSize: 50,\n    strokeWidth: 10,\n    duration: 100,\n    easeFn: linearEase,\n\n    durationIndeterminate: 1333,\n    startIndeterminate: 1,\n    endIndeterminate: 149,\n    easeFnIndeterminate: materialEase,\n\n    easingPresets: {\n      linearEase: linearEase,\n      materialEase: materialEase\n    }\n  };\n\n  return {\n    configure: function(options) {\n      progressConfig = angular.extend(progressConfig, options || {});\n      return progressConfig;\n    },\n    $get: function() { return progressConfig; }\n  };\n\n  function linearEase(t, b, c, d) {\n    return c * t / d + b;\n  }\n\n  function materialEase(t, b, c, d) {\n    // via http://www.timotheegroleau.com/Flash/experiments/easing_function_generator.htm\n    // with settings of [0, 0, 1, 1]\n    var ts = (t /= d) * t;\n    var tc = ts * t;\n    return b + c * (6 * tc * ts + -15 * ts * ts + 10 * tc);\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.progressLinear\n * @description Linear Progress module!\n */\nMdProgressLinearDirective.$inject = [\"$mdTheming\", \"$mdUtil\", \"$log\"];\nangular.module('material.components.progressLinear', [\n  'material.core'\n])\n  .directive('mdProgressLinear', MdProgressLinearDirective);\n\n/**\n * @ngdoc directive\n * @name mdProgressLinear\n * @module material.components.progressLinear\n * @restrict E\n *\n * @description\n * The linear progress directive is used to make loading content\n * in your app as delightful and painless as possible by minimizing\n * the amount of visual change a user sees before they can view\n * and interact with content.\n *\n * Each operation should only be represented by one activity indicator\n * For example: one refresh operation should not display both a\n * refresh bar and an activity circle.\n *\n * For operations where the percentage of the operation completed\n * can be determined, use a determinate indicator. They give users\n * a quick sense of how long an operation will take.\n *\n * For operations where the user is asked to wait a moment while\n * something finishes up, and it’s not necessary to expose what's\n * happening behind the scenes and how long it will take, use an\n * indeterminate indicator.\n *\n * @param {string} md-mode Select from one of four modes: determinate, indeterminate, buffer or query.\n *\n * Note: if the `md-mode` value is set as undefined or specified as 1 of the four (4) valid modes, then `indeterminate`\n * will be auto-applied as the mode.\n *\n * Note: if not configured, the `md-mode=\"indeterminate\"` will be auto injected as an attribute. If `value=\"\"` is also specified, however,\n * then `md-mode=\"determinate\"` would be auto-injected instead.\n * @param {number=} value In determinate and buffer modes, this number represents the percentage of the primary progress bar. Default: 0\n * @param {number=} md-buffer-value In the buffer mode, this number represents the percentage of the secondary progress bar. Default: 0\n * @param {boolean=} ng-disabled Determines whether to disable the progress element.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-progress-linear md-mode=\"determinate\" value=\"...\"></md-progress-linear>\n *\n * <md-progress-linear md-mode=\"determinate\" ng-value=\"...\"></md-progress-linear>\n *\n * <md-progress-linear md-mode=\"indeterminate\"></md-progress-linear>\n *\n * <md-progress-linear md-mode=\"buffer\" value=\"...\" md-buffer-value=\"...\"></md-progress-linear>\n *\n * <md-progress-linear md-mode=\"query\"></md-progress-linear>\n * </hljs>\n */\nfunction MdProgressLinearDirective($mdTheming, $mdUtil, $log) {\n  var MODE_DETERMINATE = \"determinate\";\n  var MODE_INDETERMINATE = \"indeterminate\";\n  var MODE_BUFFER = \"buffer\";\n  var MODE_QUERY = \"query\";\n  var DISABLED_CLASS = \"_md-progress-linear-disabled\";\n\n  return {\n    restrict: 'E',\n    template: '<div class=\"md-container\">' +\n      '<div class=\"md-dashed\"></div>' +\n      '<div class=\"md-bar md-bar1\"></div>' +\n      '<div class=\"md-bar md-bar2\"></div>' +\n      '</div>',\n    compile: compile\n  };\n\n  function compile(tElement, tAttrs, transclude) {\n    tElement.attr('aria-valuemin', 0);\n    tElement.attr('aria-valuemax', 100);\n    tElement.attr('role', 'progressbar');\n\n    return postLink;\n  }\n  function postLink(scope, element, attr) {\n    $mdTheming(element);\n\n    var lastMode;\n    var isDisabled = attr.hasOwnProperty('disabled');\n    var toVendorCSS = $mdUtil.dom.animator.toCss;\n    var bar1 = angular.element(element[0].querySelector('.md-bar1'));\n    var bar2 = angular.element(element[0].querySelector('.md-bar2'));\n    var container = angular.element(element[0].querySelector('.md-container'));\n\n    element\n      .attr('md-mode', mode())\n      .toggleClass(DISABLED_CLASS, isDisabled);\n\n    validateMode();\n    watchAttributes();\n\n    /**\n     * Watch the value, md-buffer-value, and md-mode attributes\n     */\n    function watchAttributes() {\n      attr.$observe('value', function(value) {\n        var percentValue = clamp(value);\n        element.attr('aria-valuenow', percentValue);\n\n        if (mode() != MODE_QUERY) animateIndicator(bar2, percentValue);\n      });\n\n      attr.$observe('mdBufferValue', function(value) {\n        animateIndicator(bar1, clamp(value));\n      });\n\n      attr.$observe('disabled', function(value) {\n        if (value === true || value === false) {\n          isDisabled = !!value;\n        } else {\n          isDisabled = angular.isDefined(value);\n        }\n\n        element.toggleClass(DISABLED_CLASS, isDisabled);\n        container.toggleClass(lastMode, !isDisabled);\n      });\n\n      attr.$observe('mdMode', function(mode) {\n        if (lastMode) container.removeClass(lastMode);\n\n        switch (mode) {\n          case MODE_QUERY:\n          case MODE_BUFFER:\n          case MODE_DETERMINATE:\n          case MODE_INDETERMINATE:\n            container.addClass(lastMode = \"md-mode-\" + mode);\n            break;\n          default:\n            container.addClass(lastMode = \"md-mode-\" + MODE_INDETERMINATE);\n            break;\n        }\n      });\n    }\n\n    /**\n     * Auto-defaults the mode to either `determinate` or `indeterminate` mode; if not specified\n     */\n    function validateMode() {\n      if (angular.isUndefined(attr.mdMode)) {\n        var hasValue = angular.isDefined(attr.value);\n        var mode = hasValue ? MODE_DETERMINATE : MODE_INDETERMINATE;\n        var info = \"Auto-adding the missing md-mode='{0}' to the ProgressLinear element\";\n        element.attr(\"md-mode\", mode);\n        attr.mdMode = mode;\n      }\n    }\n\n    /**\n     * Is the md-mode a valid option?\n     */\n    function mode() {\n      var value = (attr.mdMode || \"\").trim();\n      if (value) {\n        switch (value) {\n          case MODE_DETERMINATE:\n          case MODE_INDETERMINATE:\n          case MODE_BUFFER:\n          case MODE_QUERY:\n            break;\n          default:\n            value = MODE_INDETERMINATE;\n            break;\n        }\n      }\n      return value;\n    }\n\n    /**\n     * Manually set CSS to animate the Determinate indicator based on the specified\n     * percentage value (0-100).\n     */\n    function animateIndicator(target, value) {\n      if (isDisabled || !mode()) return;\n\n      var to = $mdUtil.supplant(\"translateX({0}%) scale({1},1)\", [(value-100)/2, value/100]);\n      var styles = toVendorCSS({ transform : to });\n      angular.element(target).css(styles);\n    }\n  }\n\n  /**\n   * Clamps the value to be between 0 and 100.\n   * @param {number} value The value to clamp.\n   * @returns {number}\n   */\n  function clamp(value) {\n    return Math.max(0, Math.min(value || 0, 100));\n  }\n}\n\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.radioButton\n * @description radioButton module!\n */\nmdRadioGroupDirective.$inject = [\"$mdUtil\", \"$mdConstant\", \"$mdTheming\", \"$timeout\"];\nmdRadioButtonDirective.$inject = [\"$mdAria\", \"$mdUtil\", \"$mdTheming\"];\nangular.module('material.components.radioButton', [\n  'material.core'\n])\n  .directive('mdRadioGroup', mdRadioGroupDirective)\n  .directive('mdRadioButton', mdRadioButtonDirective);\n\n/**\n * @type {Readonly<{NEXT: number, CURRENT: number, PREVIOUS: number}>}\n */\nvar incrementSelection = Object.freeze({PREVIOUS: -1, CURRENT: 0, NEXT: 1});\n\n/**\n * @ngdoc directive\n * @module material.components.radioButton\n * @name mdRadioGroup\n *\n * @restrict E\n *\n * @description\n * The `<md-radio-group>` directive identifies a grouping\n * container for the 1..n grouped radio buttons; specified using nested\n * `<md-radio-button>` elements.\n *\n * The radio button uses the accent color by default. The primary color palette may be used with\n * the `md-primary` class.\n *\n * Note: `<md-radio-group>` and `<md-radio-button>` handle `tabindex` differently\n * than the native `<input type=\"radio\">` controls. Whereas the native controls\n * force the user to tab through all the radio buttons, `<md-radio-group>`\n * is focusable and by default the `<md-radio-button>`s are not.\n *\n * @param {string} ng-model Assignable angular expression to data-bind to.\n * @param {string=} ng-change AngularJS expression to be executed when input changes due to user\n *    interaction.\n * @param {boolean=} md-no-ink If present, disables ink ripple effects.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-radio-group ng-model=\"selected\">\n *   <md-radio-button ng-repeat=\"item in items\"\n *                    ng-value=\"item.value\" aria-label=\"{{item.label}}\">\n *     {{ item.label }}\n *   </md-radio-button>\n * </md-radio-group>\n * </hljs>\n */\nfunction mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {\n  RadioGroupController.prototype = createRadioGroupControllerProto();\n\n  return {\n    restrict: 'E',\n    controller: ['$element', RadioGroupController],\n    require: ['mdRadioGroup', '?ngModel'],\n    link: { pre: linkRadioGroup }\n  };\n\n  function linkRadioGroup(scope, element, attr, controllers) {\n    // private md component indicator for styling\n    element.addClass('_md');\n    $mdTheming(element);\n\n    var radioGroupController = controllers[0];\n    var ngModelCtrl = controllers[1] || $mdUtil.fakeNgModel();\n\n    radioGroupController.init(ngModelCtrl);\n\n    scope.mouseActive = false;\n\n    element\n      .attr({\n        'role': 'radiogroup',\n        'tabIndex': element.attr('tabindex') || '0'\n      })\n      .on('keydown', keydownListener)\n      .on('mousedown', function() {\n        scope.mouseActive = true;\n        $timeout(function() {\n          scope.mouseActive = false;\n        }, 100);\n      })\n      .on('focus', function() {\n        if (scope.mouseActive === false) {\n          radioGroupController.$element.addClass('md-focused');\n        }\n      })\n      .on('blur', function() {\n        radioGroupController.$element.removeClass('md-focused');\n      });\n\n    // Initially set the first radio button as the aria-activedescendant. This will be overridden\n    // if a 'checked' radio button gets rendered. We need to wait for the nextTick here so that the\n    // radio buttons have their id values assigned.\n    $mdUtil.nextTick(function () {\n      var radioButtons = getRadioButtons(radioGroupController.$element);\n      if (radioButtons.count() &&\n          !radioGroupController.$element[0].hasAttribute('aria-activedescendant')) {\n        radioGroupController.setActiveDescendant(radioButtons.first().id);\n      }\n    });\n\n    /**\n     * Apply the md-focused class if it isn't already applied.\n     */\n    function setFocus() {\n      if (!element.hasClass('md-focused')) { element.addClass('md-focused'); }\n    }\n\n    /**\n     * @param {KeyboardEvent} keyboardEvent\n     */\n    function keydownListener(keyboardEvent) {\n      var keyCode = keyboardEvent.which || keyboardEvent.keyCode;\n\n      // Only listen to events that we originated ourselves\n      // so that we don't trigger on things like arrow keys in inputs.\n      if (keyCode !== $mdConstant.KEY_CODE.ENTER &&\n          keyboardEvent.currentTarget !== keyboardEvent.target) {\n        return;\n      }\n\n      switch (keyCode) {\n        case $mdConstant.KEY_CODE.LEFT_ARROW:\n        case $mdConstant.KEY_CODE.UP_ARROW:\n          keyboardEvent.preventDefault();\n          radioGroupController.selectPrevious();\n          setFocus();\n          break;\n\n        case $mdConstant.KEY_CODE.RIGHT_ARROW:\n        case $mdConstant.KEY_CODE.DOWN_ARROW:\n          keyboardEvent.preventDefault();\n          radioGroupController.selectNext();\n          setFocus();\n          break;\n\n        case $mdConstant.KEY_CODE.SPACE:\n          keyboardEvent.preventDefault();\n          radioGroupController.selectCurrent();\n          break;\n\n        case $mdConstant.KEY_CODE.ENTER:\n          var form = angular.element($mdUtil.getClosest(element[0], 'form'));\n          if (form.length > 0) {\n            form.triggerHandler('submit');\n          }\n          break;\n      }\n    }\n  }\n\n  /**\n   * @param {JQLite} $element\n   * @constructor\n   */\n  function RadioGroupController($element) {\n    this._radioButtonRenderFns = [];\n    this.$element = $element;\n  }\n\n  function createRadioGroupControllerProto() {\n    return {\n      init: function(ngModelCtrl) {\n        this._ngModelCtrl = ngModelCtrl;\n        this._ngModelCtrl.$render = angular.bind(this, this.render);\n      },\n      add: function(rbRender) {\n        this._radioButtonRenderFns.push(rbRender);\n      },\n      remove: function(rbRender) {\n        var index = this._radioButtonRenderFns.indexOf(rbRender);\n        if (index !== -1) {\n          this._radioButtonRenderFns.splice(index, 1);\n        }\n      },\n      render: function() {\n        this._radioButtonRenderFns.forEach(function(rbRender) {\n          rbRender();\n        });\n      },\n      setViewValue: function(value, eventType) {\n        this._ngModelCtrl.$setViewValue(value, eventType);\n        // update the other radio buttons as well\n        this.render();\n      },\n      getViewValue: function() {\n        return this._ngModelCtrl.$viewValue;\n      },\n      selectCurrent: function() {\n        return changeSelectedButton(this.$element, incrementSelection.CURRENT);\n      },\n      selectNext: function() {\n        return changeSelectedButton(this.$element, incrementSelection.NEXT);\n      },\n      selectPrevious: function() {\n        return changeSelectedButton(this.$element, incrementSelection.PREVIOUS);\n      },\n      setActiveDescendant: function (radioId) {\n        this.$element.attr('aria-activedescendant', radioId);\n      },\n      isDisabled: function() {\n        return this.$element[0].hasAttribute('disabled');\n      }\n    };\n  }\n\n  /**\n   * Coerce all child radio buttons into an array, then wrap them in an iterator.\n   * @param parent {!JQLite}\n   * @return {{add: add, next: (function()), last: (function(): any|null), previous: (function()), count: (function(): number), hasNext: (function(*=): Array.length|*|number|boolean), inRange: (function(*): boolean), remove: remove, contains: (function(*=): *|boolean), itemAt: (function(*=): any|null), findBy: (function(*, *): *[]), hasPrevious: (function(*=): Array.length|*|number|boolean), items: (function(): *[]), indexOf: (function(*=): number), first: (function(): any|null)}}\n   */\n  function getRadioButtons(parent) {\n    return $mdUtil.iterator(parent[0].querySelectorAll('md-radio-button'), true);\n  }\n\n  /**\n   * Change the radio group's selected button by a given increment.\n   * If no button is selected, select the first button.\n   * @param {JQLite} parent the md-radio-group\n   * @param {incrementSelection} increment enum that determines whether the next or\n   *  previous button is clicked. For current, only the first button is selected, otherwise the\n   *  current selection is maintained (by doing nothing).\n   */\n  function changeSelectedButton(parent, increment) {\n    var buttons = getRadioButtons(parent);\n    var target;\n\n    if (buttons.count()) {\n      var validate = function (button) {\n        // If disabled, then NOT valid\n        return !angular.element(button).attr(\"disabled\");\n      };\n\n      var selected = parent[0].querySelector('md-radio-button.md-checked');\n      if (!selected) {\n        target = buttons.first();\n      } else if (increment === incrementSelection.PREVIOUS ||\n                 increment === incrementSelection.NEXT) {\n        target = buttons[\n          increment === incrementSelection.PREVIOUS ? 'previous' : 'next'\n        ](selected, validate);\n      }\n\n      if (target) {\n        // Activate radioButton's click listener (triggerHandler won't create a real click event)\n        angular.element(target).triggerHandler('click');\n      }\n    }\n  }\n}\n\n/**\n * @ngdoc directive\n * @module material.components.radioButton\n * @name mdRadioButton\n *\n * @restrict E\n *\n * @description\n * The `<md-radio-button>`directive is the child directive required to be used within `<md-radio-group>` elements.\n *\n * While similar to the `<input type=\"radio\" ng-model=\"\" value=\"\">` directive,\n * the `<md-radio-button>` directive provides ink effects, ARIA support, and\n * supports use within named radio groups.\n *\n * One of `value` or `ng-value` must be set so that the `md-radio-group`'s model is set properly when the\n * `md-radio-button` is selected.\n *\n * @param {string} value The value to which the model should be set when selected.\n * @param {string} ng-value AngularJS expression which sets the value to which the model should\n *    be set when selected.\n * @param {string=} name Property name of the form under which the control is published.\n * @param {string=} aria-label Adds label to radio button for accessibility.\n *    Defaults to radio button's text. If no text content is available, a warning will be logged.\n *\n * @usage\n * <hljs lang=\"html\">\n *\n * <md-radio-button value=\"1\" aria-label=\"Label 1\">\n *   Label 1\n * </md-radio-button>\n *\n * <md-radio-button ng-value=\"specialValue\" aria-label=\"Green\">\n *   Green\n * </md-radio-button>\n *\n * </hljs>\n *\n */\nfunction mdRadioButtonDirective($mdAria, $mdUtil, $mdTheming) {\n\n  var CHECKED_CSS = 'md-checked';\n\n  return {\n    restrict: 'E',\n    require: '^mdRadioGroup',\n    transclude: true,\n    template: '<div class=\"md-container\" md-ink-ripple md-ink-ripple-checkbox>' +\n                '<div class=\"md-off\"></div>' +\n                '<div class=\"md-on\"></div>' +\n              '</div>' +\n              '<div ng-transclude class=\"md-label\"></div>',\n    link: link\n  };\n\n  function link(scope, element, attr, radioGroupController) {\n    var lastChecked;\n\n    $mdTheming(element);\n    configureAria(element);\n    element.addClass('md-auto-horizontal-margin');\n\n    // ngAria overwrites the aria-checked inside a $watch for ngValue.\n    // We should defer the initialization until all the watches have fired.\n    // This can also be fixed by removing the `lastChecked` check, but that'll\n    // cause more DOM manipulation on each digest.\n    if (attr.ngValue) {\n      $mdUtil.nextTick(initialize, false);\n    } else {\n      initialize();\n    }\n\n    /**\n     * Initializes the component.\n     */\n    function initialize() {\n      if (!radioGroupController) {\n        throw 'RadioButton: No RadioGroupController could be found.';\n      }\n\n      radioGroupController.add(render);\n      attr.$observe('value', render);\n\n      element\n        .on('click', listener)\n        .on('$destroy', function() {\n          radioGroupController.remove(render);\n        });\n    }\n\n    /**\n     * On click functionality.\n     */\n    function listener(ev) {\n      if (element[0].hasAttribute('disabled') || radioGroupController.isDisabled()) return;\n\n      scope.$apply(function() {\n        radioGroupController.setViewValue(attr.value, ev && ev.type);\n      });\n    }\n\n    /**\n     * Add or remove the `.md-checked` class from the RadioButton (and conditionally its parent).\n     * Update the `aria-activedescendant` attribute.\n     */\n    function render() {\n      var checked = radioGroupController.getViewValue() == attr.value;\n\n      if (checked === lastChecked) return;\n\n      if (element[0] && element[0].parentNode &&\n          element[0].parentNode.nodeName.toLowerCase() !== 'md-radio-group') {\n        // If the radioButton is inside a div, then add class so highlighting will work.\n        element.parent().toggleClass(CHECKED_CSS, checked);\n      }\n\n      if (checked) {\n        radioGroupController.setActiveDescendant(element.attr('id'));\n      }\n\n      lastChecked = checked;\n\n      element\n        .attr('aria-checked', checked)\n        .toggleClass(CHECKED_CSS, checked);\n    }\n\n    /**\n     * Inject ARIA-specific attributes appropriate for each radio button\n     */\n    function configureAria(element) {\n      element.attr({\n        id: attr.id || 'radio_' + $mdUtil.nextUid(),\n        role: 'radio',\n        'aria-checked': 'false'\n      });\n\n      $mdAria.expectWithText(element, 'aria-label');\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.select\n */\n\n/***************************************************\n\n ### TODO ###\n - [ ] Abstract placement logic in $mdSelect service to $mdMenu service\n\n ***************************************************/\n\nSelectDirective.$inject = [\"$mdSelect\", \"$mdUtil\", \"$mdConstant\", \"$mdTheming\", \"$mdAria\", \"$parse\", \"$sce\"];\nSelectMenuDirective.$inject = [\"$parse\", \"$mdUtil\", \"$mdConstant\", \"$mdTheming\"];\nOptionDirective.$inject = [\"$mdButtonInkRipple\", \"$mdUtil\", \"$mdTheming\"];\nSelectProvider.$inject = [\"$$interimElementProvider\"];\nOptionController.$inject = [\"$element\"];\nvar SELECT_EDGE_MARGIN = 8;\nvar selectNextId = 0;\nvar CHECKBOX_SELECTION_INDICATOR =\n  angular.element('<div class=\"md-container\"><div class=\"md-icon\"></div></div>');\n\nangular.module('material.components.select', [\n    'material.core',\n    'material.components.backdrop'\n  ])\n  .directive('mdSelect', SelectDirective)\n  .directive('mdSelectMenu', SelectMenuDirective)\n  .directive('mdOption', OptionDirective)\n  .directive('mdOptgroup', OptgroupDirective)\n  .directive('mdSelectHeader', SelectHeaderDirective)\n  .provider('$mdSelect', SelectProvider);\n\n/**\n * @ngdoc directive\n * @name mdSelect\n * @restrict E\n * @module material.components.select\n *\n * @description Displays a select box, bound to an `ng-model`. Selectable options are defined using\n * the <a ng-href=\"api/directive/mdOption\">md-option</a> element directive. Options can be grouped\n * using the <a ng-href=\"api/directive/mdOptgroup\">md-optgroup</a> element directive.\n *\n * When the select is required and uses a floating label, then the label will automatically contain\n * an asterisk (`*`). This behavior can be disabled by using the `md-no-asterisk` attribute.\n *\n * By default, the select will display with an underline to match other form elements. This can be\n * disabled by applying the `md-no-underline` CSS class.\n *\n * @param {expression} ng-model Assignable angular expression to data-bind to.\n * @param {expression=} ng-change Expression to be executed when the model value changes.\n * @param {boolean=} multiple When present, allows for more than one option to be selected.\n *  The model is an array with the selected choices. **Note:** This attribute is only evaluated\n *  once; it is not watched.\n * @param {expression=} md-on-close Expression to be evaluated when the select is closed.\n * @param {expression=} md-on-open Expression to be evaluated when opening the select.\n *  Will hide the select options and show a spinner until the evaluated promise resolves.\n * @param {expression=} md-selected-text Expression to be evaluated that will return a string\n *  to be displayed as a placeholder in the select input box when it is closed. The value\n *  will be treated as *text* (not html).\n * @param {expression=} md-selected-html Expression to be evaluated that will return a string\n *  to be displayed as a placeholder in the select input box when it is closed. The value\n *  will be treated as *html*. The value must either be explicitly marked as trustedHtml or\n *  the ngSanitize module must be loaded.\n * @param {string=} placeholder Placeholder hint text.\n * @param {boolean=} md-no-asterisk When set to true, an asterisk will not be appended to the\n *  floating label. **Note:** This attribute is only evaluated once; it is not watched.\n * @param {string=} aria-label Optional label for accessibility. Only necessary if no explicit label\n *  is present.\n * @param {string=} md-container-class Class list to get applied to the `.md-select-menu-container`\n *  element (for custom styling).\n * @param {string=} md-select-only-option If specified, a `<md-select>` will automatically select\n * it's first option, if it only has one.\n *\n * @usage\n * With a placeholder (label and aria-label are added dynamically)\n * <hljs lang=\"html\">\n *   <md-input-container>\n *     <md-select\n *       ng-model=\"someModel\"\n *       placeholder=\"Select a state\">\n *       <md-option ng-value=\"opt\" ng-repeat=\"opt in neighborhoods2\">{{ opt }}</md-option>\n *     </md-select>\n *   </md-input-container>\n * </hljs>\n *\n * With an explicit label\n * <hljs lang=\"html\">\n *   <md-input-container>\n *     <label>State</label>\n *     <md-select\n *       ng-model=\"someModel\">\n *       <md-option ng-value=\"opt\" ng-repeat=\"opt in neighborhoods2\">{{ opt }}</md-option>\n *     </md-select>\n *   </md-input-container>\n * </hljs>\n *\n * Using the `md-select-header` element directive\n *\n * When a developer needs to put more than just a text label in the `md-select-menu`, they should\n * use one or more `md-select-header`s. These elements can contain custom HTML which can be styled\n * as desired. Use cases for this element include a sticky search bar and custom option group\n * labels.\n *\n * <hljs lang=\"html\">\n *   <md-input-container>\n *     <md-select ng-model=\"someModel\">\n *       <md-select-header>\n *         <span> Neighborhoods - </span>\n *       </md-select-header>\n *       <md-option ng-value=\"opt\" ng-repeat=\"opt in neighborhoods2\">{{ opt }}</md-option>\n *     </md-select>\n *   </md-input-container>\n * </hljs>\n *\n * ## Selects and object equality\n * When using a `md-select` to pick from a list of objects, it is important to realize how javascript handles\n * equality. Consider the following example:\n * <hljs lang=\"js\">\n * angular.controller('MyCtrl', function($scope) {\n *   $scope.users = [\n *     { id: 1, name: 'Bob' },\n *     { id: 2, name: 'Alice' },\n *     { id: 3, name: 'Steve' }\n *   ];\n *   $scope.selectedUser = { id: 1, name: 'Bob' };\n * });\n * </hljs>\n * <hljs lang=\"html\">\n * <div ng-controller=\"MyCtrl\">\n *   <md-select ng-model=\"selectedUser\">\n *     <md-option ng-value=\"user\" ng-repeat=\"user in users\">{{ user.name }}</md-option>\n *   </md-select>\n * </div>\n * </hljs>\n *\n * At first one might expect that the select should be populated with \"Bob\" as the selected user.\n * However, this is not true. To determine whether something is selected,\n * `ngModelController` is looking at whether `$scope.selectedUser == (any user in $scope.users);`;\n *\n * Javascript's `==` operator does not check for deep equality (ie. that all properties\n * on the object are the same), but instead whether the objects are *the same object in memory*.\n * In this case, we have two instances of identical objects, but they exist in memory as unique\n * entities. Because of this, the select will have no value populated for a selected user.\n *\n * To get around this, `ngModelController` provides a `track by` option that allows us to specify a\n * different expression which will be used for the equality operator. As such, we can update our\n * `html` to make use of this by specifying the `ng-model-options=\"{trackBy: '$value.id'}\"` on the\n * `md-select` element. This converts our equality expression to be\n * `$scope.selectedUser.id == (any id in $scope.users.map(function(u) { return u.id; }));`\n * which results in Bob being selected as desired.\n *\n * **Note:** We do not support AngularJS's `track by` syntax. For instance\n *  `ng-options=\"user in users track by user.id\"` will not work with `md-select`.\n *\n * Working HTML:\n * <hljs lang=\"html\">\n * <div ng-controller=\"MyCtrl\">\n *   <md-select ng-model=\"selectedUser\" ng-model-options=\"{trackBy: '$value.id'}\">\n *     <md-option ng-value=\"user\" ng-repeat=\"user in users\">{{ user.name }}</md-option>\n *   </md-select>\n * </div>\n * </hljs>\n */\nfunction SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $parse, $sce) {\n  return {\n    restrict: 'E',\n    require: ['^?mdInputContainer', 'mdSelect', 'ngModel', '?^form'],\n    compile: compile,\n    controller: function() {\n    } // empty placeholder controller to be initialized in link\n  };\n\n  /**\n   * @param {JQLite} tElement\n   * @param {IAttributes} tAttrs\n   * @return {postLink}\n   */\n  function compile(tElement, tAttrs) {\n    var isMultiple = $mdUtil.parseAttributeBoolean(tAttrs.multiple);\n    tElement.addClass('md-auto-horizontal-margin');\n\n    // add the select value that will hold our placeholder or selected option value\n    var valueEl = angular.element('<md-select-value><span></span></md-select-value>');\n    valueEl.append('<span class=\"md-select-icon\" aria-hidden=\"true\"></span>');\n    valueEl.addClass('md-select-value');\n    if (!valueEl[0].hasAttribute('id')) {\n      valueEl.attr('id', 'select_value_label_' + $mdUtil.nextUid());\n    }\n\n    // There's got to be an md-content inside. If there's not one, let's add it.\n    var mdContentEl = tElement.find('md-content');\n    if (!mdContentEl.length) {\n      tElement.append(angular.element('<md-content>').append(tElement.contents()));\n      mdContentEl = tElement.find('md-content');\n    }\n    mdContentEl.attr('role', 'listbox');\n    mdContentEl.attr('tabindex', '-1');\n\n    if (isMultiple) {\n      mdContentEl.attr('aria-multiselectable', 'true');\n    } else {\n      mdContentEl.attr('aria-multiselectable', 'false');\n    }\n\n    // Add progress spinner for md-options-loading\n    if (tAttrs.mdOnOpen) {\n\n      // Show progress indicator while loading async\n      // Use ng-hide for `display:none` so the indicator does not interfere with the options list\n      tElement\n        .find('md-content')\n        .prepend(angular.element(\n          '<div>' +\n          ' <md-progress-circular md-mode=\"indeterminate\" ng-if=\"$$loadingAsyncDone === false\"' +\n          ' md-diameter=\"25px\"></md-progress-circular>' +\n          '</div>'\n        ));\n\n      // Hide list [of item options] while loading async\n      tElement\n        .find('md-option')\n        .attr('ng-show', '$$loadingAsyncDone');\n    }\n\n    if (tAttrs.name) {\n      var autofillClone = angular.element('<select class=\"md-visually-hidden\"></select>');\n      autofillClone.attr({\n        'name': tAttrs.name,\n        'aria-hidden': 'true',\n        'tabindex': '-1'\n      });\n      var opts = tElement.find('md-option');\n      angular.forEach(opts, function(el) {\n        var newEl = angular.element('<option>' + el.innerHTML + '</option>');\n        if (el.hasAttribute('ng-value')) {\n          newEl.attr('ng-value', el.getAttribute('ng-value'));\n        }\n        else if (el.hasAttribute('value')) {\n          newEl.attr('value', el.getAttribute('value'));\n        }\n        autofillClone.append(newEl);\n      });\n\n      // Adds an extra option that will hold the selected value for the\n      // cases where the select is a part of a non-AngularJS form. This can be done with a ng-model,\n      // however if the `md-option` is being `ng-repeat`-ed, AngularJS seems to insert a similar\n      // `option` node, but with a value of `? string: <value> ?` which would then get submitted.\n      // This also goes around having to prepend a dot to the name attribute.\n      autofillClone.append(\n        '<option ng-value=\"' + tAttrs.ngModel + '\" selected></option>'\n      );\n\n      tElement.parent().append(autofillClone);\n    }\n\n    // Use everything that's left inside element.contents() as the contents of the menu\n    var multipleContent = isMultiple ? 'multiple' : '';\n    var ngModelOptions = tAttrs.ngModelOptions ? $mdUtil.supplant('ng-model-options=\"{0}\"', [tAttrs.ngModelOptions]) : '';\n    var selectTemplate = '' +\n      '<div class=\"md-select-menu-container\" aria-hidden=\"true\" role=\"presentation\">' +\n      '  <md-select-menu role=\"presentation\" {0} {1}>{2}</md-select-menu>' +\n      '</div>';\n\n    selectTemplate = $mdUtil.supplant(selectTemplate, [multipleContent, ngModelOptions,  tElement.html()]);\n    tElement.empty().append(valueEl);\n    tElement.append(selectTemplate);\n\n    if (!tAttrs.tabindex) {\n      tAttrs.$set('tabindex', 0);\n    }\n\n    return function postLink(scope, element, attrs, ctrls) {\n      var untouched = true;\n      var isDisabled;\n\n      var containerCtrl = ctrls[0];\n      var mdSelectCtrl = ctrls[1];\n      var ngModelCtrl = ctrls[2];\n      var formCtrl = ctrls[3];\n      // grab a reference to the select menu value label\n      var selectValueElement = element.find('md-select-value');\n      var isReadonly = angular.isDefined(attrs.readonly);\n      var disableAsterisk = $mdUtil.parseAttributeBoolean(attrs.mdNoAsterisk);\n      var stopMdMultipleWatch;\n      var userDefinedLabelledby = angular.isDefined(attrs.ariaLabelledby);\n      var listboxContentElement = element.find('md-content');\n      var initialPlaceholder = element.attr('placeholder');\n\n      if (disableAsterisk) {\n        element.addClass('md-no-asterisk');\n      }\n\n      if (containerCtrl) {\n        var isErrorGetter = containerCtrl.isErrorGetter || function() {\n          return ngModelCtrl.$invalid && (ngModelCtrl.$touched || (formCtrl && formCtrl.$submitted));\n        };\n\n        if (containerCtrl.input) {\n          // We ignore inputs that are in the md-select-header.\n          // One case where this might be useful would be adding as searchbox.\n          if (element.find('md-select-header').find('input')[0] !== containerCtrl.input[0]) {\n            throw new Error(\"<md-input-container> can only have *one* child <input>, <textarea>, or <select> element!\");\n          }\n        }\n\n        containerCtrl.input = element;\n        if (!containerCtrl.label) {\n          $mdAria.expect(element, 'aria-label', initialPlaceholder);\n          var selectLabel = element.attr('aria-label');\n          if (!selectLabel) {\n            selectLabel = initialPlaceholder;\n          }\n          listboxContentElement.attr('aria-label', selectLabel);\n        } else {\n          containerCtrl.label.attr('aria-hidden', 'true');\n          listboxContentElement.attr('aria-label', containerCtrl.label.text());\n          containerCtrl.setHasPlaceholder(!!initialPlaceholder);\n        }\n\n        var stopInvalidWatch = scope.$watch(isErrorGetter, containerCtrl.setInvalid);\n      }\n\n      var selectContainer, selectScope, selectMenuCtrl;\n\n      selectContainer = findSelectContainer();\n      $mdTheming(element);\n\n      var originalRender = ngModelCtrl.$render;\n      ngModelCtrl.$render = function() {\n        originalRender();\n        syncSelectValueText();\n        inputCheckValue();\n      };\n\n      var stopPlaceholderObserver = attrs.$observe('placeholder', ngModelCtrl.$render);\n\n      var stopRequiredObserver = attrs.$observe('required', function (value) {\n        if (containerCtrl && containerCtrl.label) {\n          // Toggle the md-required class on the input containers label, because the input container\n          // is automatically applying the asterisk indicator on the label.\n          containerCtrl.label.toggleClass('md-required', value && !disableAsterisk);\n        }\n        element.removeAttr('aria-required');\n        if (value) {\n          listboxContentElement.attr('aria-required', 'true');\n        } else {\n          listboxContentElement.removeAttr('aria-required');\n        }\n      });\n\n      /**\n       * Set the contents of the md-select-value element. This element's contents are announced by\n       * screen readers and used for displaying the value of the select in both single and multiple\n       * selection modes.\n       * @param {string=} text A sanitized and trusted HTML string or a pure text string from user\n       *  input.\n       */\n      mdSelectCtrl.setSelectValueText = function(text) {\n        var useDefaultText = text === undefined || text === '';\n        // Whether the select label has been given via user content rather than the internal\n        // template of <md-option>\n        var isSelectLabelFromUser = false;\n\n        mdSelectCtrl.setIsPlaceholder(!text);\n\n        if (attrs.mdSelectedText && attrs.mdSelectedHtml) {\n          throw Error('md-select cannot have both `md-selected-text` and `md-selected-html`');\n        }\n\n        if (attrs.mdSelectedText || attrs.mdSelectedHtml) {\n          text = $parse(attrs.mdSelectedText || attrs.mdSelectedHtml)(scope);\n          isSelectLabelFromUser = true;\n        } else if (useDefaultText) {\n          // Use placeholder attribute, otherwise fallback to the md-input-container label\n          var tmpPlaceholder = attrs.placeholder ||\n              (containerCtrl && containerCtrl.label ? containerCtrl.label.text() : '');\n\n          text = tmpPlaceholder || '';\n          isSelectLabelFromUser = true;\n        }\n\n        var target = selectValueElement.children().eq(0);\n\n        if (attrs.mdSelectedHtml) {\n          // Using getTrustedHtml will run the content through $sanitize if it is not already\n          // explicitly trusted. If the ngSanitize module is not loaded, this will\n          // *correctly* throw an sce error.\n          target.html($sce.getTrustedHtml(text));\n        } else if (isSelectLabelFromUser) {\n          target.text(text);\n        } else {\n          // If we've reached this point, the text is not user-provided.\n          target.html(text);\n        }\n\n        if (useDefaultText) {\n          // Avoid screen readers double announcing the label name when no value has been selected\n          selectValueElement.attr('aria-hidden', 'true');\n          if (!userDefinedLabelledby) {\n            element.removeAttr('aria-labelledby');\n          }\n        } else {\n          selectValueElement.removeAttr('aria-hidden');\n          if (!userDefinedLabelledby) {\n            element.attr('aria-labelledby', element[0].id + ' ' + selectValueElement[0].id);\n          }\n        }\n      };\n\n      /**\n       * @param {boolean} isPlaceholder true to mark the md-select-value element and\n       *  input container, if one exists, with classes for styling when a placeholder is present.\n       *  false to remove those classes.\n       */\n      mdSelectCtrl.setIsPlaceholder = function(isPlaceholder) {\n          if (isPlaceholder) {\n            selectValueElement.addClass('md-select-placeholder');\n            // Don't hide the floating label if the md-select has a placeholder.\n            if (containerCtrl && containerCtrl.label && !element.attr('placeholder')) {\n              containerCtrl.label.addClass('md-placeholder');\n            }\n          } else {\n            selectValueElement.removeClass('md-select-placeholder');\n            if (containerCtrl && containerCtrl.label && !element.attr('placeholder')) {\n              containerCtrl.label.removeClass('md-placeholder');\n            }\n          }\n      };\n\n      if (!isReadonly) {\n        var handleBlur = function(event) {\n          // Attach before ngModel's blur listener to stop propagation of blur event\n          // and prevent setting $touched.\n          if (untouched) {\n            untouched = false;\n            if (selectScope._mdSelectIsOpen) {\n              event.stopImmediatePropagation();\n            }\n          }\n\n          containerCtrl && containerCtrl.setFocused(false);\n          inputCheckValue();\n        };\n        var handleFocus = function() {\n          // Always focus the container (if we have one) so floating labels and other styles are\n          // applied properly\n          containerCtrl && containerCtrl.setFocused(true);\n        };\n\n        element.on('focus', handleFocus);\n        element.on('blur', handleBlur);\n      }\n\n      mdSelectCtrl.triggerClose = function() {\n        $parse(attrs.mdOnClose)(scope);\n      };\n\n      scope.$$postDigest(function() {\n        initAriaLabel();\n        syncSelectValueText();\n      });\n\n      function initAriaLabel() {\n        var labelText = element.attr('aria-label') || element.attr('placeholder');\n        if (!labelText && containerCtrl && containerCtrl.label) {\n          labelText = containerCtrl.label.text();\n        }\n        $mdAria.expect(element, 'aria-label', labelText);\n      }\n\n      var stopSelectedLabelsWatcher = scope.$watch(function() {\n        return selectMenuCtrl.getSelectedLabels();\n      }, syncSelectValueText);\n\n      function syncSelectValueText() {\n        selectMenuCtrl = selectMenuCtrl ||\n          selectContainer.find('md-select-menu').controller('mdSelectMenu');\n        mdSelectCtrl.setSelectValueText(selectMenuCtrl.getSelectedLabels());\n      }\n\n      // TODO add tests for mdMultiple\n      // TODO add docs for mdMultiple\n      var stopMdMultipleObserver = attrs.$observe('mdMultiple', function(val) {\n        if (stopMdMultipleWatch) {\n          stopMdMultipleWatch();\n        }\n        var parser = $parse(val);\n        stopMdMultipleWatch = scope.$watch(function() {\n          return parser(scope);\n        }, function(multiple, prevVal) {\n          var selectMenu = selectContainer.find('md-select-menu');\n          // assume compiler did a good job\n          if (multiple === undefined && prevVal === undefined) {\n            return;\n          }\n          if (multiple) {\n            var setMultipleAttrs = {'multiple': 'multiple'};\n            element.attr(setMultipleAttrs);\n            selectMenu.attr(setMultipleAttrs);\n          } else {\n            element.removeAttr('multiple');\n            selectMenu.removeAttr('multiple');\n          }\n          element.find('md-content').attr('aria-multiselectable', multiple ? 'true' : 'false');\n\n          if (selectContainer) {\n            selectMenuCtrl.setMultiple(Boolean(multiple));\n            originalRender = ngModelCtrl.$render;\n            ngModelCtrl.$render = function() {\n              originalRender();\n              syncSelectValueText();\n              inputCheckValue();\n            };\n            ngModelCtrl.$render();\n          }\n        });\n      });\n\n      var stopDisabledObserver = attrs.$observe('disabled', function(disabled) {\n        if (angular.isString(disabled)) {\n          disabled = true;\n        }\n        // Prevent click event being registered twice\n        if (isDisabled !== undefined && isDisabled === disabled) {\n          return;\n        }\n        isDisabled = disabled;\n        if (disabled) {\n          element\n            .attr({'aria-disabled': 'true'})\n            .removeAttr('tabindex')\n            .removeAttr('aria-expanded')\n            .removeAttr('aria-haspopup')\n            .off('click', openSelect)\n            .off('keydown', handleKeypress);\n        } else {\n          element\n            .attr({\n              'tabindex': attrs.tabindex,\n              'aria-haspopup': 'listbox'\n            })\n            .removeAttr('aria-disabled')\n            .on('click', openSelect)\n            .on('keydown', handleKeypress);\n        }\n      });\n\n      if (!attrs.hasOwnProperty('disabled') && !attrs.hasOwnProperty('ngDisabled')) {\n        element.attr({'aria-disabled': 'false'});\n        element.on('click', openSelect);\n        element.on('keydown', handleKeypress);\n      }\n\n      var ariaAttrs = {\n        role: 'button',\n        'aria-haspopup': 'listbox'\n      };\n\n      if (!element[0].hasAttribute('id')) {\n        ariaAttrs.id = 'select_' + $mdUtil.nextUid();\n      }\n\n      var containerId = 'select_container_' + $mdUtil.nextUid();\n      selectContainer.attr('id', containerId);\n      var listboxContentId = 'select_listbox_' + $mdUtil.nextUid();\n      selectContainer.find('md-content').attr('id', listboxContentId);\n      // Only add aria-owns if element ownership is NOT represented in the DOM.\n      if (!element.find('md-select-menu').length) {\n        ariaAttrs['aria-owns'] = listboxContentId;\n      }\n      element.attr(ariaAttrs);\n\n      scope.$on('$destroy', function() {\n        stopRequiredObserver && stopRequiredObserver();\n        stopDisabledObserver && stopDisabledObserver();\n        stopMdMultipleWatch && stopMdMultipleWatch();\n        stopMdMultipleObserver && stopMdMultipleObserver();\n        stopSelectedLabelsWatcher && stopSelectedLabelsWatcher();\n        stopPlaceholderObserver && stopPlaceholderObserver();\n        stopInvalidWatch && stopInvalidWatch();\n\n        element.off('focus');\n        element.off('blur');\n\n        $mdSelect\n          .destroy()\n          .finally(function() {\n            if (containerCtrl) {\n              containerCtrl.setFocused(false);\n              containerCtrl.setHasValue(false);\n              containerCtrl.input = null;\n            }\n            ngModelCtrl.$setTouched();\n          });\n      });\n\n      function inputCheckValue() {\n        // The select counts as having a value if one or more options are selected,\n        // or if the input's validity state says it has bad input (eg: string in a number input).\n        // We must do this on nextTick as the $render is sometimes invoked on nextTick.\n        $mdUtil.nextTick(function () {\n          containerCtrl && containerCtrl.setHasValue(\n            selectMenuCtrl.getSelectedLabels().length > 0 || (element[0].validity || {}).badInput);\n        });\n      }\n\n      function findSelectContainer() {\n        var selectContainer = angular.element(\n          element[0].querySelector('.md-select-menu-container')\n        );\n        selectScope = scope;\n        attrs.mdContainerClass && selectContainer.addClass(attrs.mdContainerClass);\n        selectMenuCtrl = selectContainer.find('md-select-menu').controller('mdSelectMenu');\n        selectMenuCtrl.init(ngModelCtrl, attrs);\n        element.on('$destroy', function() {\n          selectContainer.remove();\n        });\n        return selectContainer;\n      }\n\n      /**\n       * Determine if the select menu should be opened or an option in the select menu should be\n       * selected.\n       * @param {KeyboardEvent} e keyboard event to handle\n       */\n      function handleKeypress(e) {\n        if ($mdConstant.isNavigationKey(e)) {\n          // prevent page scrolling on interaction\n          e.preventDefault();\n          openSelect(e);\n        } else {\n          if (shouldHandleKey(e, $mdConstant)) {\n            e.preventDefault();\n\n            var node = selectMenuCtrl.optNodeForKeyboardSearch(e);\n            if (!node || node.hasAttribute('disabled')) {\n              return;\n            }\n            var optionCtrl = angular.element(node).controller('mdOption');\n            if (!selectMenuCtrl.isMultiple) {\n              angular.forEach(Object.keys(selectMenuCtrl.selected), function (key) {\n                selectMenuCtrl.deselect(key);\n              });\n            }\n            selectMenuCtrl.select(optionCtrl.hashKey, optionCtrl.value);\n            selectMenuCtrl.refreshViewValue();\n          }\n        }\n      }\n\n      function openSelect() {\n        selectScope._mdSelectIsOpen = true;\n        element.attr('aria-expanded', 'true');\n\n        $mdSelect.show({\n          scope: selectScope,\n          preserveScope: true,\n          skipCompile: true,\n          element: selectContainer,\n          target: element[0],\n          selectCtrl: mdSelectCtrl,\n          preserveElement: true,\n          hasBackdrop: true,\n          loadingAsync: attrs.mdOnOpen ? scope.$eval(attrs.mdOnOpen) || true : false\n        }).finally(function() {\n          selectScope._mdSelectIsOpen = false;\n          element.removeAttr('aria-expanded');\n          element.removeAttr('aria-activedescendant');\n          ngModelCtrl.$setTouched();\n        });\n      }\n\n    };\n  }\n}\n\nfunction SelectMenuDirective($parse, $mdUtil, $mdConstant, $mdTheming) {\n  // We want the scope to be set to 'false' so an isolated scope is not created\n  // which would interfere with the md-select-header's access to the\n  // parent scope.\n  SelectMenuController.$inject = [\"$scope\", \"$attrs\", \"$element\"];\n  return {\n    restrict: 'E',\n    require: ['mdSelectMenu'],\n    scope: false,\n    controller: SelectMenuController,\n    link: {pre: preLink}\n  };\n\n  // We use preLink instead of postLink to ensure that the select is initialized before\n  // its child options run postLink.\n  function preLink(scope, element, attrs, ctrls) {\n    var selectMenuCtrl = ctrls[0];\n\n    element.addClass('_md');     // private md component indicator for styling\n\n    $mdTheming(element);\n    element.on('click', clickListener);\n    element.on('keypress', keyListener);\n\n    /**\n     * @param {KeyboardEvent} keyboardEvent\n     */\n    function keyListener(keyboardEvent) {\n      if (keyboardEvent.keyCode === 13 || keyboardEvent.keyCode === 32) {\n        clickListener(keyboardEvent);\n      }\n    }\n\n    /**\n     * @param {Event} mouseEvent\n     * @return {void}\n     */\n    function clickListener(mouseEvent) {\n      var option = $mdUtil.getClosest(mouseEvent.target, 'md-option');\n      var optionCtrl = option && angular.element(option).data('$mdOptionController');\n\n      if (!option || !optionCtrl) {\n        // Avoid closing the menu when the select header's input is clicked\n        if (mouseEvent.target && mouseEvent.target.parentNode &&\n          mouseEvent.target.parentNode.tagName === 'MD-SELECT-HEADER') {\n          mouseEvent.stopImmediatePropagation();\n        }\n        return;\n      } else if (option.hasAttribute('disabled')) {\n        mouseEvent.stopImmediatePropagation();\n        return;\n      }\n\n      var optionHashKey = selectMenuCtrl.hashGetter(optionCtrl.value);\n      var isSelected = angular.isDefined(selectMenuCtrl.selected[optionHashKey]);\n\n      scope.$apply(function() {\n        if (selectMenuCtrl.isMultiple) {\n          if (isSelected) {\n            selectMenuCtrl.deselect(optionHashKey);\n          } else {\n            selectMenuCtrl.select(optionHashKey, optionCtrl.value);\n          }\n        } else {\n          if (!isSelected) {\n            angular.forEach(Object.keys(selectMenuCtrl.selected), function (key) {\n              selectMenuCtrl.deselect(key);\n            });\n            selectMenuCtrl.select(optionHashKey, optionCtrl.value);\n          }\n        }\n        selectMenuCtrl.refreshViewValue();\n      });\n    }\n  }\n\n  function SelectMenuController($scope, $attrs, $element) {\n    var self = this;\n    var defaultIsEmpty;\n    var searchStr = '';\n    var clearSearchTimeout, optNodes, optText;\n    var CLEAR_SEARCH_AFTER = 300;\n\n    self.isMultiple = angular.isDefined($attrs.multiple);\n    // selected is an object with keys matching all of the selected options' hashed values\n    self.selected = {};\n    // options is an object with keys matching every option's hash value,\n    // and values containing an instance of every option's controller.\n    self.options = {};\n\n    $scope.$watchCollection(function() {\n      return self.options;\n    }, function() {\n      self.ngModel.$render();\n      updateOptionSetSizeAndPosition();\n    });\n\n    /**\n     * @param {boolean} isMultiple\n     */\n    self.setMultiple = function(isMultiple) {\n      var ngModel = self.ngModel;\n      defaultIsEmpty = defaultIsEmpty || ngModel.$isEmpty;\n      self.isMultiple = isMultiple;\n\n      if (self.isMultiple) {\n        // We want to delay the render method so that the directive has a chance to load before\n        // rendering, this prevents the control being marked as dirty onload.\n        var loaded = false;\n        var delayedRender = function(val) {\n          if (!loaded) {\n            $mdUtil.nextTick(function () {\n              renderMultiple(val);\n              loaded = true;\n            });\n          } else {\n            renderMultiple(val);\n          }\n        };\n        ngModel.$validators['md-multiple'] = validateArray;\n        ngModel.$render = delayedRender;\n\n        // watchCollection on the model because by default ngModel only watches the model's\n        // reference. This allows the developer to also push and pop from their array.\n        $scope.$watchCollection(self.modelBinding, function(value) {\n          if (validateArray(value)) {\n            delayedRender(value);\n          }\n        });\n\n        ngModel.$isEmpty = function(value) {\n          return !value || value.length === 0;\n        };\n      } else {\n        delete ngModel.$validators['md-multiple'];\n        ngModel.$render = renderSingular;\n      }\n\n      function validateArray(modelValue, viewValue) {\n        // If a value is truthy but not an array, reject it.\n        // If value is undefined/falsy, accept that it's an empty array.\n        return angular.isArray(modelValue || viewValue || []);\n      }\n    };\n\n    /**\n     * @param {KeyboardEvent} keyboardEvent keyboard event to handle\n     * @return {Element|HTMLElement|undefined}\n     */\n    self.optNodeForKeyboardSearch = function(keyboardEvent) {\n      var search, i;\n      clearSearchTimeout && clearTimeout(clearSearchTimeout);\n      clearSearchTimeout = setTimeout(function() {\n        clearSearchTimeout = undefined;\n        searchStr = '';\n        optText = undefined;\n        optNodes = undefined;\n      }, CLEAR_SEARCH_AFTER);\n\n      searchStr += keyboardEvent.key;\n      search = new RegExp('^' + $mdUtil.sanitize(searchStr), 'i');\n      if (!optNodes) {\n        optNodes = $element.find('md-option');\n        optText = new Array(optNodes.length);\n        angular.forEach(optNodes, function(el, i) {\n          optText[i] = el.textContent.trim();\n        });\n      }\n\n      for (i = 0; i < optText.length; ++i) {\n        if (search.test(optText[i])) {\n          return optNodes[i];\n        }\n      }\n    };\n\n    self.init = function(ngModel, parentAttrs) {\n      self.ngModel = ngModel;\n      self.modelBinding = parentAttrs.ngModel;\n\n      // Setup a more robust version of isEmpty to ensure value is a valid option\n      self.ngModel.$isEmpty = function($viewValue) {\n        // We have to transform the viewValue into the hashKey, because otherwise the\n        // OptionCtrl may not exist. Developers may have specified a trackBy function.\n        var hashedValue = self.options[self.hashGetter($viewValue)] ? self.options[self.hashGetter($viewValue)].value : null;\n        // Base this check on the default AngularJS $isEmpty() function.\n        // eslint-disable-next-line no-self-compare\n        return !angular.isDefined(hashedValue) || hashedValue === null || hashedValue === '' || hashedValue !== hashedValue;\n      };\n\n      // Allow users to provide `ng-model=\"foo\" ng-model-options=\"{trackBy: '$value.id'}\"` so\n      // that we can properly compare objects set on the model to the available options\n      //\n      // If the user doesn't provide a trackBy, we automatically generate an id for every\n      // value passed in with the getId function\n      if ($attrs.ngModelOptions) {\n        self.hashGetter = function(value) {\n          var ngModelOptions = $parse($attrs.ngModelOptions)($scope);\n          var trackByOption = ngModelOptions && ngModelOptions.trackBy;\n\n          if (trackByOption) {\n            return $parse(trackByOption)($scope, { $value: value });\n          } else if (angular.isObject(value)) {\n            return getId(value);\n          }\n          return value;\n        };\n      } else {\n        self.hashGetter = getId;\n      }\n      self.setMultiple(self.isMultiple);\n\n      /**\n       * If the value is an object, get the unique, incremental id of the value.\n       * If it's not an object, the value will be converted to a string and then returned.\n       * @param value\n       * @returns {string}\n       */\n      function getId(value) {\n        if (angular.isObject(value) && !angular.isArray(value)) {\n          return 'object_' + (value.$$mdSelectId || (value.$$mdSelectId = ++selectNextId));\n        }\n        return value + '';\n      }\n\n      if (parentAttrs.hasOwnProperty('mdSelectOnlyOption')) {\n        $mdUtil.nextTick(function() {\n          var optionKeys = Object.keys(self.options);\n\n          if (optionKeys.length === 1) {\n            var option = self.options[optionKeys[0]];\n\n            self.deselect(Object.keys(self.selected)[0]);\n            self.select(self.hashGetter(option.value), option.value);\n            self.refreshViewValue();\n            self.ngModel.$setPristine();\n          }\n        }, false);\n      }\n    };\n\n    /**\n     * @param {string=} id\n     */\n    self.setActiveDescendant = function(id) {\n      if (angular.isDefined(id)) {\n        $element.find('md-content').attr('aria-activedescendant', id);\n      } else {\n        $element.find('md-content').removeAttr('aria-activedescendant');\n      }\n    };\n\n    /**\n     * @param {{mode: string}=} opts options object to allow specifying html (default) or aria mode.\n     * @return {string} comma separated set of selected values\n     */\n    self.getSelectedLabels = function(opts) {\n      opts = opts || {};\n      var mode = opts.mode || 'html';\n      var selectedOptionEls =\n        $mdUtil.nodesToArray($element[0].querySelectorAll('md-option[selected]'));\n\n      if (selectedOptionEls.length) {\n        var mapFn;\n\n        if (mode === 'html') {\n          // Map the given element to its innerHTML string. If the element has a child ripple\n          // container remove it from the HTML string, before returning the string.\n          mapFn = function(el) {\n            // If we do not have a `value` or `ng-value`, assume it is an empty option which clears\n            // the select.\n            if (el.hasAttribute('md-option-empty')) {\n              return '';\n            }\n\n            var html = el.innerHTML;\n\n            // Remove the ripple container from the selected option, copying it would cause a CSP\n            // violation.\n            var rippleContainer = el.querySelector('.md-ripple-container');\n            if (rippleContainer) {\n              html = html.replace(rippleContainer.outerHTML, '');\n            }\n\n            // Remove the checkbox container, because it will cause the label to wrap inside of the\n            // placeholder. It should be not displayed inside of the label element.\n            var checkboxContainer = el.querySelector('.md-container');\n            if (checkboxContainer) {\n              html = html.replace(checkboxContainer.outerHTML, '');\n            }\n\n            return html;\n          };\n        } else if (mode === 'aria') {\n          mapFn = function(el) {\n            return el.hasAttribute('aria-label') ? el.getAttribute('aria-label') : el.textContent;\n          };\n        }\n\n        // Ensure there are no duplicates; see https://github.com/angular/material/issues/9442\n        return $mdUtil.uniq(selectedOptionEls.map(mapFn)).join(', ');\n      } else {\n        return '';\n      }\n    };\n\n    /**\n     * Mark an option as selected\n     * @param {string} hashKey key within the SelectMenuController.options object, which is an\n     *  instance of OptionController.\n     * @param {OptionController} hashedValue value to associate with the key\n     */\n    self.select = function(hashKey, hashedValue) {\n      var option = self.options[hashKey];\n      option && option.setSelected(true, self.isMultiple);\n      self.selected[hashKey] = hashedValue;\n    };\n\n    /**\n     * Mark an option as not selected\n     * @param {string} hashKey key within the SelectMenuController.options object, which is an\n     *  instance of OptionController.\n     */\n    self.deselect = function(hashKey) {\n      var option = self.options[hashKey];\n      option && option.setSelected(false, self.isMultiple);\n      delete self.selected[hashKey];\n    };\n\n    /**\n     * Add an option to the select\n     * @param {string} hashKey key within the SelectMenuController.options object, which is an\n     *  instance of OptionController.\n     * @param {OptionController} optionCtrl instance to associate with the key\n     */\n    self.addOption = function(hashKey, optionCtrl) {\n      if (angular.isDefined(self.options[hashKey])) {\n        throw new Error('Duplicate md-option values are not allowed in a select. ' +\n          'Duplicate value \"' + optionCtrl.value + '\" found.');\n      }\n\n      self.options[hashKey] = optionCtrl;\n\n      // If this option's value was already in our ngModel, go ahead and select it.\n      if (angular.isDefined(self.selected[hashKey])) {\n        self.select(hashKey, optionCtrl.value);\n\n        // When the current $modelValue of the ngModel Controller is using the same hash as\n        // the current option, which will be added, then we can be sure, that the validation\n        // of the option has occurred before the option was added properly.\n        // This means, that we have to manually trigger a new validation of the current option.\n        if (angular.isDefined(self.ngModel.$$rawModelValue) &&\n            self.hashGetter(self.ngModel.$$rawModelValue) === hashKey) {\n          self.ngModel.$validate();\n        }\n\n        self.refreshViewValue();\n      }\n    };\n\n    /**\n     * Remove an option from the select\n     * @param {string} hashKey key within the SelectMenuController.options object, which is an\n     *  instance of OptionController.\n     */\n    self.removeOption = function(hashKey) {\n      delete self.options[hashKey];\n      // Don't deselect an option when it's removed - the user's ngModel should be allowed\n      // to have values that do not match a currently available option.\n    };\n\n    self.refreshViewValue = function() {\n      var values = [];\n      var option;\n      for (var hashKey in self.selected) {\n        // If this hashKey has an associated option, push that option's value to the model.\n        if ((option = self.options[hashKey])) {\n          values.push(option.value);\n        } else {\n          // Otherwise, the given hashKey has no associated option, and we got it\n          // from an ngModel value at an earlier time. Push the unhashed value of\n          // this hashKey to the model.\n          // This allows the developer to put a value in the model that doesn't yet have\n          // an associated option.\n          values.push(self.selected[hashKey]);\n        }\n      }\n\n      var newVal = self.isMultiple ? values : values[0];\n      var prevVal = self.ngModel.$modelValue;\n\n      if (!equals(prevVal, newVal)) {\n        self.ngModel.$setViewValue(newVal);\n        self.ngModel.$render();\n      }\n\n      function equals(prevVal, newVal) {\n        if (self.isMultiple) {\n          if (!angular.isArray(prevVal)) {\n            // newVal is always an array when self.isMultiple is true\n            // thus, if prevVal is not an array they are different\n            return false;\n          } else if (prevVal.length !== newVal.length) {\n            // they are different if they have different length\n            return false;\n          } else {\n            // if they have the same length, then they are different\n            // if an item in the newVal array can't be found in the prevVal\n            var prevValHashes = prevVal.map(function(prevValItem) {\n              return self.hashGetter(prevValItem);\n            });\n            return newVal.every(function(newValItem) {\n              var newValItemHash = self.hashGetter(newValItem);\n              return prevValHashes.some(function(prevValHash) {\n                return prevValHash === newValItemHash;\n              });\n            });\n          }\n        } else {\n          return self.hashGetter(prevVal) === self.hashGetter(newVal);\n        }\n      }\n    };\n\n    /**\n     * If the options include md-optgroups, then we need to apply aria-setsize and aria-posinset\n     * to help screen readers understand the indexes. When md-optgroups are not used, we save on\n     * perf and extra attributes by not applying these attributes as they are not needed by screen\n     * readers.\n     */\n    function updateOptionSetSizeAndPosition() {\n      var i, options;\n      var hasOptGroup = $element.find('md-optgroup');\n      if (!hasOptGroup.length) {\n        return;\n      }\n\n      options = $element.find('md-option');\n\n      for (i = 0; i < options.length; i++) {\n        options[i].setAttribute('aria-setsize', options.length);\n        options[i].setAttribute('aria-posinset', i + 1);\n      }\n    }\n\n    function renderMultiple() {\n      var newSelectedValues = self.ngModel.$modelValue || self.ngModel.$viewValue || [];\n      if (!angular.isArray(newSelectedValues)) {\n        return;\n      }\n\n      var oldSelected = Object.keys(self.selected);\n\n      var newSelectedHashes = newSelectedValues.map(self.hashGetter);\n      var deselected = oldSelected.filter(function(hash) {\n        return newSelectedHashes.indexOf(hash) === -1;\n      });\n\n      deselected.forEach(self.deselect);\n      newSelectedHashes.forEach(function(hashKey, i) {\n        self.select(hashKey, newSelectedValues[i]);\n      });\n    }\n\n    function renderSingular() {\n      var value = self.ngModel.$viewValue || self.ngModel.$modelValue;\n      Object.keys(self.selected).forEach(self.deselect);\n      self.select(self.hashGetter(value), value);\n    }\n  }\n}\n\n/**\n * @ngdoc directive\n * @name mdOption\n * @restrict E\n * @module material.components.select\n *\n * @description Displays an option in a <a ng-href=\"api/directive/mdSelect\">md-select</a> box's\n * dropdown menu. Options can be grouped using\n * <a ng-href=\"api/directive/mdOptgroup\">md-optgroup</a> element directives.\n *\n * ### Option Params\n *\n * When applied, `md-option-empty` will mark the option as \"empty\" allowing the option to clear the\n * select and put it back in it's default state. You may supply this attribute on any option you\n * wish, however, it is automatically applied to an option whose `value` or `ng-value` are not\n * defined.\n *\n * **Automatically Applied**\n *\n *  - `<md-option>`\n *  - `<md-option value>`\n *  - `<md-option value=\"\">`\n *  - `<md-option ng-value>`\n *  - `<md-option ng-value=\"\">`\n *\n * **NOT Automatically Applied**\n *\n *  - `<md-option ng-value=\"1\">`\n *  - `<md-option ng-value=\"''\">`\n *  - `<md-option ng-value=\"undefined\">`\n *  - `<md-option value=\"undefined\">` (this evaluates to the string `\"undefined\"`)\n *  - <code ng-non-bindable>&lt;md-option ng-value=\"{{someValueThatMightBeUndefined}}\"&gt;</code>\n *\n * **Note:** A value of `undefined` ***is considered a valid value*** (and does not auto-apply this\n * attribute) since you may wish this to be your \"Not Available\" or \"None\" option.\n *\n * **Note:** Using the\n * <a ng-href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option#Attributes\">value</a>\n * attribute from the `<option>` element (as opposed to the `<md-option>` element's\n * <a ng-href=\"https://docs.angularjs.org/api/ng/directive/ngValue\">ng-value</a>) always evaluates\n * to a `string`. This means that `value=\"null\"` will cause a check against `myValue != \"null\"`\n * rather than `!myValue` or `myValue != null`.\n * Importantly, this also applies to `number` values. `value=\"1\"` will not match up with an\n * `ng-model` like `$scope.selectedValue = 1`. Use `ng-value=\"1\"` in this case and other cases where\n * you have values that are not strings.\n *\n * **Note:** Please see our <a ng-href=\"api/directive/mdSelect#selects-and-object-equality\">docs on\n * using objects with `md-select`</a> for additional guidance on using the `trackBy` option with\n * `ng-model-options`.\n *\n * @param {expression=} ng-value Binds the given expression to the value of the option.\n * @param {string=} value Attribute to set the value of the option.\n * @param {expression=} ng-repeat <a ng-href=\"https://docs.angularjs.org/api/ng/directive/ngRepeat\">\n *  AngularJS directive</a> that instantiates a template once per item from a collection.\n * @param {expression=} ng-selected <a ng-href=\"https://docs.angularjs.org/api/ng/directive/ngSelected\">\n *  AngularJS directive</a> that adds the `selected` attribute to the option when the expression\n *  evaluates as truthy.\n *\n *  **Note:** Unlike native `option` elements used with AngularJS, `md-option` elements\n *  watch their `selected` attributes for changes and trigger model value changes on `md-select`.\n * @param {boolean=} md-option-empty If the attribute exists, mark the option as \"empty\" allowing\n * the option to clear the select and put it back in it's default state. You may supply this\n * attribute on any option you wish, however, it is automatically applied to an option whose `value`\n * or `ng-value` are not defined.\n * @param {number=} tabindex The `tabindex` of the option. Defaults to `0`.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-select ng-model=\"currentState\" placeholder=\"Select a state\">\n *   <md-option ng-value=\"AL\">Alabama</md-option>\n *   <md-option ng-value=\"AK\">Alaska</md-option>\n *   <md-option ng-value=\"FL\">Florida</md-option>\n * </md-select>\n * </hljs>\n *\n * With `ng-repeat`:\n * <hljs lang=\"html\">\n * <md-select ng-model=\"currentState\" placeholder=\"Select a state\">\n *   <md-option ng-value=\"state\" ng-repeat=\"state in states\">{{ state }}</md-option>\n * </md-select>\n * </hljs>\n */\nfunction OptionDirective($mdButtonInkRipple, $mdUtil, $mdTheming) {\n\n  return {\n    restrict: 'E',\n    require: ['mdOption', '^^mdSelectMenu'],\n    controller: OptionController,\n    compile: compile\n  };\n\n  /**\n   * @param {JQLite} element\n   * @param {IAttributes} attrs\n   * @return {postLink}\n   */\n  function compile(element, attrs) {\n    // Manual transclusion to avoid the extra inner <span> that ng-transclude generates\n    element.append(angular.element('<div class=\"md-text\">').append(element.contents()));\n\n    element.attr('tabindex', attrs.tabindex || '0');\n\n    if (!hasDefinedValue(attrs)) {\n      element.attr('md-option-empty', '');\n    }\n\n    return postLink;\n  }\n\n  /**\n   * @param {Object} attrs list of attributes from the compile function\n   * @return {string|undefined|null} if defined and non-empty, return the value of the option's\n   *  value attribute, otherwise return the value of the option's ng-value attribute.\n   */\n  function hasDefinedValue(attrs) {\n    var value = attrs.value;\n    var ngValue = attrs.ngValue;\n\n    return value || ngValue;\n  }\n\n  function postLink(scope, element, attrs, ctrls) {\n    var optionCtrl = ctrls[0];\n    var selectMenuCtrl = ctrls[1];\n\n    $mdTheming(element);\n\n    if (selectMenuCtrl.isMultiple) {\n      element.addClass('md-checkbox-enabled');\n      element.prepend(CHECKBOX_SELECTION_INDICATOR.clone());\n    }\n\n    if (angular.isDefined(attrs.ngValue)) {\n      scope.$watch(attrs.ngValue, function (newValue, oldValue) {\n        setOptionValue(newValue, oldValue);\n        element.removeAttr('aria-checked');\n      });\n    } else if (angular.isDefined(attrs.value)) {\n      setOptionValue(attrs.value);\n    } else {\n      scope.$watch(function() {\n        return element.text().trim();\n      }, setOptionValue);\n    }\n\n    attrs.$observe('disabled', function(disabled) {\n      if (disabled) {\n        element.attr('tabindex', '-1');\n      } else {\n        element.attr('tabindex', '0');\n      }\n    });\n\n    scope.$$postDigest(function() {\n      attrs.$observe('selected', function(selected) {\n        if (!angular.isDefined(selected)) return;\n        if (typeof selected == 'string') selected = true;\n        if (selected) {\n          if (!selectMenuCtrl.isMultiple) {\n            selectMenuCtrl.deselect(Object.keys(selectMenuCtrl.selected)[0]);\n          }\n          selectMenuCtrl.select(optionCtrl.hashKey, optionCtrl.value);\n        } else {\n          selectMenuCtrl.deselect(optionCtrl.hashKey);\n        }\n        selectMenuCtrl.refreshViewValue();\n      });\n    });\n\n    $mdButtonInkRipple.attach(scope, element);\n    configureAria();\n\n    /**\n     * @param {*} newValue the option's new value\n     * @param {*=} oldValue the option's previous value\n     * @param {boolean=} prevAttempt true if this had to be attempted again due to an undefined\n     *  hashGetter on the selectMenuCtrl, undefined otherwise.\n     */\n    function setOptionValue(newValue, oldValue, prevAttempt) {\n      if (!selectMenuCtrl.hashGetter) {\n        if (!prevAttempt) {\n          scope.$$postDigest(function() {\n            setOptionValue(newValue, oldValue, true);\n          });\n        }\n        return;\n      }\n      var oldHashKey = selectMenuCtrl.hashGetter(oldValue, scope);\n      var newHashKey = selectMenuCtrl.hashGetter(newValue, scope);\n\n      optionCtrl.hashKey = newHashKey;\n      optionCtrl.value = newValue;\n\n      selectMenuCtrl.removeOption(oldHashKey, optionCtrl);\n      selectMenuCtrl.addOption(newHashKey, optionCtrl);\n    }\n\n    scope.$on('$destroy', function() {\n      selectMenuCtrl.removeOption(optionCtrl.hashKey, optionCtrl);\n    });\n\n    function configureAria() {\n      var ariaAttrs = {\n        'role': 'option'\n      };\n\n      // We explicitly omit the `aria-selected` attribute from single-selection, unselected\n      // options. Including the `aria-selected=\"false\"` attributes adds a significant amount of\n      // noise to screen-reader users without providing useful information.\n      if (selectMenuCtrl.isMultiple) {\n        ariaAttrs['aria-selected'] = 'false';\n      }\n\n      if (!element[0].hasAttribute('id')) {\n        ariaAttrs.id = 'select_option_' + $mdUtil.nextUid();\n      }\n      element.attr(ariaAttrs);\n    }\n  }\n}\n\n/**\n * @param {JQLite} $element\n * @constructor\n */\nfunction OptionController($element) {\n  /**\n   * @param {boolean} isSelected\n   * @param {boolean=} isMultiple\n   */\n  this.setSelected = function(isSelected, isMultiple) {\n    if (isSelected) {\n      $element.attr({\n        'selected': 'true',\n        'aria-selected': 'true'\n      });\n    } else if (!isSelected) {\n      $element.removeAttr('selected');\n\n      if (isMultiple) {\n        $element.attr('aria-selected', 'false');\n      } else {\n        // We explicitly omit the `aria-selected` attribute from single-selection, unselected\n        // options. Including the `aria-selected=\"false\"` attributes adds a significant amount of\n        // noise to screen-reader users without providing useful information.\n        $element.removeAttr('aria-selected');\n      }\n    }\n  };\n}\n\n/**\n * @ngdoc directive\n * @name mdOptgroup\n * @restrict E\n * @module material.components.select\n *\n * @description Displays a label separating groups of\n * <a ng-href=\"api/directive/mdOption\">md-option</a> element directives in a\n * <a ng-href=\"api/directive/mdSelect\">md-select</a> box's dropdown menu.\n *\n * **Note:** When using `md-select-header` element directives within a `md-select`, the labels that\n * would normally be added to the <a ng-href=\"api/directive/mdOptgroup\">md-optgroup</a> directives\n * are omitted, allowing the `md-select-header` to represent the option group label\n * (and possibly more).\n *\n * @usage\n * With label attributes\n * <hljs lang=\"html\">\n * <md-select ng-model=\"currentState\" placeholder=\"Select a state\">\n *   <md-optgroup label=\"Southern\">\n *     <md-option ng-value=\"AL\">Alabama</md-option>\n *     <md-option ng-value=\"FL\">Florida</md-option>\n *   </md-optgroup>\n *   <md-optgroup label=\"Northern\">\n *     <md-option ng-value=\"AK\">Alaska</md-option>\n *     <md-option ng-value=\"MA\">Massachusetts</md-option>\n *   </md-optgroup>\n * </md-select>\n * </hljs>\n *\n * With label elements\n * <hljs lang=\"html\">\n * <md-select ng-model=\"currentState\" placeholder=\"Select a state\">\n *   <md-optgroup>\n *     <label>Southern</label>\n *     <md-option ng-value=\"AL\">Alabama</md-option>\n *     <md-option ng-value=\"FL\">Florida</md-option>\n *   </md-optgroup>\n *   <md-optgroup>\n *     <label>Northern</label>\n *     <md-option ng-value=\"AK\">Alaska</md-option>\n *     <md-option ng-value=\"MA\">Massachusetts</md-option>\n *   </md-optgroup>\n * </md-select>\n * </hljs>\n *\n * @param {string=} label The option group's label.\n */\nfunction OptgroupDirective() {\n  return {\n    restrict: 'E',\n    compile: compile\n  };\n  function compile(element, attrs) {\n    // If we have a select header element, we don't want to add the normal label\n    // header.\n    if (!hasSelectHeader()) {\n      setupLabelElement();\n    }\n    element.attr('role', 'group');\n\n    function hasSelectHeader() {\n      return element.parent().find('md-select-header').length;\n    }\n\n    function setupLabelElement() {\n      var labelElement = element.find('label');\n      if (!labelElement.length) {\n        labelElement = angular.element('<label>');\n        element.prepend(labelElement);\n      }\n      labelElement.addClass('md-container-ignore');\n      labelElement.attr('aria-hidden', 'true');\n      if (attrs.label) {\n        labelElement.text(attrs.label);\n      }\n      element.attr('aria-label', labelElement.text());\n    }\n  }\n}\n\nfunction SelectHeaderDirective() {\n  return {\n    restrict: 'E',\n  };\n}\n\nfunction SelectProvider($$interimElementProvider) {\n  selectDefaultOptions.$inject = [\"$mdSelect\", \"$mdConstant\", \"$mdUtil\", \"$window\", \"$q\", \"$$rAF\", \"$animateCss\", \"$animate\", \"$document\"];\n  return $$interimElementProvider('$mdSelect')\n    .setDefaults({\n      methods: ['target'],\n      options: selectDefaultOptions\n    });\n\n  /* @ngInject */\n  function selectDefaultOptions($mdSelect, $mdConstant, $mdUtil, $window, $q, $$rAF, $animateCss, $animate, $document) {\n    var ERROR_TARGET_EXPECTED = \"$mdSelect.show() expected a target element in options.target but got '{0}'!\";\n    var animator = $mdUtil.dom.animator;\n    var keyCodes = $mdConstant.KEY_CODE;\n\n    return {\n      parent: 'body',\n      themable: true,\n      onShow: onShow,\n      onRemove: onRemove,\n      hasBackdrop: true,\n      disableParentScroll: true\n    };\n\n    /**\n     * Interim-element onRemove logic....\n     */\n    function onRemove(scope, element, opts) {\n      var animationRunner = null;\n      var destroyListener = scope.$on('$destroy', function() {\n        // Listen for the case where the element was destroyed while there was an\n        // ongoing close animation. If this happens, we need to end the animation\n        // manually.\n        animationRunner.end();\n      });\n\n      opts = opts || { };\n      opts.cleanupInteraction();\n      opts.cleanupResizing();\n      opts.hideBackdrop();\n\n      // For navigation $destroy events, do a quick, non-animated removal,\n      // but for normal closes (from clicks, etc) animate the removal\n      return (opts.$destroy === true) ? cleanElement() : animateRemoval().then(cleanElement);\n\n      /**\n       * For normal closes (eg clicks), animate the removal.\n       * For forced closes (like $destroy events from navigation),\n       * skip the animations.\n       */\n      function animateRemoval() {\n        animationRunner = $animateCss(element, {addClass: 'md-leave'});\n        return animationRunner.start();\n      }\n\n      /**\n       * Restore the element to a closed state\n       */\n      function cleanElement() {\n        destroyListener();\n\n        element\n          .removeClass('md-active')\n          .attr('aria-hidden', 'true')\n          .css({\n            'display': 'none',\n            'top': '',\n            'right': '',\n            'bottom': '',\n            'left': '',\n            'font-size': '',\n            'min-width': ''\n          });\n\n        announceClosed(opts);\n\n        if (!opts.$destroy) {\n          if (opts.restoreFocus) {\n            opts.target.focus();\n          } else {\n            // Make sure that the container's md-input-focused is removed on backdrop click.\n            $mdUtil.nextTick(function() {\n              opts.target.triggerHandler('blur');\n            }, true);\n          }\n        }\n      }\n    }\n\n    /**\n     * Interim-element onShow logic.\n     */\n    function onShow(scope, element, opts) {\n\n      watchAsyncLoad();\n      sanitizeAndConfigure(scope, opts);\n\n      opts.hideBackdrop = showBackdrop(scope, element, opts);\n\n      return showDropDown(scope, element, opts)\n        .then(function(response) {\n          element.attr('aria-hidden', 'false');\n          opts.alreadyOpen = true;\n          opts.cleanupInteraction = activateInteraction();\n          opts.cleanupResizing = activateResizing();\n          opts.contentEl[0].focus();\n\n          return response;\n        }, opts.hideBackdrop);\n\n      // ************************************\n      // Closure Functions\n      // ************************************\n\n      /**\n       * Attach the select DOM element(s) and animate to the correct positions and scale.\n       */\n      function showDropDown(scope, element, opts) {\n        if (opts.parent !== element.parent()) {\n          element.parent().attr('aria-owns', element.find('md-content').attr('id'));\n        }\n\n        opts.parent.append(element);\n\n        return $q(function(resolve, reject) {\n          try {\n            $animateCss(element, {removeClass: 'md-leave', duration: 0})\n              .start()\n              .then(positionAndFocusMenu)\n              .then(resolve);\n\n          } catch (e) {\n            reject(e);\n          }\n        });\n      }\n\n      /**\n       * Initialize container and dropDown menu positions/scale, then animate to show.\n       * @return {*} a Promise that resolves after the menu is animated in and an item is focused\n       */\n      function positionAndFocusMenu() {\n        return $q(function(resolve) {\n          if (opts.isRemoved) return $q.reject(false);\n\n          var info = calculateMenuPositions(scope, element, opts);\n\n          info.container.element.css(animator.toCss(info.container.styles));\n          info.dropDown.element.css(animator.toCss(info.dropDown.styles));\n\n          $$rAF(function() {\n            element.addClass('md-active');\n            info.dropDown.element.css(animator.toCss({transform: ''}));\n            autoFocus(opts.focusedNode);\n\n            resolve();\n          });\n\n        });\n      }\n\n      /**\n       * Show modal backdrop element.\n       */\n      function showBackdrop(scope, element, options) {\n\n        // If we are not within a dialog...\n        if (options.disableParentScroll && !$mdUtil.getClosest(options.target, 'MD-DIALOG')) {\n          // !! DO this before creating the backdrop; since disableScrollAround()\n          //    configures the scroll offset; which is used by mdBackDrop postLink()\n          options.restoreScroll = $mdUtil.disableScrollAround(options.element, options.parent);\n        } else {\n          options.disableParentScroll = false;\n        }\n\n        if (options.hasBackdrop) {\n          // Override duration to immediately show invisible backdrop\n          options.backdrop = $mdUtil.createBackdrop(scope, \"md-select-backdrop md-click-catcher\");\n          $animate.enter(options.backdrop, $document[0].body, null, {duration: 0});\n        }\n\n        /**\n         * Hide modal backdrop element...\n         */\n        return function hideBackdrop() {\n          if (options.backdrop) options.backdrop.remove();\n          if (options.disableParentScroll) options.restoreScroll();\n\n          delete options.restoreScroll;\n        };\n      }\n\n      /**\n       * @param {Element|HTMLElement|null=} previousNode\n       * @param {Element|HTMLElement} node\n       * @param {SelectMenuController|Function|object=} menuController SelectMenuController instance\n       */\n      function focusOptionNode(previousNode, node, menuController) {\n        var listboxContentNode = opts.contentEl[0];\n\n        if (node) {\n          if (previousNode) {\n            previousNode.classList.remove('md-focused');\n          }\n\n          node.classList.add('md-focused');\n          if (menuController && menuController.setActiveDescendant) {\n            menuController.setActiveDescendant(node.id);\n          }\n\n          // Scroll the node into view if needed.\n          if (listboxContentNode.scrollHeight > listboxContentNode.clientHeight) {\n            var scrollBottom = listboxContentNode.clientHeight + listboxContentNode.scrollTop;\n            var nodeBottom = node.offsetTop + node.offsetHeight;\n            if (nodeBottom > scrollBottom) {\n              listboxContentNode.scrollTop = nodeBottom - listboxContentNode.clientHeight;\n            } else if (node.offsetTop < listboxContentNode.scrollTop) {\n              listboxContentNode.scrollTop = node.offsetTop;\n            }\n          }\n          opts.focusedNode = node;\n          if (menuController && menuController.refreshViewValue) {\n            menuController.refreshViewValue();\n          }\n        }\n      }\n\n      /**\n       * @param {Element|HTMLElement} nodeToFocus\n       */\n      function autoFocus(nodeToFocus) {\n        var selectMenuController;\n        if (nodeToFocus && !nodeToFocus.hasAttribute('disabled')) {\n          selectMenuController = opts.selectEl.controller('mdSelectMenu');\n          focusOptionNode(null, nodeToFocus, selectMenuController);\n        }\n      }\n\n      /**\n       * Check for valid opts and set some useful defaults\n       */\n      function sanitizeAndConfigure(scope, options) {\n        var selectMenuElement = element.find('md-select-menu');\n\n        if (!options.target) {\n          throw new Error($mdUtil.supplant(ERROR_TARGET_EXPECTED, [options.target]));\n        }\n\n        angular.extend(options, {\n          isRemoved: false,\n          target: angular.element(options.target), // make sure it's not a naked DOM node\n          parent: angular.element(options.parent),\n          selectEl: selectMenuElement,\n          contentEl: element.find('md-content'),\n          optionNodes: selectMenuElement[0].getElementsByTagName('md-option')\n        });\n      }\n\n      /**\n       * Configure various resize listeners for screen changes\n       */\n      function activateResizing() {\n        var debouncedOnResize = (function(scope, target, options) {\n\n          return function() {\n            if (options.isRemoved) return;\n\n            var updates = calculateMenuPositions(scope, target, options);\n            var container = updates.container;\n            var dropDown = updates.dropDown;\n\n            container.element.css(animator.toCss(container.styles));\n            dropDown.element.css(animator.toCss(dropDown.styles));\n          };\n\n        })(scope, element, opts);\n\n        var window = angular.element($window);\n        window.on('resize', debouncedOnResize);\n        window.on('orientationchange', debouncedOnResize);\n\n        // Publish deactivation closure...\n        return function deactivateResizing() {\n\n          // Disable resizing handlers\n          window.off('resize', debouncedOnResize);\n          window.off('orientationchange', debouncedOnResize);\n        };\n      }\n\n      /**\n       * If asynchronously loading, watch and update internal '$$loadingAsyncDone' flag.\n       */\n      function watchAsyncLoad() {\n        if (opts.loadingAsync && !opts.isRemoved) {\n          scope.$$loadingAsyncDone = false;\n\n          $q.when(opts.loadingAsync)\n            .then(function() {\n              scope.$$loadingAsyncDone = true;\n              delete opts.loadingAsync;\n            }).then(function() {\n              $$rAF(positionAndFocusMenu);\n            });\n        }\n      }\n\n      function activateInteraction() {\n        if (opts.isRemoved) {\n          return;\n        }\n\n        var dropDown = opts.selectEl;\n        var selectMenuController = dropDown.controller('mdSelectMenu') || {};\n\n        element.addClass('md-clickable');\n\n        // Close on backdrop click\n        opts.backdrop && opts.backdrop.on('click', onBackdropClick);\n\n        // Escape to close\n        // Cycling of options, and closing on enter\n        dropDown.on('keydown', onMenuKeyDown);\n        dropDown.on('click', checkCloseMenu);\n\n        return function cleanupInteraction() {\n          opts.backdrop && opts.backdrop.off('click', onBackdropClick);\n          dropDown.off('keydown', onMenuKeyDown);\n          dropDown.off('click', checkCloseMenu);\n\n          element.removeClass('md-clickable');\n          opts.isRemoved = true;\n        };\n\n        // ************************************\n        // Closure Functions\n        // ************************************\n\n        function onBackdropClick(e) {\n          e.preventDefault();\n          e.stopPropagation();\n          opts.restoreFocus = false;\n          $mdUtil.nextTick($mdSelect.hide, true);\n        }\n\n        function onMenuKeyDown(ev) {\n          ev.preventDefault();\n          ev.stopPropagation();\n\n          switch (ev.keyCode) {\n            case keyCodes.UP_ARROW:\n              return focusPrevOption();\n            case keyCodes.DOWN_ARROW:\n              return focusNextOption();\n            case keyCodes.SPACE:\n            case keyCodes.ENTER:\n              if (opts.focusedNode) {\n                dropDown.triggerHandler({\n                  type: 'click',\n                  target: opts.focusedNode\n                });\n                ev.preventDefault();\n              }\n              checkCloseMenu(ev);\n              break;\n            case keyCodes.TAB:\n            case keyCodes.ESCAPE:\n              ev.stopPropagation();\n              ev.preventDefault();\n              opts.restoreFocus = true;\n              $mdUtil.nextTick($mdSelect.hide, true);\n              break;\n            default:\n              if (shouldHandleKey(ev, $mdConstant)) {\n                var optNode = selectMenuController.optNodeForKeyboardSearch(ev);\n                if (optNode && !optNode.hasAttribute('disabled')) {\n                  focusOptionNode(opts.focusedNode, optNode, selectMenuController);\n                }\n              }\n          }\n        }\n\n        /**\n         * Change the focus to another option. If there is no focused option, focus the first\n         * option. If there is a focused option, then use the direction to determine if we should\n         * focus the previous or next option in the list.\n         * @param {'next'|'prev'} direction\n         */\n        function focusOption(direction) {\n          var optionsArray = $mdUtil.nodesToArray(opts.optionNodes);\n          var index = optionsArray.indexOf(opts.focusedNode);\n          var prevOption = optionsArray[index];\n          var newOption;\n\n          do {\n            if (index === -1) {\n              // We lost the previously focused element, reset to first option\n              index = 0;\n            } else if (direction === 'next' && index < optionsArray.length - 1) {\n              index++;\n            } else if (direction === 'prev' && index > 0) {\n              index--;\n            }\n            newOption = optionsArray[index];\n            if (newOption.hasAttribute('disabled')) {\n              newOption = null;\n            }\n          } while (!newOption && index < optionsArray.length - 1 && index > 0);\n\n          focusOptionNode(prevOption, newOption, selectMenuController);\n        }\n\n        function focusNextOption() {\n          focusOption('next');\n        }\n\n        function focusPrevOption() {\n          focusOption('prev');\n        }\n\n        /**\n         * @param {KeyboardEvent|MouseEvent} event\n         */\n        function checkCloseMenu(event) {\n          if (event && (event.type === 'click') && (event.currentTarget !== dropDown[0])) {\n            return;\n          }\n          if (mouseOnScrollbar()) {\n            return;\n          }\n\n          if (opts.focusedNode && opts.focusedNode.hasAttribute &&\n              !opts.focusedNode.hasAttribute('disabled')) {\n            event.preventDefault();\n            event.stopPropagation();\n            if (!selectMenuController.isMultiple) {\n              opts.restoreFocus = true;\n\n              $mdUtil.nextTick(function () {\n                $mdSelect.hide(selectMenuController.ngModel.$viewValue);\n                opts.focusedNode.classList.remove('md-focused');\n              }, true);\n            }\n          }\n\n          /**\n           * check if the mouseup event was on a scrollbar\n           */\n          function mouseOnScrollbar() {\n            var clickOnScrollbar = false;\n            if (event && (event.currentTarget.children.length > 0)) {\n              var child = event.currentTarget.children[0];\n              var hasScrollbar = child.scrollHeight > child.clientHeight;\n              if (hasScrollbar && child.children.length > 0) {\n                var relPosX = event.pageX - event.currentTarget.getBoundingClientRect().left;\n                if (relPosX > child.querySelector('md-option').offsetWidth)\n                  clickOnScrollbar = true;\n              }\n            }\n            return clickOnScrollbar;\n          }\n        }\n      }\n    }\n\n    /**\n     * To notify listeners that the Select menu has closed,\n     * trigger the [optional] user-defined expression\n     */\n    function announceClosed(opts) {\n      var mdSelect = opts.selectCtrl;\n      if (mdSelect) {\n        var menuController = opts.selectEl.controller('mdSelectMenu');\n        mdSelect.setSelectValueText(menuController ? menuController.getSelectedLabels() : '');\n        mdSelect.triggerClose();\n      }\n    }\n\n\n    /**\n     * Calculate the menu positions after an event like options changing, screen resizing, or\n     * animations finishing.\n     * @param {Object} scope\n     * @param element\n     * @param opts\n     * @return {{container: {styles: {top: number, left: number, 'font-size': *, 'min-width': number}, element: Object}, dropDown: {styles: {transform: string, transformOrigin: string}, element: Object}}}\n     */\n    function calculateMenuPositions(scope, element, opts) {\n      var\n        containerNode = element[0],\n        targetNode = opts.target[0].children[0], // target the label\n        parentNode = $document[0].body,\n        selectNode = opts.selectEl[0],\n        contentNode = opts.contentEl[0],\n        parentRect = parentNode.getBoundingClientRect(),\n        targetRect = targetNode.getBoundingClientRect(),\n        shouldOpenAroundTarget = false,\n        bounds = {\n          left: parentRect.left + SELECT_EDGE_MARGIN,\n          top: SELECT_EDGE_MARGIN,\n          bottom: parentRect.height - SELECT_EDGE_MARGIN,\n          right: parentRect.width - SELECT_EDGE_MARGIN - ($mdUtil.floatingScrollbars() ? 16 : 0)\n        },\n        spaceAvailable = {\n          top: targetRect.top - bounds.top,\n          left: targetRect.left - bounds.left,\n          right: bounds.right - (targetRect.left + targetRect.width),\n          bottom: bounds.bottom - (targetRect.top + targetRect.height)\n        },\n        maxWidth = parentRect.width - SELECT_EDGE_MARGIN * 2,\n        selectedNode = selectNode.querySelector('md-option[selected]'),\n        optionNodes = selectNode.getElementsByTagName('md-option'),\n        optgroupNodes = selectNode.getElementsByTagName('md-optgroup'),\n        isScrollable = calculateScrollable(element, contentNode),\n        centeredNode;\n\n      var loading = isPromiseLike(opts.loadingAsync);\n      if (!loading) {\n        // If a selected node, center around that\n        if (selectedNode) {\n          centeredNode = selectedNode;\n          // If there are option groups, center around the first option group\n        } else if (optgroupNodes.length) {\n          centeredNode = optgroupNodes[0];\n          // Otherwise - if we are not loading async - center around the first optionNode\n        } else if (optionNodes.length) {\n          centeredNode = optionNodes[0];\n          // In case there are no options, center on whatever's in there... (eg progress indicator)\n        } else {\n          centeredNode = contentNode.firstElementChild || contentNode;\n        }\n      } else {\n        // If loading, center on progress indicator\n        centeredNode = contentNode.firstElementChild || contentNode;\n      }\n\n      if (contentNode.offsetWidth > maxWidth) {\n        contentNode.style['max-width'] = maxWidth + 'px';\n      } else {\n        contentNode.style.maxWidth = null;\n      }\n      if (shouldOpenAroundTarget) {\n        contentNode.style['min-width'] = targetRect.width + 'px';\n      }\n\n      // Remove padding before we compute the position of the menu\n      if (isScrollable) {\n        selectNode.classList.add('md-overflow');\n      }\n\n      var focusedNode = centeredNode;\n      if ((focusedNode.tagName || '').toUpperCase() === 'MD-OPTGROUP') {\n        focusedNode = optionNodes[0] || contentNode.firstElementChild || contentNode;\n        centeredNode = focusedNode;\n      }\n      // Cache for autoFocus()\n      opts.focusedNode = focusedNode;\n\n      // Get the selectMenuRect *after* max-width is possibly set above\n      containerNode.style.display = 'block';\n      var selectMenuRect = selectNode.getBoundingClientRect();\n      var centeredRect = getOffsetRect(centeredNode);\n\n      if (centeredNode) {\n        var centeredStyle = $window.getComputedStyle(centeredNode);\n        centeredRect.paddingLeft = parseInt(centeredStyle.paddingLeft, 10) || 0;\n        centeredRect.paddingRight = parseInt(centeredStyle.paddingRight, 10) || 0;\n      }\n\n      if (isScrollable) {\n        var scrollBuffer = contentNode.offsetHeight / 2;\n        contentNode.scrollTop = centeredRect.top + centeredRect.height / 2 - scrollBuffer;\n\n        if (spaceAvailable.top < scrollBuffer) {\n          contentNode.scrollTop = Math.min(\n            centeredRect.top,\n            contentNode.scrollTop + scrollBuffer - spaceAvailable.top\n          );\n        } else if (spaceAvailable.bottom < scrollBuffer) {\n          contentNode.scrollTop = Math.max(\n            centeredRect.top + centeredRect.height - selectMenuRect.height,\n            contentNode.scrollTop - scrollBuffer + spaceAvailable.bottom\n          );\n        }\n      }\n\n      var left, top, transformOrigin, minWidth, fontSize;\n      if (shouldOpenAroundTarget) {\n        left = targetRect.left;\n        top = targetRect.top + targetRect.height;\n        transformOrigin = '50% 0';\n        if (top + selectMenuRect.height > bounds.bottom) {\n          top = targetRect.top - selectMenuRect.height;\n          transformOrigin = '50% 100%';\n        }\n      } else {\n        left = (targetRect.left + centeredRect.left - centeredRect.paddingLeft);\n        top = Math.floor(targetRect.top + targetRect.height / 2 - centeredRect.height / 2 -\n            centeredRect.top + contentNode.scrollTop) + 2;\n\n        transformOrigin = (centeredRect.left + targetRect.width / 2) + 'px ' +\n          (centeredRect.top + centeredRect.height / 2 - contentNode.scrollTop) + 'px 0px';\n\n        minWidth = Math.min(targetRect.width + centeredRect.paddingLeft + centeredRect.paddingRight, maxWidth);\n\n        fontSize = window.getComputedStyle(targetNode)['font-size'];\n      }\n\n      // Keep left and top within the window\n      var containerRect = containerNode.getBoundingClientRect();\n      var scaleX = Math.round(100 * Math.min(targetRect.width / selectMenuRect.width, 1.0)) / 100;\n      var scaleY = Math.round(100 * Math.min(targetRect.height / selectMenuRect.height, 1.0)) / 100;\n\n      return {\n        container: {\n          element: angular.element(containerNode),\n          styles: {\n            left: Math.floor(clamp(bounds.left, left, bounds.right - minWidth)),\n            top: Math.floor(clamp(bounds.top, top, bounds.bottom - containerRect.height)),\n            'min-width': minWidth,\n            'font-size': fontSize\n          }\n        },\n        dropDown: {\n          element: angular.element(selectNode),\n          styles: {\n            transformOrigin: transformOrigin,\n            transform: !opts.alreadyOpen ? $mdUtil.supplant('scale({0},{1})', [scaleX, scaleY]) : \"\"\n          }\n        }\n      };\n    }\n  }\n\n  function isPromiseLike(obj) {\n    return obj && angular.isFunction(obj.then);\n  }\n\n  function clamp(min, n, max) {\n    return Math.max(min, Math.min(n, max));\n  }\n\n  function getOffsetRect(node) {\n    return node ? {\n      left: node.offsetLeft,\n      top: node.offsetTop,\n      width: node.offsetWidth,\n      height: node.offsetHeight\n    } : {left: 0, top: 0, width: 0, height: 0};\n  }\n\n  function calculateScrollable(element, contentNode) {\n    var isScrollable = false;\n\n    try {\n      var oldDisplay = element[0].style.display;\n\n      // Set the element's display to block so that this calculation is correct\n      element[0].style.display = 'block';\n\n      isScrollable = contentNode.scrollHeight > contentNode.offsetHeight;\n\n      // Reset it back afterwards\n      element[0].style.display = oldDisplay;\n    } finally {\n      // Nothing to do\n    }\n    return isScrollable;\n  }\n}\n\nfunction shouldHandleKey(ev, $mdConstant) {\n  var char = String.fromCharCode(ev.keyCode);\n  var isNonUsefulKey = (ev.keyCode <= 31);\n\n  return (char && char.length && !isNonUsefulKey &&\n    !$mdConstant.isMetaKey(ev) && !$mdConstant.isFnLockKey(ev) && !$mdConstant.hasModifierKey(ev));\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.showHide\n */\n\n// Add additional handlers to ng-show and ng-hide that notify directives\n// contained within that they should recompute their size.\n// These run in addition to AngularJS's built-in ng-hide and ng-show directives.\nangular.module('material.components.showHide', [\n  'material.core'\n])\n  .directive('ngShow', createDirective('ngShow', true))\n  .directive('ngHide', createDirective('ngHide', false));\n\n\nfunction createDirective(name, targetValue) {\n  return ['$mdUtil', '$window', function($mdUtil, $window) {\n    return {\n      restrict: 'A',\n      multiElement: true,\n      link: function($scope, $element, $attr) {\n        var unregister = $scope.$on('$md-resize-enable', function() {\n          unregister();\n\n          var node = $element[0];\n          var cachedTransitionStyles = node.nodeType === $window.Node.ELEMENT_NODE ?\n            $window.getComputedStyle(node) : {};\n\n          $scope.$watch($attr[name], function(value) {\n            if (!!value === targetValue) {\n              $mdUtil.nextTick(function() {\n                $scope.$broadcast('$md-resize');\n              });\n\n              var opts = {\n                cachedTransitionStyles: cachedTransitionStyles\n              };\n\n              $mdUtil.dom.animator.waitTransitionEnd($element, opts).then(function() {\n                $scope.$broadcast('$md-resize');\n              });\n            }\n          });\n        });\n      }\n    };\n  }];\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.sidenav\n *\n * @description\n * A Sidenav component.\n */\nSidenavService.$inject = [\"$mdComponentRegistry\", \"$mdUtil\", \"$q\", \"$log\"];\nSidenavDirective.$inject = [\"$mdMedia\", \"$mdUtil\", \"$mdConstant\", \"$mdTheming\", \"$mdInteraction\", \"$animate\", \"$compile\", \"$parse\", \"$log\", \"$q\", \"$document\", \"$window\", \"$$rAF\"];\nSidenavController.$inject = [\"$scope\", \"$attrs\", \"$mdComponentRegistry\", \"$q\", \"$interpolate\"];\nangular\n  .module('material.components.sidenav', [\n    'material.core',\n    'material.components.backdrop'\n  ])\n  .factory('$mdSidenav', SidenavService)\n  .directive('mdSidenav', SidenavDirective)\n  .controller('$mdSidenavController', SidenavController);\n\n\n/**\n * @ngdoc service\n * @name $mdSidenav\n * @module material.components.sidenav\n *\n * @description\n * `$mdSidenav` makes it easy to interact with multiple sidenavs in an app. When looking up a\n * sidenav instance, you can either look it up synchronously or wait for it to be initialized\n * asynchronously. This is done by passing the second argument to `$mdSidenav`.\n *\n * @usage\n * <hljs lang=\"js\">\n * // Async lookup for sidenav instance; will resolve when the instance is available\n * $mdSidenav(componentId, true).then(function(instance) {\n *   $log.debug( componentId + \"is now ready\" );\n * });\n * // Sync lookup for sidenav instance; this will resolve immediately.\n * $mdSidenav(componentId).then(function(instance) {\n *   $log.debug( componentId + \"is now ready\" );\n * });\n * // Async toggle the given sidenav;\n * // when instance is known ready and lazy lookup is not needed.\n * $mdSidenav(componentId)\n *    .toggle()\n *    .then(function(){\n *      $log.debug('toggled');\n *    });\n * // Async open the given sidenav\n * $mdSidenav(componentId)\n *    .open()\n *    .then(function(){\n *      $log.debug('opened');\n *    });\n * // Async close the given sidenav\n * $mdSidenav(componentId)\n *    .close()\n *    .then(function(){\n *      $log.debug('closed');\n *    });\n * // Async lookup for sidenav instance\n * $mdSidenav(componentId, true).then(function(instance) {\n *   // On close callback to handle close, backdrop click, or escape key pressed.\n *   // Callback happens BEFORE the close action occurs.\n *   instance.onClose(function() {\n *     $log.debug('closing');\n *   });\n * });\n * // Sync check to see if the specified sidenav is set to be open\n * $mdSidenav(componentId).isOpen();\n * // Sync check to whether given sidenav is locked open\n * // If this is true, the sidenav will be open regardless of close()\n * $mdSidenav(componentId).isLockedOpen();\n * </hljs>\n */\nfunction SidenavService($mdComponentRegistry, $mdUtil, $q, $log) {\n  var errorMsg = \"SideNav '{0}' is not available! Did you use md-component-id='{0}'?\";\n  var service = {\n    find: findInstance,      //  sync  - returns proxy API\n    waitFor: waitForInstance //  async - returns promise\n  };\n\n  /**\n   * Service API that supports three (3) usages:\n   * $mdSidenav().find(\"left\")               // sync (must already exist) or returns undefined\n   * $mdSidenav(\"left\").toggle();            // sync (must already exist) or returns reject promise;\n   * $mdSidenav(\"left\",true).then(function(left) { // async returns instance when available\n   *  left.toggle();\n   * });\n   */\n  return function(handle, enableWait) {\n    if (angular.isUndefined(handle)) {\n      return service;\n    }\n\n    var shouldWait = enableWait === true;\n    var instance = service.find(handle, shouldWait);\n    return !instance && shouldWait ? service.waitFor(handle) :\n           !instance && angular.isUndefined(enableWait) ? addLegacyAPI(service, handle) : instance;\n  };\n\n  /**\n   * For failed instance/handle lookups, older-clients expect an response object with noops\n   * that include `rejected promise APIs`\n   * @param service\n   * @param handle\n   * @returns {Object}\n   */\n  function addLegacyAPI(service, handle) {\n    var falseFn = function() {\n      return false;\n    };\n    var rejectFn = function() {\n      return $q.when($mdUtil.supplant(errorMsg, [handle || \"\"]));\n    };\n\n    return angular.extend({\n      isLockedOpen: falseFn,\n      isOpen: falseFn,\n      toggle: rejectFn,\n      open: rejectFn,\n      close: rejectFn,\n      onClose: angular.noop,\n      then: function(callback) {\n        return waitForInstance(handle).then(callback || angular.noop);\n      }\n    }, service);\n  }\n\n  /**\n   * Synchronously lookup the controller instance for the specified sidNav instance which has been\n   * registered with the markup `md-component-id`\n   */\n  function findInstance(handle, shouldWait) {\n    var instance = $mdComponentRegistry.get(handle);\n\n    if (!instance && !shouldWait) {\n      // Report missing instance\n      $log.error($mdUtil.supplant(errorMsg, [handle || \"\"]));\n\n      // The component has not registered itself... most like NOT yet created\n      // return null to indicate that the Sidenav is not in the DOM\n      return undefined;\n    }\n    return instance;\n  }\n\n  /**\n   * Asynchronously wait for the component instantiation,\n   * Deferred lookup of component instance using $component registry\n   */\n  function waitForInstance(handle) {\n    return $mdComponentRegistry.when(handle).catch($log.error);\n  }\n}\n\n/**\n * @ngdoc directive\n * @name mdSidenav\n * @module material.components.sidenav\n * @restrict E\n *\n * @description\n * A Sidenav component that can be opened and closed programmatically.\n *\n * By default, upon opening it will slide out on top of the main content area.\n *\n * For keyboard and screen reader accessibility, focus is sent to the sidenav wrapper by default.\n * It can be overridden with the `md-autofocus` directive on the child element you want focused.\n *\n * @usage\n * <hljs lang=\"html\">\n * <div layout=\"row\" ng-controller=\"MyController\">\n *   <md-sidenav md-component-id=\"left\" class=\"md-sidenav-left\">\n *     Left Nav!\n *   </md-sidenav>\n *\n *   <md-content>\n *     Center Content\n *     <md-button ng-click=\"openLeftMenu()\">\n *       Open Left Menu\n *     </md-button>\n *   </md-content>\n *\n *   <md-sidenav md-component-id=\"right\"\n *     md-is-locked-open=\"$mdMedia('min-width: 333px')\"\n *     class=\"md-sidenav-right\">\n *     <form>\n *       <md-input-container>\n *         <label for=\"testInput\">Test input</label>\n *         <input id=\"testInput\" type=\"text\"\n *                ng-model=\"data\" md-autofocus>\n *       </md-input-container>\n *     </form>\n *   </md-sidenav>\n * </div>\n * </hljs>\n *\n * <hljs lang=\"js\">\n * var app = angular.module('myApp', ['ngMaterial']);\n * app.controller('MyController', function($scope, $mdSidenav) {\n *   $scope.openLeftMenu = function() {\n *     $mdSidenav('left').toggle();\n *   };\n * });\n * </hljs>\n *\n * @param {expression=} md-is-open A model bound to whether the sidenav is opened.\n * @param {boolean=} md-disable-backdrop When present in the markup, the sidenav will not show a\n *  backdrop.\n * @param {boolean=} md-disable-close-events When present in the markup, clicking the backdrop or\n *  pressing the 'Escape' key will not close the sidenav.\n * @param {string=} md-component-id componentId to use with $mdSidenav service.\n * @param {expression=} md-is-locked-open When this expression evaluates to true,\n * the sidenav \"locks open\": it falls into the content's flow instead of appearing over it. This\n * overrides the `md-is-open` attribute.\n *\n * The `$mdMedia()` service is exposed to the `md-is-locked-open` attribute, which\n * can be given a media query or one of the `sm`, `gt-sm`, `md`, `gt-md`, `lg` or `gt-lg` presets.\n * <br><br>Examples:\n *\n *   Lock open when `true`:<br>\n *   `<md-sidenav md-is-locked-open=\"shouldLockOpen\"></md-sidenav>`\n *\n *   Lock open when the width is `1000px` or greater:<br>\n *   `<md-sidenav md-is-locked-open=\"$mdMedia('min-width: 1000px')\"></md-sidenav>`\n *\n *   Lock open on small screens:<br>\n *   `<md-sidenav md-is-locked-open=\"$mdMedia('sm')\"></md-sidenav>`\n *\n * @param {string=} md-disable-scroll-target Selector, pointing to an element, whose scrolling will\n * be disabled when the sidenav is opened. By default this is the sidenav's direct parent.\n */\nfunction SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $mdInteraction, $animate,\n                          $compile, $parse, $log, $q, $document, $window, $$rAF) {\n  return {\n    restrict: 'E',\n    scope: {\n      isOpen: '=?mdIsOpen'\n    },\n    controller: '$mdSidenavController',\n    compile: function(element) {\n      element.addClass('md-closed').attr('tabIndex', '-1');\n      return postLink;\n    }\n  };\n\n  /**\n   * Directive Post Link function...\n   */\n  function postLink(scope, element, attr, sidenavCtrl) {\n    var lastParentOverFlow;\n    var backdrop;\n    var disableScrollTarget = null;\n    var disableCloseEvents;\n    var triggeringInteractionType;\n    var triggeringElement = null;\n    var previousContainerStyles;\n    var promise = $q.when(true);\n    var isLockedOpenParsed = $parse(attr.mdIsLockedOpen);\n    var ngWindow = angular.element($window);\n    var isLocked = function() {\n      return isLockedOpenParsed(scope.$parent, {\n        $mdMedia: $mdMedia\n      });\n    };\n\n    if (attr.mdDisableScrollTarget) {\n      disableScrollTarget = $document[0].querySelector(attr.mdDisableScrollTarget);\n\n      if (disableScrollTarget) {\n        disableScrollTarget = angular.element(disableScrollTarget);\n      } else {\n        $log.warn($mdUtil.supplant('mdSidenav: couldn\\'t find element matching ' +\n          'selector \"{selector}\". Falling back to parent.',\n          { selector: attr.mdDisableScrollTarget }));\n      }\n    }\n\n    if (!disableScrollTarget) {\n      disableScrollTarget = element.parent();\n    }\n\n    // Only create the backdrop if the backdrop isn't disabled.\n    if (!attr.hasOwnProperty('mdDisableBackdrop')) {\n      backdrop = $mdUtil.createBackdrop(scope, \"md-sidenav-backdrop md-opaque ng-enter\");\n    }\n\n    // If md-disable-close-events is set on the sidenav we will disable\n    // backdrop click and Escape key events\n    if (attr.hasOwnProperty('mdDisableCloseEvents')) {\n      disableCloseEvents = true;\n    }\n\n    element.addClass('_md');     // private md component indicator for styling\n    $mdTheming(element);\n\n    // The backdrop should inherit the sidenavs theme,\n    // because the backdrop will take its parent theme by default.\n    if (backdrop) $mdTheming.inherit(backdrop, element);\n\n    element.on('$destroy', function() {\n      backdrop && backdrop.remove();\n      sidenavCtrl.destroy();\n    });\n\n    scope.$on('$destroy', function(){\n      backdrop && backdrop.remove();\n    });\n\n    scope.$watch(isLocked, updateIsLocked);\n    scope.$watch('isOpen', updateIsOpen);\n\n\n    // Publish special accessor for the Controller instance\n    sidenavCtrl.$toggleOpen = toggleOpen;\n\n    /**\n     * Toggle the DOM classes to indicate `locked`\n     * @param isLocked\n     * @param oldValue\n     */\n    function updateIsLocked(isLocked, oldValue) {\n      scope.isLockedOpen = isLocked;\n      if (isLocked === oldValue) {\n        element.toggleClass('md-locked-open', !!isLocked);\n      } else {\n        $animate[isLocked ? 'addClass' : 'removeClass'](element, 'md-locked-open');\n      }\n      if (backdrop) {\n        backdrop.toggleClass('md-locked-open', !!isLocked);\n      }\n    }\n\n    /**\n     * Toggle the SideNav view and attach/detach listeners\n     * @param {boolean} isOpen\n     */\n    function updateIsOpen(isOpen) {\n      var focusEl = $mdUtil.findFocusTarget(element) || element;\n      var parent = element.parent();\n      var restorePositioning;\n\n      // If the user hasn't set the disable close events property we are adding\n      // click and escape events to close the sidenav\n      if (!disableCloseEvents) {\n        parent[isOpen ? 'on' : 'off']('keydown', onKeyDown);\n        if (backdrop) backdrop[isOpen ? 'on' : 'off']('click', close);\n      }\n\n      restorePositioning = updateContainerPositions(parent, isOpen);\n\n      if (isOpen) {\n        // Capture upon opening..\n        triggeringElement = $document[0].activeElement;\n        triggeringInteractionType = $mdInteraction.getLastInteractionType();\n      }\n\n      disableParentScroll(isOpen);\n\n      return promise = $q.all([\n        isOpen && backdrop ? $animate.enter(backdrop, parent) : backdrop ?\n                             $animate.leave(backdrop) : $q.when(true),\n        $animate[isOpen ? 'removeClass' : 'addClass'](element, 'md-closed')\n      ]).then(function() {\n        // Perform focus when animations are ALL done...\n        if (scope.isOpen) {\n          $$rAF(function() {\n            // Notifies child components that the sidenav was opened. Should wait\n            // a frame in order to allow for the element height to be computed.\n            ngWindow.triggerHandler('resize');\n          });\n\n          focusEl && focusEl.focus();\n        }\n\n        // Restores the positioning on the sidenav and backdrop.\n        restorePositioning && restorePositioning();\n      });\n    }\n\n    function updateContainerPositions(parent, willOpen) {\n      var drawerEl = element[0];\n      var scrollTop = parent[0].scrollTop;\n\n      if (willOpen && scrollTop) {\n        previousContainerStyles = {\n          top: drawerEl.style.top,\n          bottom: drawerEl.style.bottom,\n          height: drawerEl.style.height\n        };\n\n        // When the parent is scrolled down, then we want to be able to show the sidenav at the\n        // current scroll position. We're moving the sidenav down to the correct scroll position\n        // and apply the height of the parent, to increase the performance. Using 100% as height,\n        // will impact the performance heavily.\n        var positionStyle = {\n          top: scrollTop + 'px',\n          bottom: 'auto',\n          height: parent[0].clientHeight + 'px'\n        };\n\n        // Apply the new position styles to the sidenav and backdrop.\n        element.css(positionStyle);\n        backdrop.css(positionStyle);\n      }\n\n      // When the sidenav is closing and we have previous defined container styles,\n      // then we return a restore function, which resets the sidenav and backdrop.\n      if (!willOpen && previousContainerStyles) {\n        return function() {\n          drawerEl.style.top = previousContainerStyles.top;\n          drawerEl.style.bottom = previousContainerStyles.bottom;\n          drawerEl.style.height = previousContainerStyles.height;\n\n          backdrop[0].style.top = null;\n          backdrop[0].style.bottom = null;\n          backdrop[0].style.height = null;\n\n          previousContainerStyles = null;\n        };\n      }\n    }\n\n    /**\n     * Prevent parent scrolling (when the SideNav is open)\n     */\n    function disableParentScroll(disabled) {\n      if (disabled && !lastParentOverFlow) {\n        lastParentOverFlow = disableScrollTarget.css('overflow');\n        disableScrollTarget.css('overflow', 'hidden');\n      } else if (angular.isDefined(lastParentOverFlow)) {\n        disableScrollTarget.css('overflow', lastParentOverFlow);\n        lastParentOverFlow = undefined;\n      }\n    }\n\n    /**\n     * Toggle the sideNav view and publish a promise to be resolved when\n     * the view animation finishes.\n     * @param {boolean} isOpen true to open the sidenav, false to close it\n     * @returns {*} promise to be resolved when the view animation finishes\n     */\n    function toggleOpen(isOpen) {\n      if (scope.isOpen === isOpen) {\n        return $q.when(true);\n      } else {\n        if (scope.isOpen && sidenavCtrl.onCloseCb) sidenavCtrl.onCloseCb();\n\n        return $q(function(resolve) {\n          // Toggle value to force an async `updateIsOpen()` to run\n          scope.isOpen = isOpen;\n\n          $mdUtil.nextTick(function() {\n            // When the current `updateIsOpen()` animation finishes\n            promise.then(function(result) {\n\n              if (!scope.isOpen && triggeringElement && triggeringInteractionType === 'keyboard') {\n                // reset focus to originating element (if available) upon close\n                triggeringElement.focus();\n                triggeringElement = null;\n              }\n\n              resolve(result);\n            });\n          });\n        });\n      }\n    }\n\n    /**\n     * Auto-close sideNav when the `escape` key is pressed.\n     * @param {KeyboardEvent} ev keydown event\n     */\n    function onKeyDown(ev) {\n      var isEscape = (ev.keyCode === $mdConstant.KEY_CODE.ESCAPE);\n      return isEscape ? close(ev) : $q.when(true);\n    }\n\n    /**\n     * With backdrop `clicks` or `escape` key-press, immediately apply the CSS close transition...\n     * Then notify the controller to close() and perform its own actions.\n     * @param {Event} ev\n     * @returns {*}\n     */\n    function close(ev) {\n      ev.preventDefault();\n\n      return sidenavCtrl.close();\n    }\n  }\n}\n\n/*\n * @private\n * @ngdoc controller\n * @name SidenavController\n * @module material.components.sidenav\n */\nfunction SidenavController($scope, $attrs, $mdComponentRegistry, $q, $interpolate) {\n  var self = this;\n\n  // Use Default internal method until overridden by directive postLink\n\n  // Synchronous getters\n  self.isOpen = function() { return !!$scope.isOpen; };\n  self.isLockedOpen = function() { return !!$scope.isLockedOpen; };\n\n  // Synchronous setters\n  self.onClose = function (callback) {\n    self.onCloseCb = callback;\n    return self;\n  };\n\n  // Async actions\n  self.open   = function() { return self.$toggleOpen(true);  };\n  self.close  = function() { return self.$toggleOpen(false); };\n  self.toggle = function() { return self.$toggleOpen(!$scope.isOpen);  };\n  self.$toggleOpen = function(value) { return $q.when($scope.isOpen = value); };\n\n  // Evaluate the component id.\n  var rawId = $attrs.mdComponentId;\n  var hasDataBinding = rawId && rawId.indexOf($interpolate.startSymbol()) > -1;\n  var componentId = hasDataBinding ? $interpolate(rawId)($scope.$parent) : rawId;\n\n  // Register the component.\n  self.destroy = $mdComponentRegistry.register(self, componentId);\n\n  // Watch and update the component, if the id has changed.\n  if (hasDataBinding) {\n    $attrs.$observe('mdComponentId', function(id) {\n      if (id && id !== self.$$mdHandle) {\n        // `destroy` only deregisters the old component id so we can add the new one.\n        self.destroy();\n        self.destroy = $mdComponentRegistry.register(self, id);\n      }\n    });\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.slider\n */\nSliderDirective.$inject = [\"$$rAF\", \"$window\", \"$mdAria\", \"$mdUtil\", \"$mdConstant\", \"$mdTheming\", \"$mdGesture\", \"$parse\", \"$log\", \"$timeout\"];\nangular.module('material.components.slider', [\n  'material.core'\n])\n.directive('mdSlider', SliderDirective)\n.directive('mdSliderContainer', SliderContainerDirective);\n\n/**\n * @type {number} the page size used for stepping when page up/down keys are pressed.\n */\nvar stepPageSize = 10;\n/**\n * @type {number} the multiplier applied to a step when the arrow key is pressed along with\n *  alt, meta, or ctrl.\n */\nvar modifierMultiplier = 4;\n\n/**\n * @ngdoc directive\n * @name mdSliderContainer\n * @module material.components.slider\n * @restrict E\n * @description\n * The `<md-slider-container>` can hold the slider with two other elements.\n * In this case, the other elements are a `span` for the label and an `input` for displaying\n * the model value.\n *\n * @usage\n * <hljs lang=\"html\">\n *  <md-slider-container>\n *    <span>Red</span>\n *    <md-slider min=\"0\" max=\"255\" ng-model=\"color.red\" aria-label=\"red\" id=\"red-slider\">\n *    </md-slider>\n *    <md-input-container>\n *      <input type=\"number\" ng-model=\"color.red\" aria-label=\"Red\" aria-controls=\"red-slider\">\n *    </md-input-container>\n *  </md-slider-container>\n * </hljs>\n */\nfunction SliderContainerDirective() {\n  return {\n    controller: function () {},\n    compile: function (elem) {\n      var slider = elem.find('md-slider');\n\n      if (!slider) {\n        return;\n      }\n\n      var vertical = slider.attr('md-vertical');\n\n      if (vertical !== undefined) {\n        elem.attr('md-vertical', '');\n      }\n\n      if (!slider.attr('flex')) {\n        slider.attr('flex', '');\n      }\n\n      return function postLink(scope, element, attr, ctrl) {\n        element.addClass('_md');     // private md component indicator for styling\n\n        // We have to manually stop the $watch on ngDisabled because it exists\n        // on the parent scope, and won't be automatically destroyed when\n        // the component is destroyed.\n        function setDisable(value) {\n          element.children().attr('disabled', value);\n          element.find('input').attr('disabled', value);\n        }\n\n        var stopDisabledWatch = angular.noop;\n\n        if (attr.disabled) {\n          setDisable(true);\n        }\n        else if (attr.ngDisabled) {\n          stopDisabledWatch = scope.$watch(attr.ngDisabled, function (value) {\n            setDisable(value);\n          });\n        }\n\n        scope.$on('$destroy', function () {\n          stopDisabledWatch();\n        });\n\n        var initialMaxWidth;\n\n        /**\n         * @param {number} length of the input's string value\n         */\n        ctrl.fitInputWidthToTextLength = function (length) {\n          var input = element[0].querySelector('md-input-container');\n\n          if (input) {\n            var computedStyle = getComputedStyle(input);\n            var minWidth = parseInt(computedStyle.minWidth);\n            var padding = parseInt(computedStyle.paddingLeft) + parseInt(computedStyle.paddingRight);\n\n            initialMaxWidth = initialMaxWidth || parseInt(computedStyle.maxWidth);\n            var newMaxWidth = Math.max(initialMaxWidth, minWidth + padding + (minWidth / 2 * length));\n\n            input.style.maxWidth = newMaxWidth + 'px';\n          }\n        };\n      };\n    }\n  };\n}\n\n/**\n * @ngdoc directive\n * @name mdSlider\n * @module material.components.slider\n * @restrict E\n * @description\n * The `<md-slider>` component allows the user to choose from a range of values.\n *\n * As per the [Material Design spec](https://material.io/archive/guidelines/style/color.html#color-color-system)\n * the slider is in the accent color by default. The primary color palette may be used with\n * the `md-primary` class.\n *\n * The slider has two modes:\n * - \"normal\" mode where the user slides between a wide range of values\n * - \"discrete\" mode where the user slides between only a few select values\n *\n * To enable discrete mode, add the `md-discrete` attribute to a slider\n * and use the `step` attribute to change the distance between\n * values the user is allowed to pick.\n *\n * When using the keyboard:\n * - pressing the arrow keys will increase or decrease the slider's value by one step\n * - holding the Meta, Control, or Alt key while pressing the arrow keys will\n *   move the slider four steps at a time\n * - pressing the Home key will move the slider to the first allowed value\n * - pressing the End key will move the slider to the last allowed value\n * - pressing the Page Up key will increase the slider value by ten\n * - pressing the Page Down key will decrease the slider value by ten\n *\n * @usage\n * <h4>Normal Mode</h4>\n * <hljs lang=\"html\">\n * <md-slider ng-model=\"myValue\" min=\"5\" max=\"500\">\n * </md-slider>\n * </hljs>\n * <h4>Discrete Mode</h4>\n * <hljs lang=\"html\">\n * <md-slider md-discrete ng-model=\"myDiscreteValue\" step=\"10\" min=\"10\" max=\"130\">\n * </md-slider>\n * </hljs>\n * <h4>Invert Mode</h4>\n * <hljs lang=\"html\">\n * <md-slider md-invert ng-model=\"myValue\" step=\"10\" min=\"10\" max=\"130\">\n * </md-slider>\n * </hljs>\n *\n * @param {expression} ng-model Assignable angular expression to be data-bound.\n *  The expression should evaluate to a `number`.\n * @param {expression=} ng-disabled If this expression evaluates as truthy, the slider will be\n *  disabled.\n * @param {expression=} ng-readonly If this expression evaluates as truthy, the slider will be in\n *  read only mode.\n * @param {boolean=} md-discrete If this attribute exists during initialization, enable discrete\n *  mode. Defaults to `false`.\n * @param {boolean=} md-vertical If this attribute exists during initialization, enable vertical\n *  orientation mode. Defaults to `false`.\n * @param {boolean=} md-invert If this attribute exists during initialization, enable inverted mode.\n *  Defaults to `false`.\n * @param {number=} step The distance between values the user is allowed to pick. Defaults to `1`.\n * @param {number=} min The minimum value the user is allowed to pick. Defaults to `0`.\n * @param {number=} max The maximum value the user is allowed to pick. Defaults to `100`.\n * @param {number=} round The amount of numbers after the decimal point. The maximum is 6 to\n *  prevent scientific notation. Defaults to `3`.\n */\nfunction SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdTheming, $mdGesture,\n                         $parse, $log, $timeout) {\n  return {\n    scope: {},\n    require: ['?ngModel', '?^mdSliderContainer'],\n    template:\n      '<div class=\"md-slider-wrapper\">' +\n        '<div class=\"md-slider-content\">' +\n          '<div class=\"md-track-container\">' +\n            '<div class=\"md-track\"></div>' +\n            '<div class=\"md-track md-track-fill\"></div>' +\n            '<div class=\"md-track-ticks\"></div>' +\n          '</div>' +\n          '<div class=\"md-thumb-container\">' +\n            '<div class=\"md-thumb\"></div>' +\n            '<div class=\"md-focus-thumb\"></div>' +\n            '<div class=\"md-focus-ring\"></div>' +\n            '<div class=\"md-sign\">' +\n              '<span class=\"md-thumb-text\"></span>' +\n            '</div>' +\n            '<div class=\"md-disabled-thumb\"></div>' +\n          '</div>' +\n        '</div>' +\n      '</div>',\n    compile: compile\n  };\n\n  // **********************************************************\n  // Private Methods\n  // **********************************************************\n\n  function compile (tElement, tAttrs) {\n    var wrapper = angular.element(tElement[0].getElementsByClassName('md-slider-wrapper'));\n\n    var tabIndex = tAttrs.tabindex || 0;\n    wrapper.attr('tabindex', tabIndex);\n\n    if (tAttrs.disabled || tAttrs.ngDisabled) wrapper.attr('tabindex', -1);\n\n    wrapper.attr('role', 'slider');\n\n    $mdAria.expect(tElement, 'aria-label');\n\n    return postLink;\n  }\n\n  function postLink(scope, element, attr, ctrls) {\n    $mdTheming(element);\n    var ngModelCtrl = ctrls[0] || {\n      // Mock ngModelController if it doesn't exist to give us\n      // the minimum functionality needed\n      $setViewValue: function(val) {\n        this.$viewValue = val;\n        this.$viewChangeListeners.forEach(function(cb) { cb(); });\n      },\n      $parsers: [],\n      $formatters: [],\n      $viewChangeListeners: []\n    };\n\n    var containerCtrl = ctrls[1];\n    var container = angular.element($mdUtil.getClosest(element, '_md-slider-container', true));\n    var isDisabled = attr.ngDisabled ? angular.bind(null, $parse(attr.ngDisabled), scope.$parent) : function () {\n          return element[0].hasAttribute('disabled');\n        };\n\n    var thumb = angular.element(element[0].querySelector('.md-thumb'));\n    var thumbText = angular.element(element[0].querySelector('.md-thumb-text'));\n    var thumbContainer = thumb.parent();\n    var trackContainer = angular.element(element[0].querySelector('.md-track-container'));\n    var activeTrack = angular.element(element[0].querySelector('.md-track-fill'));\n    var tickContainer = angular.element(element[0].querySelector('.md-track-ticks'));\n    var wrapper = angular.element(element[0].getElementsByClassName('md-slider-wrapper'));\n    var content = angular.element(element[0].getElementsByClassName('md-slider-content'));\n    var throttledRefreshDimensions = $mdUtil.throttle(refreshSliderDimensions, 5000);\n\n    // Default values, overridable by attrs\n    var DEFAULT_ROUND = 3;\n    var vertical = angular.isDefined(attr.mdVertical);\n    var discrete = angular.isDefined(attr.mdDiscrete);\n    var invert = angular.isDefined(attr.mdInvert);\n    angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(0);\n    angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(100);\n    angular.isDefined(attr.step)? attr.$observe('step', updateStep) : updateStep(1);\n    angular.isDefined(attr.round)? attr.$observe('round', updateRound) : updateRound(DEFAULT_ROUND);\n\n    // We have to manually stop the $watch on ngDisabled because it exists\n    // on the parent scope, and won't be automatically destroyed when\n    // the component is destroyed.\n    var stopDisabledWatch = angular.noop;\n    if (attr.ngDisabled) {\n      stopDisabledWatch = scope.$parent.$watch(attr.ngDisabled, updateAriaDisabled);\n    }\n\n    $mdGesture.register(wrapper, 'drag', { horizontal: !vertical });\n\n    scope.mouseActive = false;\n\n    wrapper\n      .on('keydown', keydownListener)\n      .on('mousedown', mouseDownListener)\n      .on('focus', focusListener)\n      .on('blur', blurListener)\n      .on('$md.pressdown', onPressDown)\n      .on('$md.pressup', onPressUp)\n      .on('$md.dragstart', onDragStart)\n      .on('$md.drag', onDrag)\n      .on('$md.dragend', onDragEnd);\n\n    // On resize, recalculate the slider's dimensions and re-render\n    function updateAll() {\n      refreshSliderDimensions();\n      ngModelRender();\n    }\n    setTimeout(updateAll, 0);\n\n    var debouncedUpdateAll = $$rAF.throttle(updateAll);\n    angular.element($window).on('resize', debouncedUpdateAll);\n\n    scope.$on('$destroy', function() {\n      angular.element($window).off('resize', debouncedUpdateAll);\n    });\n\n    ngModelCtrl.$render = ngModelRender;\n    ngModelCtrl.$viewChangeListeners.push(ngModelRender);\n    ngModelCtrl.$formatters.push(minMaxValidator);\n    ngModelCtrl.$formatters.push(stepValidator);\n\n    /**\n     * Attributes\n     */\n    var min;\n    var max;\n    var step;\n    var round;\n    function updateMin(value) {\n      min = parseFloat(value);\n      ngModelCtrl.$viewValue = minMaxValidator(ngModelCtrl.$modelValue, min, max);\n      wrapper.attr('aria-valuemin', value);\n      updateAll();\n    }\n    function updateMax(value) {\n      max = parseFloat(value);\n      ngModelCtrl.$viewValue = minMaxValidator(ngModelCtrl.$modelValue, min, max);\n      wrapper.attr('aria-valuemax', value);\n      updateAll();\n    }\n    function updateStep(value) {\n      step = parseFloat(value);\n    }\n    function updateRound(value) {\n      // Set max round digits to 6, after 6 the input uses scientific notation\n      round = minMaxValidator(parseInt(value), 0, 6);\n    }\n    function updateAriaDisabled() {\n      element.attr('aria-disabled', !!isDisabled());\n    }\n\n    // Draw the ticks with canvas.\n    // The alternative to drawing ticks with canvas is to draw one element for each tick,\n    // which could quickly become a performance bottleneck.\n    var tickCanvas, tickCtx;\n    function redrawTicks() {\n      if (!discrete || isDisabled()) return;\n      if (angular.isUndefined(step))         return;\n\n      if (step <= 0) {\n        var msg = 'Slider step value must be greater than zero when in discrete mode';\n        $log.error(msg);\n        throw new Error(msg);\n      }\n\n      var numSteps = Math.floor((max - min) / step);\n      if (!tickCanvas) {\n        tickCanvas = angular.element('<canvas>').css('position', 'absolute');\n        tickContainer.append(tickCanvas);\n\n        tickCtx = tickCanvas[0].getContext('2d');\n      }\n\n      var dimensions = getSliderDimensions();\n\n      // If `dimensions` doesn't have height and width it might be the first attempt so we will refresh dimensions\n      if (dimensions && !dimensions.height && !dimensions.width) {\n        refreshSliderDimensions();\n        dimensions = sliderDimensions;\n      }\n\n      tickCanvas[0].width = dimensions.width;\n      tickCanvas[0].height = dimensions.height;\n\n      var distance;\n      for (var i = 0; i <= numSteps; i++) {\n        var trackTicksStyle = $window.getComputedStyle(tickContainer[0]);\n        tickCtx.fillStyle = trackTicksStyle.color || 'black';\n\n        distance = Math.floor((vertical ? dimensions.height : dimensions.width) * (i / numSteps));\n\n        tickCtx.fillRect(vertical ? 0 : distance - 1,\n          vertical ? distance - 1 : 0,\n          vertical ? dimensions.width : 2,\n          vertical ? 2 : dimensions.height);\n      }\n    }\n\n    function clearTicks() {\n      if (tickCanvas && tickCtx) {\n        var dimensions = getSliderDimensions();\n        tickCtx.clearRect(0, 0, dimensions.width, dimensions.height);\n      }\n    }\n\n    /**\n     * Refreshing Dimensions\n     */\n    var sliderDimensions = {};\n    refreshSliderDimensions();\n    function refreshSliderDimensions() {\n      sliderDimensions = trackContainer[0].getBoundingClientRect();\n    }\n    function getSliderDimensions() {\n      throttledRefreshDimensions();\n      return sliderDimensions;\n    }\n\n    /**\n     * left/right/up/down arrow listener\n     * @param {!KeyboardEvent} ev\n     */\n    function keydownListener(ev) {\n      if (isDisabled()) return;\n      var keyCodes = $mdConstant.KEY_CODE;\n\n      var changeAmount;\n      switch (ev.keyCode) {\n        case keyCodes.DOWN_ARROW:\n        case keyCodes.LEFT_ARROW:\n          ev.preventDefault();\n          changeAmount = -step;\n          break;\n        case keyCodes.UP_ARROW:\n        case keyCodes.RIGHT_ARROW:\n          ev.preventDefault();\n          changeAmount = step;\n          break;\n        case keyCodes.PAGE_DOWN:\n          ev.preventDefault();\n          changeAmount = -step * stepPageSize;\n          break;\n        case keyCodes.PAGE_UP:\n          ev.preventDefault();\n          changeAmount = step * stepPageSize;\n          break;\n        case keyCodes.HOME:\n          ev.preventDefault();\n          ev.stopPropagation();\n          updateValue(min);\n          break;\n        case keyCodes.END:\n          ev.preventDefault();\n          ev.stopPropagation();\n          updateValue(max);\n          break;\n      }\n      if (changeAmount) {\n        changeAmount = invert ? -changeAmount : changeAmount;\n        if (ev.metaKey || ev.ctrlKey || ev.altKey) {\n          changeAmount *= modifierMultiplier;\n        }\n        ev.preventDefault();\n        ev.stopPropagation();\n        updateValue(ngModelCtrl.$viewValue + changeAmount);\n      }\n    }\n\n    /**\n     * @param value new slider value used for setting the model value\n     */\n    function updateValue(value) {\n      scope.$evalAsync(function() {\n        setModelValue(value);\n      });\n    }\n\n    function mouseDownListener() {\n      redrawTicks();\n\n      scope.mouseActive = true;\n      wrapper.removeClass('md-focused');\n\n      $timeout(function() {\n        scope.mouseActive = false;\n      }, 100);\n    }\n\n    function focusListener() {\n      if (scope.mouseActive === false) {\n        wrapper.addClass('md-focused');\n      }\n    }\n\n    function blurListener() {\n      wrapper.removeClass('md-focused');\n      element.removeClass('md-active');\n      clearTicks();\n    }\n\n    /**\n     * ngModel setters and validators\n     */\n    function setModelValue(value) {\n      ngModelCtrl.$setViewValue(minMaxValidator(stepValidator(value)));\n    }\n    function ngModelRender() {\n      if (isNaN(ngModelCtrl.$viewValue)) {\n        ngModelCtrl.$viewValue = ngModelCtrl.$modelValue;\n      }\n\n      ngModelCtrl.$viewValue = minMaxValidator(ngModelCtrl.$viewValue);\n\n      var percent = valueToPercent(ngModelCtrl.$viewValue);\n      scope.modelValue = ngModelCtrl.$viewValue;\n      wrapper.attr('aria-valuenow', ngModelCtrl.$viewValue);\n      setSliderPercent(percent);\n      thumbText.text(ngModelCtrl.$viewValue);\n    }\n\n    function minMaxValidator(value, minValue, maxValue) {\n      if (angular.isNumber(value)) {\n        minValue = angular.isNumber(minValue) ? minValue : min;\n        maxValue = angular.isNumber(maxValue) ? maxValue : max;\n\n        return Math.max(minValue, Math.min(maxValue, value));\n      }\n    }\n\n    function stepValidator(value) {\n      if (angular.isNumber(value)) {\n        var formattedValue = (Math.round((value - min) / step) * step + min);\n        formattedValue = (Math.round(formattedValue * Math.pow(10, round)) / Math.pow(10, round));\n\n        if (containerCtrl && containerCtrl.fitInputWidthToTextLength) {\n          $mdUtil.debounce(function () {\n            containerCtrl.fitInputWidthToTextLength(formattedValue.toString().length);\n          }, 100)();\n        }\n\n        return formattedValue;\n      }\n    }\n\n    /**\n     * @param {number} percent 0-1\n     */\n    function setSliderPercent(percent) {\n\n      percent = clamp(percent);\n\n      var thumbPosition = (percent * 100) + '%';\n      var activeTrackPercent = invert ? (1 - percent) * 100 + '%' : thumbPosition;\n\n      if (vertical) {\n        thumbContainer.css('bottom', thumbPosition);\n      }\n      else {\n        $mdUtil.bidiProperty(thumbContainer, 'left', 'right', thumbPosition);\n      }\n\n\n      activeTrack.css(vertical ? 'height' : 'width', activeTrackPercent);\n\n      element.toggleClass((invert ? 'md-max' : 'md-min'), percent === 0);\n      element.toggleClass((invert ? 'md-min' : 'md-max'), percent === 1);\n    }\n\n    /**\n     * Slide listeners\n     */\n    var isDragging = false;\n\n    function onPressDown(ev) {\n      if (isDisabled()) return;\n\n      element.addClass('md-active');\n      element[0].focus();\n      refreshSliderDimensions();\n\n      var exactVal = percentToValue(positionToPercent(vertical ? ev.srcEvent.clientY : ev.srcEvent.clientX));\n      var closestVal = minMaxValidator(stepValidator(exactVal));\n      scope.$apply(function() {\n        setModelValue(closestVal);\n        setSliderPercent(valueToPercent(closestVal));\n      });\n    }\n    function onPressUp(ev) {\n      if (isDisabled()) return;\n\n      element.removeClass('md-dragging');\n\n      var exactVal = percentToValue(positionToPercent(vertical ? ev.srcEvent.clientY : ev.srcEvent.clientX));\n      var closestVal = minMaxValidator(stepValidator(exactVal));\n      scope.$apply(function() {\n        setModelValue(closestVal);\n        ngModelRender();\n      });\n    }\n    function onDragStart(ev) {\n      if (isDisabled()) return;\n      isDragging = true;\n\n      ev.stopPropagation();\n\n      element.addClass('md-dragging');\n      setSliderFromEvent(ev);\n    }\n    function onDrag(ev) {\n      if (!isDragging) return;\n      ev.stopPropagation();\n      setSliderFromEvent(ev);\n    }\n    function onDragEnd(ev) {\n      if (!isDragging) return;\n      ev.stopPropagation();\n      isDragging = false;\n    }\n\n    function setSliderFromEvent(ev) {\n      // While panning discrete, update only the\n      // visual positioning but not the model value.\n      if (discrete) adjustThumbPosition(vertical ? ev.srcEvent.clientY : ev.srcEvent.clientX);\n      else            doSlide(vertical ? ev.srcEvent.clientY : ev.srcEvent.clientX);\n    }\n\n    /**\n     * Slide the UI by changing the model value\n     * @param x\n     */\n    function doSlide(x) {\n      scope.$evalAsync(function() {\n        setModelValue(percentToValue(positionToPercent(x)));\n      });\n    }\n\n    /**\n     * Slide the UI without changing the model (while dragging/panning)\n     * @param x\n     */\n    function adjustThumbPosition(x) {\n      var exactVal = percentToValue(positionToPercent(x));\n      var closestVal = minMaxValidator(stepValidator(exactVal));\n      setSliderPercent(positionToPercent(x));\n      thumbText.text(closestVal);\n    }\n\n    /**\n    * Clamps the value to be between 0 and 1.\n    * @param {number} value The value to clamp.\n    * @returns {number}\n    */\n    function clamp(value) {\n      return Math.max(0, Math.min(value || 0, 1));\n    }\n\n    /**\n     * Convert position on slider to percentage value of offset from beginning...\n     * @param position\n     * @returns {number}\n     */\n    function positionToPercent(position) {\n      var offset = vertical ? sliderDimensions.top : sliderDimensions.left;\n      var size = vertical ? sliderDimensions.height : sliderDimensions.width;\n      var calc = (position - offset) / size;\n\n      if (!vertical && $mdUtil.isRtl(attr)) {\n        calc = 1 - calc;\n      }\n\n      return Math.max(0, Math.min(1, vertical ? 1 - calc : calc));\n    }\n\n    /**\n     * Convert percentage offset on slide to equivalent model value\n     * @param percent\n     * @returns {*}\n     */\n    function percentToValue(percent) {\n      var adjustedPercent = invert ? (1 - percent) : percent;\n      return (min + adjustedPercent * (max - min));\n    }\n\n    function valueToPercent(val) {\n      var percent = (val - min) / (max - min);\n      return invert ? (1 - percent) : percent;\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.sticky\n * @description\n * Sticky effects for md.\n */\nMdSticky.$inject = [\"$mdConstant\", \"$$rAF\", \"$mdUtil\", \"$compile\"];\nangular\n  .module('material.components.sticky', [\n    'material.core',\n    'material.components.content'\n  ])\n  .factory('$mdSticky', MdSticky);\n\n/**\n * @ngdoc service\n * @name $mdSticky\n * @module material.components.sticky\n *\n * @description\n * The `$mdSticky` service provides the capability to make elements sticky, even when the browser\n * does not support `position: sticky`.\n *\n * Whenever the current browser supports stickiness natively, the `$mdSticky` service will leverage\n * the native browser's sticky functionality.\n *\n * By default the `$mdSticky` service compiles the cloned element, when not specified through the\n * `stickyClone` parameter, in the same scope as the actual element lives.\n *\n * @usage\n * <hljs lang=\"js\">\n *   angular.module('myModule')\n *     .directive('stickyText', function($mdSticky) {\n *       return {\n *         restrict: 'E',\n *         template: '<span>Sticky Text</span>',\n *         link: function(scope, element) {\n *           $mdSticky(scope, element);\n *         }\n *       };\n *     });\n * </hljs>\n *\n * <h3>Notes</h3>\n * When using an element which contains a compiled directive that changes the DOM structure\n * during compilation, you should compile the clone yourself.\n *\n * An example of this usage can be found below:\n * <hljs lang=\"js\">\n *   angular.module('myModule')\n *     .directive('stickySelect', function($mdSticky, $compile) {\n *       var SELECT_TEMPLATE =\n *         '<md-select ng-model=\"selected\">' +\n *         '  <md-option>Option 1</md-option>' +\n *         '</md-select>';\n *\n *       return {\n *         restrict: 'E',\n *         replace: true,\n *         template: SELECT_TEMPLATE,\n *         link: function(scope, element) {\n *           $mdSticky(scope, element, $compile(SELECT_TEMPLATE)(scope));\n *         }\n *       };\n *     });\n * </hljs>\n *\n * @returns {function(IScope, JQLite, ITemplateLinkingFunction=): void} `$mdSticky` returns a\n *   function that takes three arguments:\n *   - `scope`: the scope to use when compiling the clone and listening for the `$destroy` event,\n *      which triggers removal of the clone\n *   - `element`: the element that will be 'sticky'\n *   - `stickyClone`: An optional clone of the element (returned from AngularJS'\n *      [$compile service](https://docs.angularjs.org/api/ng/service/$compile#usage)),\n *      that will be shown when the user starts scrolling past the original element. If not\n *      provided, the result of `element.clone()` will be used and compiled in the given scope.\n */\nfunction MdSticky($mdConstant, $$rAF, $mdUtil, $compile) {\n\n  var browserStickySupport = $mdUtil.checkStickySupport();\n\n  /**\n   * Registers an element as sticky, used internally by directives to register themselves.\n   */\n  return function registerStickyElement(scope, element, stickyClone) {\n    var contentCtrl = element.controller('mdContent');\n    if (!contentCtrl) return;\n\n    if (browserStickySupport) {\n      element.css({\n        position: browserStickySupport,\n        top: 0,\n        'z-index': 2\n      });\n    } else {\n      var $$sticky = contentCtrl.$element.data('$$sticky');\n      if (!$$sticky) {\n        $$sticky = setupSticky(contentCtrl);\n        contentCtrl.$element.data('$$sticky', $$sticky);\n      }\n\n      // Compile our cloned element, when cloned in this service, into the given scope.\n      var cloneElement = stickyClone || $compile(element.clone())(scope);\n\n      var deregister = $$sticky.add(element, cloneElement);\n      scope.$on('$destroy', deregister);\n    }\n  };\n\n  function setupSticky(contentCtrl) {\n    var contentEl = contentCtrl.$element;\n\n    // Refresh elements is very expensive, so we use the debounced\n    // version when possible.\n    var debouncedRefreshElements = $$rAF.throttle(refreshElements);\n\n    // setupAugmentedScrollEvents gives us `$scrollstart` and `$scroll`,\n    // more reliable than `scroll` on android.\n    setupAugmentedScrollEvents(contentEl);\n    contentEl.on('$scrollstart', debouncedRefreshElements);\n    contentEl.on('$scroll', onScroll);\n\n    var self;\n    return self = {\n      prev: null,\n      current: null, // the currently stickied item\n      next: null,\n      items: [],\n      add: add,\n      refreshElements: refreshElements\n    };\n\n    /***************\n     * Public\n     ***************/\n    // Add an element and its sticky clone to this content's sticky collection\n    function add(element, stickyClone) {\n      stickyClone.addClass('md-sticky-clone');\n\n      var item = {\n        element: element,\n        clone: stickyClone\n      };\n      self.items.push(item);\n\n      $mdUtil.nextTick(function() {\n        contentEl.prepend(item.clone);\n      });\n\n      debouncedRefreshElements();\n\n      return function remove() {\n        self.items.forEach(function(item, index) {\n          if (item.element[0] === element[0]) {\n            self.items.splice(index, 1);\n            item.clone.remove();\n          }\n        });\n        debouncedRefreshElements();\n      };\n    }\n\n    function refreshElements() {\n      // Sort our collection of elements by their current position in the DOM.\n      // We need to do this because our elements' order of being added may not\n      // be the same as their order of display.\n      self.items.forEach(refreshPosition);\n      self.items = self.items.sort(function(a, b) {\n        return a.top < b.top ? -1 : 1;\n      });\n\n      // Find which item in the list should be active,\n      // based upon the content's current scroll position\n      var item;\n      var currentScrollTop = contentEl.prop('scrollTop');\n      for (var i = self.items.length - 1; i >= 0; i--) {\n        if (currentScrollTop > self.items[i].top) {\n          item = self.items[i];\n          break;\n        }\n      }\n      setCurrentItem(item);\n    }\n\n    /***************\n     * Private\n     ***************/\n\n    // Find the `top` of an item relative to the content element,\n    // and also the height.\n    function refreshPosition(item) {\n      // Find the top of an item by adding to the offsetHeight until we reach the\n      // content element.\n      var current = item.element[0];\n      item.top = 0;\n      item.left = 0;\n      item.right = 0;\n      while (current && current !== contentEl[0]) {\n        item.top += current.offsetTop;\n        item.left += current.offsetLeft;\n        if (current.offsetParent) {\n          // Compute offsetRight\n          item.right += current.offsetParent.offsetWidth - current.offsetWidth - current.offsetLeft;\n        }\n        current = current.offsetParent;\n      }\n      item.height = item.element.prop('offsetHeight');\n\n      var defaultVal = $mdUtil.floatingScrollbars() ? '0' : undefined;\n      $mdUtil.bidi(item.clone, 'margin-left', item.left, defaultVal);\n      $mdUtil.bidi(item.clone, 'margin-right', defaultVal, item.right);\n    }\n\n    // As we scroll, push in and select the correct sticky element.\n    function onScroll() {\n      var scrollTop = contentEl.prop('scrollTop');\n      var isScrollingDown = scrollTop > (onScroll.prevScrollTop || 0);\n\n      // Store the previous scroll so we know which direction we are scrolling\n      onScroll.prevScrollTop = scrollTop;\n\n      //\n      // AT TOP (not scrolling)\n      //\n      if (scrollTop === 0) {\n        // If we're at the top, just clear the current item and return\n        setCurrentItem(null);\n        return;\n      }\n\n      //\n      // SCROLLING DOWN (going towards the next item)\n      //\n      if (isScrollingDown) {\n\n        // If we've scrolled down past the next item's position, sticky it and return\n        if (self.next && self.next.top <= scrollTop) {\n          setCurrentItem(self.next);\n          return;\n        }\n\n        // If the next item is close to the current one, push the current one up out of the way\n        if (self.current && self.next && self.next.top - scrollTop <= self.next.height) {\n          translate(self.current, scrollTop + (self.next.top - self.next.height - scrollTop));\n          return;\n        }\n      }\n\n      //\n      // SCROLLING UP (not at the top & not scrolling down; must be scrolling up)\n      //\n      if (!isScrollingDown) {\n\n        // If we've scrolled up past the previous item's position, sticky it and return\n        if (self.current && self.prev && scrollTop < self.current.top) {\n          setCurrentItem(self.prev);\n          return;\n        }\n\n        // If the next item is close to the current one, pull the current one down into view\n        if (self.next && self.current && (scrollTop >= (self.next.top - self.current.height))) {\n          translate(self.current, scrollTop + (self.next.top - scrollTop - self.current.height));\n          return;\n        }\n      }\n\n      //\n      // Otherwise, just move the current item to the proper place (scrolling up or down)\n      //\n      if (self.current) {\n        translate(self.current, scrollTop);\n      }\n    }\n\n    function setCurrentItem(item) {\n      if (self.current === item) return;\n      // Deactivate currently active item\n      if (self.current) {\n        translate(self.current, null);\n        setStickyState(self.current, null);\n      }\n\n      // Activate new item if given\n      if (item) {\n        setStickyState(item, 'active');\n      }\n\n      self.current = item;\n      var index = self.items.indexOf(item);\n      // If index === -1, index + 1 = 0. It works out.\n      self.next = self.items[index + 1];\n      self.prev = self.items[index - 1];\n      setStickyState(self.next, 'next');\n      setStickyState(self.prev, 'prev');\n    }\n\n    function setStickyState(item, state) {\n      if (!item || item.state === state) return;\n      if (item.state) {\n        item.clone.attr('sticky-prev-state', item.state);\n        item.element.attr('sticky-prev-state', item.state);\n      }\n      item.clone.attr('sticky-state', state);\n      item.element.attr('sticky-state', state);\n      item.state = state;\n    }\n\n    function translate(item, amount) {\n      if (!item) return;\n      if (amount === null || amount === undefined) {\n        if (item.translateY) {\n          item.translateY = null;\n          item.clone.css($mdConstant.CSS.TRANSFORM, '');\n        }\n      } else {\n        item.translateY = amount;\n\n        $mdUtil.bidi(item.clone, $mdConstant.CSS.TRANSFORM,\n          'translate3d(' + item.left + 'px,' + amount + 'px,0)',\n          'translateY(' + amount + 'px)'\n        );\n      }\n    }\n  }\n\n\n  // Android 4.4 don't accurately give scroll events.\n  // To fix this problem, we setup a fake scroll event. We say:\n  // > If a scroll or touchmove event has happened in the last DELAY milliseconds,\n  //   then send a `$scroll` event every animationFrame.\n  // Additionally, we add $scrollstart and $scrollend events.\n  function setupAugmentedScrollEvents(element) {\n    var SCROLL_END_DELAY = 200;\n    var isScrolling;\n    var lastScrollTime;\n    element.on('scroll touchmove', function() {\n      if (!isScrolling) {\n        isScrolling = true;\n        $$rAF.throttle(loopScrollEvent);\n        element.triggerHandler('$scrollstart');\n      }\n      element.triggerHandler('$scroll');\n      lastScrollTime = +$mdUtil.now();\n    });\n\n    function loopScrollEvent() {\n      if (+$mdUtil.now() - lastScrollTime > SCROLL_END_DELAY) {\n        isScrolling = false;\n        element.triggerHandler('$scrollend');\n      } else {\n        element.triggerHandler('$scroll');\n        $$rAF.throttle(loopScrollEvent);\n      }\n    }\n  }\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.subheader\n * @description\n * SubHeader module\n *\n *  Subheaders are special list tiles that delineate distinct sections of a\n *  list or grid list and are typically related to the current filtering or\n *  sorting criteria. Subheader tiles are either displayed inline with tiles or\n *  can be associated with content, for example, in an adjacent column.\n *\n *  Upon scrolling, subheaders remain pinned to the top of the screen and remain\n *  pinned until pushed on or off screen by the next subheader. @see [Material\n *  Design Specifications](https://material.io/archive/guidelines/components/subheaders.html)\n *\n *  > To improve the visual grouping of content, use the system color for your subheaders.\n *\n */\nMdSubheaderDirective.$inject = [\"$mdSticky\", \"$compile\", \"$mdTheming\", \"$mdUtil\", \"$mdAria\"];\nangular\n  .module('material.components.subheader', [\n    'material.core',\n    'material.components.sticky'\n  ])\n  .directive('mdSubheader', MdSubheaderDirective);\n\n/**\n * @ngdoc directive\n * @name mdSubheader\n * @module material.components.subheader\n *\n * @restrict E\n *\n * @description\n * The `md-subheader` directive creates a sticky subheader for a section.\n *\n * Developers are able to disable the stickiness of the subheader by using the following markup\n *\n * <hljs lang=\"html\">\n *   <md-subheader class=\"md-no-sticky\">Not Sticky</md-subheader>\n * </hljs>\n *\n * ### Notes\n * - The `md-subheader` directive uses the <a ng-href=\"api/service/$mdSticky\">$mdSticky</a> service\n * to make the subheader sticky.\n *\n * > Whenever the current browser doesn't support stickiness natively, the subheader\n * will be compiled twice to create a sticky clone of the subheader.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-subheader>Online Friends</md-subheader>\n * </hljs>\n */\n\nfunction MdSubheaderDirective($mdSticky, $compile, $mdTheming, $mdUtil, $mdAria) {\n  return {\n    restrict: 'E',\n    replace: true,\n    transclude: true,\n    template: (\n    '<div class=\"md-subheader _md\">' +\n    '  <div class=\"md-subheader-inner\">' +\n    '    <div class=\"md-subheader-content\"></div>' +\n    '  </div>' +\n    '</div>'\n    ),\n    link: function postLink(scope, element, attr, controllers, transclude) {\n      $mdTheming(element);\n      element.addClass('_md');\n\n      // Remove the ngRepeat attribute from the root element, because we don't want to compile\n      // the ngRepeat for the sticky clone again.\n      $mdUtil.prefixer().removeAttribute(element, 'ng-repeat');\n\n      var outerHTML = element[0].outerHTML;\n\n      function getContent(el) {\n        return angular.element(el[0].querySelector('.md-subheader-content'));\n      }\n\n      // Set the ARIA attributes on the original element since it keeps it's original place in\n      // the DOM, whereas the clones are in reverse order. Should be done after the outerHTML,\n      // in order to avoid having multiple element be marked as headers.\n      attr.$set('role', 'heading');\n      $mdAria.expect(element, 'aria-level', '2');\n\n      // Transclude the user-given contents of the subheader\n      // the conventional way.\n      transclude(scope, function(clone) {\n        getContent(element).append(clone);\n      });\n\n      // Create another clone, that uses the outer and inner contents\n      // of the element, that will be 'stickied' as the user scrolls.\n      if (!element.hasClass('md-no-sticky')) {\n        transclude(scope, function(clone) {\n          // If the user adds an ng-if or ng-repeat directly to the md-subheader element, the\n          // compiled clone below will only be a comment tag (since they replace their elements with\n          // a comment) which cannot be properly passed to the $mdSticky; so we wrap it in our own\n          // DIV to ensure we have something $mdSticky can use\n          var wrapper = $compile('<div class=\"md-subheader-wrapper\" aria-hidden=\"true\">' + outerHTML + '</div>')(scope);\n\n          // Delay initialization until after any `ng-if`/`ng-repeat`/etc has finished before\n          // attempting to create the clone\n          $mdUtil.nextTick(function() {\n            // Append our transcluded clone into the wrapper.\n            // We don't have to recompile the element again, because the clone is already\n            // compiled in it's transclusion scope. If we recompile the outerHTML of the new clone, we would lose\n            // our ngIf's and other previous registered bindings / properties.\n            getContent(wrapper).append(clone);\n          });\n\n          // Make the element sticky and provide the stickyClone our self, to avoid recompilation of the subheader\n          // element.\n          $mdSticky(scope, element, wrapper);\n        });\n      }\n    }\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.swipe\n * @description Swipe module!\n */\n/**\n * @ngdoc directive\n * @module material.components.swipe\n * @name mdSwipeLeft\n *\n * @restrict A\n *\n * @description\n * The md-swipe-left directive allows you to specify custom behavior when an element is swiped\n * left.\n *\n * ### Notes\n * - The `$event.currentTarget` of the swiped element will be `null`, but you can get a\n * reference to the element that actually holds the `md-swipe-left` directive by using\n * `$target.current`\n *\n * > You can see this in action on the <a ng-href=\"demo/swipe\">demo page</a> (Look at the Developer\n * Tools console while swiping).\n *\n * @usage\n * <hljs lang=\"html\">\n * <div md-swipe-left=\"onSwipeLeft($event, $target)\">Swipe me left!</div>\n * </hljs>\n */\n/**\n * @ngdoc directive\n * @module material.components.swipe\n * @name mdSwipeRight\n *\n * @restrict A\n *\n * @description\n * The md-swipe-right directive allows you to specify custom behavior when an element is swiped\n * right.\n *\n * ### Notes\n * - The `$event.currentTarget` of the swiped element will be `null`, but you can get a\n * reference to the element that actually holds the `md-swipe-right` directive by using\n * `$target.current`\n *\n * > You can see this in action on the <a ng-href=\"demo/swipe\">demo page</a> (Look at the Developer\n * Tools console while swiping).\n *\n * @usage\n * <hljs lang=\"html\">\n * <div md-swipe-right=\"onSwipeRight($event, $target)\">Swipe me right!</div>\n * </hljs>\n */\n/**\n * @ngdoc directive\n * @module material.components.swipe\n * @name mdSwipeUp\n *\n * @restrict A\n *\n * @description\n * The md-swipe-up directive allows you to specify custom behavior when an element is swiped\n * up.\n *\n * ### Notes\n * - The `$event.currentTarget` of the swiped element will be `null`, but you can get a\n * reference to the element that actually holds the `md-swipe-up` directive by using\n * `$target.current`\n *\n * > You can see this in action on the <a ng-href=\"demo/swipe\">demo page</a> (Look at the Developer\n * Tools console while swiping).\n *\n * @usage\n * <hljs lang=\"html\">\n * <div md-swipe-up=\"onSwipeUp($event, $target)\">Swipe me up!</div>\n * </hljs>\n */\n/**\n * @ngdoc directive\n * @module material.components.swipe\n * @name mdSwipeDown\n *\n * @restrict A\n *\n * @description\n * The md-swipe-down directive allows you to specify custom behavior when an element is swiped\n * down.\n *\n * ### Notes\n * - The `$event.currentTarget` of the swiped element will be `null`, but you can get a\n * reference to the element that actually holds the `md-swipe-down` directive by using\n * `$target.current`\n *\n * > You can see this in action on the <a ng-href=\"demo/swipe\">demo page</a> (Look at the Developer\n * Tools console while swiping).\n *\n * @usage\n * <hljs lang=\"html\">\n * <div md-swipe-down=\"onSwipeDown($event, $target)\">Swipe me down!</div>\n * </hljs>\n */\n\nangular.module('material.components.swipe', ['material.core'])\n    .directive('mdSwipeLeft', getDirective('SwipeLeft'))\n    .directive('mdSwipeRight', getDirective('SwipeRight'))\n    .directive('mdSwipeUp', getDirective('SwipeUp'))\n    .directive('mdSwipeDown', getDirective('SwipeDown'));\n\nfunction getDirective(name) {\n    DirectiveFactory.$inject = [\"$parse\"];\n  var directiveName = 'md' + name;\n  var eventName = '$md.' + name.toLowerCase();\n\n  return DirectiveFactory;\n\n  /* @ngInject */\n  function DirectiveFactory($parse) {\n      return { restrict: 'A', link: postLink };\n      function postLink(scope, element, attr) {\n        var fn = $parse(attr[directiveName]);\n        element.on(eventName, function(ev) {\n          var currentTarget = ev.currentTarget;\n          scope.$applyAsync(function() { fn(scope, { $event: ev, $target: { current: currentTarget } }); });\n        });\n      }\n    }\n}\n\n\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.switch\n */\n\nMdSwitch.$inject = [\"mdCheckboxDirective\", \"$mdUtil\", \"$mdConstant\", \"$parse\", \"$$rAF\", \"$mdGesture\", \"$timeout\"];\nangular.module('material.components.switch', [\n  'material.core',\n  'material.components.checkbox'\n])\n  .directive('mdSwitch', MdSwitch);\n\n/**\n * @ngdoc directive\n * @module material.components.switch\n * @name mdSwitch\n * @restrict E\n *\n * The switch directive is used very much like the normal [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).\n *\n * As per the [Material Design spec](https://material.io/archive/guidelines/style/color.html#color-color-system)\n * the switch is in the accent color by default. The primary color palette may be used with\n * the `md-primary` class.\n *\n * @param {expression} ng-model Assignable angular expression to data-bind to.\n * @param {string=} name Property name of the form under which the control is published.\n * @param {expression=} ng-true-value The value to which the expression should be set when selected.\n * @param {expression=} ng-false-value The value to which the expression should be set when not selected.\n * @param {expression=} ng-change Expression to be executed when the model value changes.\n * @param {expression=} ng-disabled En/Disable based on the expression.\n * @param {boolean=} md-no-ink Use of attribute indicates use of ripple ink effects.\n * @param {string=} aria-label Publish the button label used by screen-readers for accessibility. Defaults to the switch's text.\n * @param {boolean=} md-invert When set to true, the switch will be inverted.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-switch ng-model=\"isActive\" aria-label=\"Finished?\">\n *   Finished ?\n * </md-switch>\n *\n * <md-switch md-no-ink ng-model=\"hasInk\" aria-label=\"No Ink Effects\">\n *   No Ink Effects\n * </md-switch>\n *\n * <md-switch ng-disabled=\"true\" ng-model=\"isDisabled\" aria-label=\"Disabled\">\n *   Disabled\n * </md-switch>\n *\n * </hljs>\n */\nfunction MdSwitch(mdCheckboxDirective, $mdUtil, $mdConstant, $parse, $$rAF, $mdGesture, $timeout) {\n  var checkboxDirective = mdCheckboxDirective[0];\n\n  return {\n    restrict: 'E',\n    priority: $mdConstant.BEFORE_NG_ARIA,\n    transclude: true,\n    template:\n      '<div class=\"md-container\">' +\n        '<div class=\"md-bar\"></div>' +\n        '<div class=\"md-thumb-container\">' +\n          '<div class=\"md-thumb\" md-ink-ripple md-ink-ripple-checkbox></div>' +\n        '</div>'+\n      '</div>' +\n      '<div ng-transclude class=\"md-label\"></div>',\n    require: ['^?mdInputContainer', '?ngModel', '?^form'],\n    compile: mdSwitchCompile\n  };\n\n  function mdSwitchCompile(element, attr) {\n    var checkboxLink = checkboxDirective.compile(element, attr).post;\n    // No transition on initial load.\n    element.addClass('md-dragging');\n\n    return function (scope, element, attr, ctrls) {\n      var containerCtrl = ctrls[0];\n      var ngModel = ctrls[1] || $mdUtil.fakeNgModel();\n      var formCtrl = ctrls[2];\n\n      var disabledGetter = null;\n      if (attr.disabled != null) {\n        disabledGetter = function() { return true; };\n      } else if (attr.ngDisabled) {\n        disabledGetter = $parse(attr.ngDisabled);\n      }\n\n      var thumbContainer = angular.element(element[0].querySelector('.md-thumb-container'));\n      var switchContainer = angular.element(element[0].querySelector('.md-container'));\n      var labelContainer = angular.element(element[0].querySelector('.md-label'));\n\n      // no transition on initial load\n      $$rAF(function() {\n        element.removeClass('md-dragging');\n      });\n\n      checkboxLink(scope, element, attr, ctrls);\n\n      if (disabledGetter) {\n        scope.$watch(disabledGetter, function(isDisabled) {\n          element.attr('tabindex', isDisabled ? -1 : 0);\n        });\n      }\n\n      attr.$observe('mdInvert', function(newValue) {\n        var isInverted = $mdUtil.parseAttributeBoolean(newValue);\n\n        isInverted ? element.prepend(labelContainer) : element.prepend(switchContainer);\n\n        // Toggle a CSS class to update the margin.\n        element.toggleClass('md-inverted', isInverted);\n      });\n\n      // These events are triggered by setup drag\n      $mdGesture.register(switchContainer, 'drag');\n      switchContainer\n        .on('$md.dragstart', onDragStart)\n        .on('$md.drag', onDrag)\n        .on('$md.dragend', onDragEnd);\n\n      var drag;\n      function onDragStart(ev) {\n        // Don't go if the switch is disabled.\n        if (disabledGetter && disabledGetter(scope)) return;\n        ev.stopPropagation();\n\n        element.addClass('md-dragging');\n        drag = {width: thumbContainer.prop('offsetWidth')};\n      }\n\n      function onDrag(ev) {\n        if (!drag) return;\n        ev.stopPropagation();\n        ev.srcEvent && ev.srcEvent.preventDefault();\n\n        var percent = ev.pointer.distanceX / drag.width;\n\n        // if checked, start from right. else, start from left\n        var translate = ngModel.$viewValue ?  1 + percent : percent;\n        // Make sure the switch stays inside its bounds, 0-1%\n        translate = Math.max(0, Math.min(1, translate));\n\n        thumbContainer.css($mdConstant.CSS.TRANSFORM, 'translate3d(' + (100*translate) + '%,0,0)');\n        drag.translate = translate;\n      }\n\n      function onDragEnd(ev) {\n        if (!drag) return;\n        ev.stopPropagation();\n\n        element.removeClass('md-dragging');\n        thumbContainer.css($mdConstant.CSS.TRANSFORM, '');\n\n        // We changed if there is no distance (this is a click a click),\n        // or if the drag distance is >50% of the total.\n        var isChanged = ngModel.$viewValue ? drag.translate < 0.5 : drag.translate > 0.5;\n        if (isChanged) {\n          applyModelValue(!ngModel.$viewValue);\n        }\n        drag = null;\n\n        // Wait for incoming mouse click\n        scope.skipToggle = true;\n        $timeout(function() {\n          scope.skipToggle = false;\n        }, 1);\n      }\n\n      function applyModelValue(newValue) {\n        scope.$apply(function() {\n          ngModel.$setViewValue(newValue);\n          ngModel.$render();\n        });\n      }\n\n    };\n  }\n\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.tabs\n * @description\n *\n *  Tabs, created with the `<md-tabs>` directive provide *tabbed* navigation with different styles.\n *  The Tabs component consists of clickable tabs that are aligned horizontally side-by-side.\n *\n *  Features include support for:\n *\n *  - static or dynamic tabs,\n *  - responsive designs,\n *  - accessibility support (ARIA),\n *  - tab pagination,\n *  - external or internal tab content,\n *  - focus indicators and arrow-key navigations,\n *  - programmatic lookup and access to tab controllers, and\n *  - dynamic transitions through different tab contents.\n *\n */\n/*\n * @see js folder for tabs implementation\n */\nangular.module('material.components.tabs', [\n  'material.core',\n  'material.components.icon'\n]);\n\n})();\n(function(){\n\"use strict\";\n\nangular\n.module('material.components.tabs')\n.service('MdTabsPaginationService', MdTabsPaginationService);\n\n/**\n * @private\n * @module material.components.tabs\n * @name MdTabsPaginationService\n * @description Provides many standalone functions to ease in pagination calculations.\n *\n * Most functions accept the elements and the current offset.\n *\n * The `elements` parameter is typically the value returned from the `getElements()` function of the\n * tabsController.\n *\n * The `offset` parameter is always positive regardless of LTR or RTL (we simply make the LTR one\n * negative when we apply our transform). This is typically the `ctrl.leftOffset` variable in the\n * tabsController.\n *\n * @returns MdTabsPaginationService\n * @constructor\n */\nfunction MdTabsPaginationService() {\n  return {\n    decreasePageOffset: decreasePageOffset,\n    increasePageOffset: increasePageOffset,\n    getTabOffsets: getTabOffsets,\n    getTotalTabsWidth: getTotalTabsWidth\n  };\n\n  /**\n   * Returns the offset for the next decreasing page.\n   *\n   * @param elements\n   * @param currentOffset\n   * @returns {number}\n   */\n  function decreasePageOffset(elements, currentOffset) {\n    var canvas       = elements.canvas,\n        tabOffsets   = getTabOffsets(elements),\n        i, firstVisibleTabOffset;\n\n    // Find the first fully visible tab in offset range\n    for (i = 0; i < tabOffsets.length; i++) {\n      if (tabOffsets[i] >= currentOffset) {\n        firstVisibleTabOffset = tabOffsets[i];\n        break;\n      }\n    }\n\n    // Return (the first visible tab offset - the tabs container width) without going negative\n    return Math.max(0, firstVisibleTabOffset - canvas.clientWidth);\n  }\n\n  /**\n   * Returns the offset for the next increasing page.\n   *\n   * @param elements\n   * @param currentOffset\n   * @returns {number}\n   */\n  function increasePageOffset(elements, currentOffset) {\n    var canvas       = elements.canvas,\n        maxOffset    = getTotalTabsWidth(elements) - canvas.clientWidth,\n        tabOffsets   = getTabOffsets(elements),\n        i, firstHiddenTabOffset;\n\n    // Find the first partially (or fully) invisible tab\n    for (i = 0; i < tabOffsets.length, tabOffsets[i] <= currentOffset + canvas.clientWidth; i++) {\n      firstHiddenTabOffset = tabOffsets[i];\n    }\n\n    // Return the offset of the first hidden tab, or the maximum offset (whichever is smaller)\n    return Math.min(maxOffset, firstHiddenTabOffset);\n  }\n\n  /**\n   * Returns the offsets of all of the tabs based on their widths.\n   *\n   * @param elements\n   * @returns {number[]}\n   */\n  function getTabOffsets(elements) {\n    var i, tab, currentOffset = 0, offsets = [];\n\n    for (i = 0; i < elements.tabs.length; i++) {\n      tab = elements.tabs[i];\n      offsets.push(currentOffset);\n      currentOffset += tab.offsetWidth;\n    }\n\n    return offsets;\n  }\n\n  /**\n   * Sum the width of all tabs.\n   *\n   * @param elements\n   * @returns {number}\n   */\n  function getTotalTabsWidth(elements) {\n    var sum = 0, i, tab;\n\n    for (i = 0; i < elements.tabs.length; i++) {\n      tab = elements.tabs[i];\n      sum += tab.offsetWidth;\n    }\n\n    return sum;\n  }\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc directive\n * @name mdTab\n * @module material.components.tabs\n *\n * @restrict E\n *\n * @description\n * The `<md-tab>` is a nested directive used within `<md-tabs>` to specify a tab with a **label**\n * and optional *view content*.\n *\n * If the `label` attribute is not specified, then an optional `<md-tab-label>` tag can be used to\n * specify more complex tab header markup. If neither the **label** nor the **md-tab-label** are\n * specified, then the nested markup of the `<md-tab>` is used as the tab header markup.\n *\n * Please note that if you use `<md-tab-label>`, your content **MUST** be wrapped in the\n * `<md-tab-body>` tag.  This is to define a clear separation between the tab content and the tab\n * label.\n *\n * This container is used by the TabsController to show/hide the active tab's content view. This\n * synchronization is automatically managed by the internal TabsController whenever the tab\n * selection changes. Selection changes can be initiated via data binding changes, programmatic\n * invocation, or user gestures.\n *\n * @param {string=} label Optional attribute to specify a simple string as the tab label\n * @param {boolean=} ng-disabled If present and expression evaluates to truthy, disabled tab\n *  selection.\n * @param {string=} md-tab-class Optional attribute to specify a class that will be applied to the\n *  tab's button\n * @param {expression=} md-on-deselect Expression to be evaluated after the tab has been\n *  de-selected.\n * @param {expression=} md-on-select Expression to be evaluated after the tab has been selected.\n * @param {boolean=} md-active When true, sets the active tab.  Note: There can only be one active\n *  tab at a time.\n *\n *\n * @usage\n *\n * <hljs lang=\"html\">\n * <md-tab label=\"My Tab\" md-tab-class=\"my-content-tab\" ng-disabled md-on-select=\"onSelect()\"\n *         md-on-deselect=\"onDeselect()\">\n *   <h3>My Tab content</h3>\n * </md-tab>\n *\n * <md-tab>\n *   <md-tab-label>\n *     <h3>My Tab</h3>\n *   </md-tab-label>\n *   <md-tab-body>\n *     <p>\n *       Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque\n *       laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi\n *       architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit\n *       aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione\n *       voluptatem sequi nesciunt.\n *     </p>\n *   </md-tab-body>\n * </md-tab>\n * </hljs>\n *\n */\nangular\n    .module('material.components.tabs')\n    .directive('mdTab', MdTab);\n\nfunction MdTab () {\n  return {\n    require:  '^?mdTabs',\n    terminal: true,\n    compile:  function (element, attr) {\n      var label = firstChild(element, 'md-tab-label'),\n          body  = firstChild(element, 'md-tab-body');\n\n      if (label.length === 0) {\n        label = angular.element('<md-tab-label></md-tab-label>');\n        if (attr.label) label.text(attr.label);\n        else label.append(element.contents());\n\n        if (body.length === 0) {\n          var contents = element.contents().detach();\n          body         = angular.element('<md-tab-body></md-tab-body>');\n          body.append(contents);\n        }\n      }\n\n      element.append(label);\n      if (body.html()) element.append(body);\n\n      return postLink;\n    },\n    scope:    {\n      active:   '=?mdActive',\n      disabled: '=?ngDisabled',\n      select:   '&?mdOnSelect',\n      deselect: '&?mdOnDeselect',\n      tabClass: '@mdTabClass'\n    }\n  };\n\n  function postLink (scope, element, attr, ctrl) {\n    if (!ctrl) return;\n    var index = ctrl.getTabElementIndex(element),\n        body  = firstChild(element, 'md-tab-body').remove(),\n        label = firstChild(element, 'md-tab-label').remove(),\n        data  = ctrl.insertTab({\n          scope:    scope,\n          parent:   scope.$parent,\n          index:    index,\n          element:  element,\n          template: body.html(),\n          label:    label.html()\n        }, index);\n\n    scope.select   = scope.select || angular.noop;\n    scope.deselect = scope.deselect || angular.noop;\n\n    scope.$watch('active', function (active) { if (active) ctrl.select(data.getIndex(), true); });\n    scope.$watch('disabled', function () { ctrl.refreshIndex(); });\n    scope.$watch(\n        function () {\n          return ctrl.getTabElementIndex(element);\n        },\n        function (newIndex) {\n          data.index = newIndex;\n          ctrl.updateTabOrder();\n        }\n    );\n    scope.$on('$destroy', function () { ctrl.removeTab(data); });\n  }\n\n  function firstChild (element, tagName) {\n    var children = element[0].children;\n    for (var i = 0, len = children.length; i < len; i++) {\n      var child = children[i];\n      if (child.tagName === tagName.toUpperCase()) return angular.element(child);\n    }\n    return angular.element();\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\nangular\n    .module('material.components.tabs')\n    .directive('mdTabItem', MdTabItem);\n\nfunction MdTabItem () {\n  return {\n    require: '^?mdTabs',\n    link:    function link (scope, element, attr, ctrl) {\n      if (!ctrl) return;\n      ctrl.attachRipple(scope, element);\n    }\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\nangular\n    .module('material.components.tabs')\n    .directive('mdTabLabel', MdTabLabel);\n\nfunction MdTabLabel () {\n  return { terminal: true };\n}\n\n\n})();\n(function(){\n\"use strict\";\n\n\nMdTabScroll.$inject = [\"$parse\"];angular.module('material.components.tabs')\n    .directive('mdTabScroll', MdTabScroll);\n\nfunction MdTabScroll ($parse) {\n  return {\n    restrict: 'A',\n    compile: function ($element, attr) {\n      var fn = $parse(attr.mdTabScroll, null, true);\n      return function ngEventHandler (scope, element) {\n        element.on('wheel', function (event) {\n          scope.$apply(function () { fn(scope, { $event: event }); });\n        });\n      };\n    }\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMdTabsController.$inject = [\"$scope\", \"$element\", \"$window\", \"$mdConstant\", \"$mdTabInkRipple\", \"$mdUtil\", \"$animateCss\", \"$attrs\", \"$compile\", \"$mdTheming\", \"$mdInteraction\", \"$timeout\", \"MdTabsPaginationService\"];angular\n    .module('material.components.tabs')\n    .controller('MdTabsController', MdTabsController);\n\n/**\n * @ngInject\n */\nfunction MdTabsController ($scope, $element, $window, $mdConstant, $mdTabInkRipple, $mdUtil,\n                           $animateCss, $attrs, $compile, $mdTheming, $mdInteraction, $timeout,\n                           MdTabsPaginationService) {\n  // define private properties\n  var ctrl      = this,\n      locked    = false,\n      queue     = [],\n      destroyed = false,\n      loaded    = false;\n\n  // Define public methods\n  ctrl.$onInit            = $onInit;\n  ctrl.updatePagination   = $mdUtil.debounce(updatePagination, 100);\n  ctrl.redirectFocus      = redirectFocus;\n  ctrl.attachRipple       = attachRipple;\n  ctrl.insertTab          = insertTab;\n  ctrl.removeTab          = removeTab;\n  ctrl.select             = select;\n  ctrl.scroll             = scroll;\n  ctrl.nextPage           = nextPage;\n  ctrl.previousPage       = previousPage;\n  ctrl.keydown            = keydown;\n  ctrl.canPageForward     = canPageForward;\n  ctrl.canPageBack        = canPageBack;\n  ctrl.refreshIndex       = refreshIndex;\n  ctrl.incrementIndex     = incrementIndex;\n  ctrl.getTabElementIndex = getTabElementIndex;\n  ctrl.updateInkBarStyles = $mdUtil.debounce(updateInkBarStyles, 100);\n  ctrl.updateTabOrder     = $mdUtil.debounce(updateTabOrder, 100);\n  ctrl.getFocusedTabId    = getFocusedTabId;\n\n  // For AngularJS 1.4 and older, where there are no lifecycle hooks but bindings are pre-assigned,\n  // manually call the $onInit hook.\n  if (angular.version.major === 1 && angular.version.minor <= 4) {\n    this.$onInit();\n  }\n\n  /**\n   * AngularJS Lifecycle hook for newer AngularJS versions.\n   * Bindings are not guaranteed to have been assigned in the controller, but they are in the\n   * $onInit hook.\n   */\n  function $onInit() {\n    // Define one-way bindings\n    defineOneWayBinding('stretchTabs', handleStretchTabs);\n\n    // Define public properties with change handlers\n    defineProperty('focusIndex', handleFocusIndexChange, ctrl.selectedIndex || 0);\n    defineProperty('offsetLeft', handleOffsetChange, 0);\n    defineProperty('hasContent', handleHasContent, false);\n    defineProperty('maxTabWidth', handleMaxTabWidth, getMaxTabWidth());\n    defineProperty('shouldPaginate', handleShouldPaginate, false);\n\n    // Define boolean attributes\n    defineBooleanAttribute('noInkBar', handleInkBar);\n    defineBooleanAttribute('dynamicHeight', handleDynamicHeight);\n    defineBooleanAttribute('noPagination');\n    defineBooleanAttribute('swipeContent');\n    defineBooleanAttribute('autoselect');\n    defineBooleanAttribute('noSelectClick');\n    defineBooleanAttribute('centerTabs', handleCenterTabs);\n    defineBooleanAttribute('enableDisconnect');\n\n    // Define public properties\n    ctrl.scope             = $scope;\n    ctrl.parent            = $scope.$parent;\n    ctrl.tabs              = [];\n    ctrl.lastSelectedIndex = null;\n    ctrl.hasFocus          = false;\n    ctrl.styleTabItemFocus = false;\n    ctrl.shouldCenterTabs  = shouldCenterTabs();\n    ctrl.tabContentPrefix  = 'tab-content-';\n    ctrl.navigationHint = 'Use the left and right arrow keys to navigate between tabs';\n\n    // Setup the tabs controller after all bindings are available.\n    setupTabsController();\n  }\n\n  /**\n   * Perform setup for the controller, setup events and watcher(s)\n   */\n  function setupTabsController () {\n    ctrl.selectedIndex = ctrl.selectedIndex || 0;\n    compileTemplate();\n    configureWatchers();\n    bindEvents();\n    $mdTheming($element);\n    $mdUtil.nextTick(function () {\n      updateHeightFromContent();\n      adjustOffset();\n      updateInkBarStyles();\n      ctrl.tabs[ ctrl.selectedIndex ] && ctrl.tabs[ ctrl.selectedIndex ].scope.select();\n      loaded = true;\n      updatePagination();\n    });\n  }\n\n  /**\n   * Compiles the template provided by the user.  This is passed as an attribute from the tabs\n   * directive's template function.\n   */\n  function compileTemplate () {\n    var template = $attrs.$mdTabsTemplate,\n        element  = angular.element($element[0].querySelector('md-tab-data'));\n\n    element.html(template);\n    $compile(element.contents())(ctrl.parent);\n    delete $attrs.$mdTabsTemplate;\n  }\n\n  /**\n   * Binds events used by the tabs component.\n   */\n  function bindEvents () {\n    angular.element($window).on('resize', handleWindowResize);\n    $scope.$on('$destroy', cleanup);\n  }\n\n  /**\n   * Configure watcher(s) used by Tabs\n   */\n  function configureWatchers () {\n    $scope.$watch('$mdTabsCtrl.selectedIndex', handleSelectedIndexChange);\n  }\n\n  /**\n   * Creates a one-way binding manually rather than relying on AngularJS's isolated scope\n   * @param key\n   * @param handler\n   */\n  function defineOneWayBinding (key, handler) {\n    var attr = $attrs.$normalize('md-' + key);\n    if (handler) defineProperty(key, handler);\n    $attrs.$observe(attr, function (newValue) { ctrl[ key ] = newValue; });\n  }\n\n  /**\n   * Defines boolean attributes with default value set to true. I.e. md-stretch-tabs with no value\n   * will be treated as being truthy.\n   * @param {string} key\n   * @param {Function=} handler\n   */\n  function defineBooleanAttribute (key, handler) {\n    var attr = $attrs.$normalize('md-' + key);\n    if (handler) defineProperty(key, handler, undefined);\n    if ($attrs.hasOwnProperty(attr)) updateValue($attrs[attr]);\n    $attrs.$observe(attr, updateValue);\n    function updateValue (newValue) {\n      ctrl[ key ] = newValue !== 'false';\n    }\n  }\n\n  /**\n   * Remove any events defined by this controller\n   */\n  function cleanup () {\n    destroyed = true;\n    angular.element($window).off('resize', handleWindowResize);\n  }\n\n  // Change handlers\n\n  /**\n   * Toggles stretch tabs class and updates inkbar when tab stretching changes.\n   */\n  function handleStretchTabs () {\n    var elements = getElements();\n    angular.element(elements.wrapper).toggleClass('md-stretch-tabs', shouldStretchTabs());\n    updateInkBarStyles();\n  }\n\n  /**\n   * Update the value of ctrl.shouldCenterTabs.\n   */\n  function handleCenterTabs () {\n    ctrl.shouldCenterTabs = shouldCenterTabs();\n  }\n\n  /**\n   * @param {number} newWidth new max tab width in pixels\n   * @param {number} oldWidth previous max tab width in pixels\n   */\n  function handleMaxTabWidth (newWidth, oldWidth) {\n    if (newWidth !== oldWidth) {\n      var elements = getElements();\n\n      // Set the max width for the real tabs\n      angular.forEach(elements.tabs, function(tab) {\n        tab.style.maxWidth = newWidth + 'px';\n      });\n\n      // Set the max width for the dummy tabs too\n      angular.forEach(elements.dummies, function(tab) {\n        tab.style.maxWidth = newWidth + 'px';\n      });\n\n      $mdUtil.nextTick(ctrl.updateInkBarStyles);\n    }\n  }\n\n  function handleShouldPaginate (newValue, oldValue) {\n    if (newValue !== oldValue) {\n      ctrl.maxTabWidth      = getMaxTabWidth();\n      ctrl.shouldCenterTabs = shouldCenterTabs();\n      $mdUtil.nextTick(function () {\n        ctrl.maxTabWidth = getMaxTabWidth();\n        adjustOffset(ctrl.selectedIndex);\n      });\n    }\n  }\n\n  /**\n   * Add/remove the `md-no-tab-content` class depending on `ctrl.hasContent`\n   * @param {boolean} hasContent\n   */\n  function handleHasContent (hasContent) {\n    $element[ hasContent ? 'removeClass' : 'addClass' ]('md-no-tab-content');\n  }\n\n  /**\n   * Apply ctrl.offsetLeft to the paging element when it changes\n   * @param {string|number} left\n   */\n  function handleOffsetChange (left) {\n    var newValue = ((ctrl.shouldCenterTabs || isRtl() ? '' : '-') + left + 'px');\n\n    // Fix double-negative which can happen with RTL support\n    newValue = newValue.replace('--', '');\n\n    angular.element(getElements().paging).css($mdConstant.CSS.TRANSFORM,\n                                              'translate(' + newValue + ', 0)');\n    $scope.$broadcast('$mdTabsPaginationChanged');\n  }\n\n  /**\n   * Update the UI whenever `ctrl.focusIndex` is updated\n   * @param {number} newIndex\n   * @param {number} oldIndex\n   */\n  function handleFocusIndexChange (newIndex, oldIndex) {\n    if (newIndex === oldIndex) return;\n    if (!getElements().tabs[ newIndex ]) return;\n    adjustOffset();\n    redirectFocus();\n  }\n\n  /**\n   * Update the UI whenever the selected index changes. Calls user-defined select/deselect methods.\n   * @param {number} newValue selected index's new value\n   * @param {number} oldValue selected index's previous value\n   */\n  function handleSelectedIndexChange (newValue, oldValue) {\n    if (newValue === oldValue) return;\n\n    ctrl.selectedIndex     = getNearestSafeIndex(newValue);\n    ctrl.lastSelectedIndex = oldValue;\n    ctrl.updateInkBarStyles();\n    updateHeightFromContent();\n    adjustOffset(newValue);\n    $scope.$broadcast('$mdTabsChanged');\n    ctrl.tabs[ oldValue ] && ctrl.tabs[ oldValue ].scope.deselect();\n    ctrl.tabs[ newValue ] && ctrl.tabs[ newValue ].scope.select();\n  }\n\n  function getTabElementIndex(tabEl){\n    var tabs = $element[0].getElementsByTagName('md-tab');\n    return Array.prototype.indexOf.call(tabs, tabEl[0]);\n  }\n\n  /**\n   * Queues up a call to `handleWindowResize` when a resize occurs while the tabs component is\n   * hidden.\n   */\n  function handleResizeWhenVisible () {\n    // if there is already a watcher waiting for resize, do nothing\n    if (handleResizeWhenVisible.watcher) return;\n    // otherwise, we will abuse the $watch function to check for visible\n    handleResizeWhenVisible.watcher = $scope.$watch(function () {\n      // since we are checking for DOM size, we use $mdUtil.nextTick() to wait for after the DOM updates\n      $mdUtil.nextTick(function () {\n        // if the watcher has already run (ie. multiple digests in one cycle), do nothing\n        if (!handleResizeWhenVisible.watcher) return;\n\n        if ($element.prop('offsetParent')) {\n          handleResizeWhenVisible.watcher();\n          handleResizeWhenVisible.watcher = null;\n\n          handleWindowResize();\n        }\n      }, false);\n    });\n  }\n\n  // Event handlers / actions\n\n  /**\n   * Handle user keyboard interactions\n   * @param {KeyboardEvent} event keydown event\n   */\n  function keydown (event) {\n    switch (event.keyCode) {\n      case $mdConstant.KEY_CODE.LEFT_ARROW:\n        event.preventDefault();\n        incrementIndex(-1, true);\n        break;\n      case $mdConstant.KEY_CODE.RIGHT_ARROW:\n        event.preventDefault();\n        incrementIndex(1, true);\n        break;\n      case $mdConstant.KEY_CODE.SPACE:\n      case $mdConstant.KEY_CODE.ENTER:\n        event.preventDefault();\n        if (!locked) select(ctrl.focusIndex);\n        break;\n      case $mdConstant.KEY_CODE.TAB:\n        // On tabbing out of the tablist, reset hasFocus to reset ng-focused and\n        // its md-focused class if the focused tab is not the active tab.\n        if (ctrl.focusIndex !== ctrl.selectedIndex) {\n          ctrl.focusIndex = ctrl.selectedIndex;\n        }\n        break;\n    }\n  }\n\n  /**\n   * Update the selected index. Triggers a click event on the original `md-tab` element in order\n   * to fire user-added click events if canSkipClick or `md-no-select-click` are false.\n   * @param index\n   * @param canSkipClick Optionally allow not firing the click event if `md-no-select-click` is also true.\n   */\n  function select (index, canSkipClick) {\n    if (!locked) ctrl.focusIndex = ctrl.selectedIndex = index;\n    // skip the click event if noSelectClick is enabled\n    if (canSkipClick && ctrl.noSelectClick) return;\n    // nextTick is required to prevent errors in user-defined click events\n    $mdUtil.nextTick(function () {\n      ctrl.tabs[ index ].element.triggerHandler('click');\n    }, false);\n  }\n\n  /**\n   * When pagination is on, this makes sure the selected index is in view.\n   * @param {WheelEvent} event\n   */\n  function scroll (event) {\n    if (!ctrl.shouldPaginate) return;\n    event.preventDefault();\n    if (event.deltaY) {\n      ctrl.offsetLeft = fixOffset(ctrl.offsetLeft + event.deltaY);\n    } else if (event.deltaX) {\n      ctrl.offsetLeft = fixOffset(ctrl.offsetLeft + event.deltaX);\n    }\n  }\n\n  /**\n   * Slides the tabs over approximately one page forward.\n   */\n  function nextPage () {\n    if (!ctrl.canPageForward()) { return; }\n\n    var newOffset = MdTabsPaginationService.increasePageOffset(getElements(), ctrl.offsetLeft);\n\n    ctrl.offsetLeft = fixOffset(newOffset);\n  }\n\n  /**\n   * Slides the tabs over approximately one page backward.\n   */\n  function previousPage () {\n    if (!ctrl.canPageBack()) { return; }\n\n    var newOffset = MdTabsPaginationService.decreasePageOffset(getElements(), ctrl.offsetLeft);\n\n    // Set the new offset\n    ctrl.offsetLeft = fixOffset(newOffset);\n  }\n\n  /**\n   * Update size calculations when the window is resized.\n   */\n  function handleWindowResize () {\n    ctrl.lastSelectedIndex = ctrl.selectedIndex;\n    ctrl.offsetLeft        = fixOffset(ctrl.offsetLeft);\n\n    $mdUtil.nextTick(function () {\n      ctrl.updateInkBarStyles();\n      updatePagination();\n    });\n  }\n\n  /**\n   * Hides or shows the tabs ink bar.\n   * @param {boolean} hide A Boolean (not just truthy/falsy) value to determine whether the class\n   * should be added or removed.\n   */\n  function handleInkBar (hide) {\n    angular.element(getElements().inkBar).toggleClass('ng-hide', hide);\n  }\n\n  /**\n   * Enables or disables tabs dynamic height.\n   * @param {boolean} value A Boolean (not just truthy/falsy) value to determine whether the class\n   * should be added or removed.\n   */\n  function handleDynamicHeight (value) {\n    $element.toggleClass('md-dynamic-height', value);\n  }\n\n  /**\n   * Remove a tab from the data and select the nearest valid tab.\n   * @param {Object} tabData tab to remove\n   */\n  function removeTab (tabData) {\n    if (destroyed) return;\n    var selectedIndex = ctrl.selectedIndex,\n        tab           = ctrl.tabs.splice(tabData.getIndex(), 1)[ 0 ];\n    refreshIndex();\n    // when removing a tab, if the selected index did not change, we have to manually trigger the\n    //   tab select/deselect events\n    if (ctrl.selectedIndex === selectedIndex) {\n      tab.scope.deselect();\n      ctrl.tabs[ ctrl.selectedIndex ] && ctrl.tabs[ ctrl.selectedIndex ].scope.select();\n    }\n    $mdUtil.nextTick(function () {\n      updatePagination();\n      ctrl.offsetLeft = fixOffset(ctrl.offsetLeft);\n    });\n  }\n\n  /**\n   * Create an entry in the tabs array for a new tab at the specified index.\n   * @param {Object} tabData tab to insert\n   * @param {number} index location to insert the new tab\n   * @returns {Object} the inserted tab\n   */\n  function insertTab (tabData, index) {\n    var hasLoaded = loaded;\n    var proto = {\n          getIndex:     function () { return ctrl.tabs.indexOf(tab); },\n          isActive:     function () { return this.getIndex() === ctrl.selectedIndex; },\n          isLeft:       function () { return this.getIndex() < ctrl.selectedIndex; },\n          isRight:      function () { return this.getIndex() > ctrl.selectedIndex; },\n          shouldRender: function () { return ctrl.dynamicHeight || this.isActive(); },\n          hasFocus:     function () {\n            return ctrl.styleTabItemFocus\n                && ctrl.hasFocus && this.getIndex() === ctrl.focusIndex;\n          },\n          id:           $mdUtil.nextUid(),\n          hasContent: !!(tabData.template && tabData.template.trim())\n    };\n    var tab = angular.extend(proto, tabData);\n\n    if (angular.isDefined(index)) {\n      ctrl.tabs.splice(index, 0, tab);\n    } else {\n      ctrl.tabs.push(tab);\n    }\n    processQueue();\n    updateHasContent();\n\n    $mdUtil.nextTick(function () {\n      updatePagination();\n      setAriaControls(tab);\n\n      // if autoselect is enabled, select the newly added tab\n      if (hasLoaded && ctrl.autoselect) {\n        $mdUtil.nextTick(function () {\n          $mdUtil.nextTick(function () { select(ctrl.tabs.indexOf(tab)); });\n        });\n      }\n    });\n    return tab;\n  }\n\n  // Getter methods\n\n  /**\n   * Gathers references to all of the DOM elements used by this controller.\n   * @returns {Object}\n   */\n  function getElements () {\n    var elements = {};\n    var node = $element[0];\n\n    // gather tab bar elements\n    elements.wrapper = node.querySelector('md-tabs-wrapper');\n    elements.canvas  = elements.wrapper.querySelector('md-tabs-canvas');\n    elements.paging  = elements.canvas.querySelector('md-pagination-wrapper');\n    elements.inkBar  = elements.paging.querySelector('md-ink-bar');\n    elements.nextButton = node.querySelector('md-next-button');\n    elements.prevButton = node.querySelector('md-prev-button');\n\n    elements.contents = node.querySelectorAll('md-tabs-content-wrapper > md-tab-content');\n    elements.tabs    = elements.paging.querySelectorAll('md-tab-item');\n    elements.dummies = elements.canvas.querySelectorAll('md-dummy-tab');\n\n    return elements;\n  }\n\n  /**\n   * Determines whether or not the left pagination arrow should be enabled.\n   * @returns {boolean}\n   */\n  function canPageBack () {\n    // This works for both LTR and RTL\n    return ctrl.offsetLeft > 0;\n  }\n\n  /**\n   * Determines whether or not the right pagination arrow should be enabled.\n   * @returns {*|boolean}\n   */\n  function canPageForward () {\n    var elements = getElements();\n    var lastTab = elements.tabs[ elements.tabs.length - 1 ];\n\n    if (isRtl()) {\n      return ctrl.offsetLeft < elements.paging.offsetWidth - elements.canvas.offsetWidth;\n    }\n\n    return lastTab && lastTab.offsetLeft + lastTab.offsetWidth > elements.canvas.clientWidth +\n        ctrl.offsetLeft;\n  }\n\n  /**\n   * Returns currently focused tab item's element ID\n   */\n  function getFocusedTabId() {\n    var focusedTab = ctrl.tabs[ctrl.focusIndex];\n    if (!focusedTab || !focusedTab.id) {\n      return null;\n    }\n    return 'tab-item-' + focusedTab.id;\n  }\n\n  /**\n   * Determines if the UI should stretch the tabs to fill the available space.\n   * @returns {*}\n   */\n  function shouldStretchTabs () {\n    switch (ctrl.stretchTabs) {\n      case 'always':\n        return true;\n      case 'never':\n        return false;\n      default:\n        return !ctrl.shouldPaginate\n            && $window.matchMedia('(max-width: 600px)').matches;\n    }\n  }\n\n  /**\n   * Determines if the tabs should appear centered.\n   * @returns {boolean}\n   */\n  function shouldCenterTabs () {\n    return ctrl.centerTabs && !ctrl.shouldPaginate;\n  }\n\n  /**\n   * Determines if pagination is necessary to display the tabs within the available space.\n   * @returns {boolean} true if pagination is necessary, false otherwise\n   */\n  function shouldPaginate () {\n    var shouldPaginate;\n    if (ctrl.noPagination || !loaded) return false;\n    var canvasWidth = $element.prop('clientWidth');\n\n    angular.forEach(getElements().tabs, function (tab) {\n      canvasWidth -= tab.offsetWidth;\n    });\n\n    shouldPaginate = canvasWidth < 0;\n    // Work around width calculation issues on IE11 when pagination is enabled.\n    // Don't do this on other browsers because it breaks scroll to new tab animation.\n    if ($mdUtil.msie) {\n      if (shouldPaginate) {\n        getElements().paging.style.width = '999999px';\n      } else {\n        getElements().paging.style.width = undefined;\n      }\n    }\n    return shouldPaginate;\n  }\n\n  /**\n   * Finds the nearest tab index that is available. This is primarily used for when the active\n   * tab is removed.\n   * @param newIndex\n   * @returns {*}\n   */\n  function getNearestSafeIndex (newIndex) {\n    if (newIndex === -1) return -1;\n    var maxOffset = Math.max(ctrl.tabs.length - newIndex, newIndex),\n        i, tab;\n    for (i = 0; i <= maxOffset; i++) {\n      tab = ctrl.tabs[ newIndex + i ];\n      if (tab && (tab.scope.disabled !== true)) return tab.getIndex();\n      tab = ctrl.tabs[ newIndex - i ];\n      if (tab && (tab.scope.disabled !== true)) return tab.getIndex();\n    }\n    return newIndex;\n  }\n\n  // Utility methods\n\n  /**\n   * Defines a property using a getter and setter in order to trigger a change handler without\n   * using `$watch` to observe changes.\n   * @param {PropertyKey} key\n   * @param {Function} handler\n   * @param {any} value\n   */\n  function defineProperty (key, handler, value) {\n    Object.defineProperty(ctrl, key, {\n      get: function () { return value; },\n      set: function (newValue) {\n        var oldValue = value;\n        value        = newValue;\n        handler && handler(newValue, oldValue);\n      }\n    });\n  }\n\n  /**\n   * Updates whether or not pagination should be displayed.\n   */\n  function updatePagination () {\n    ctrl.maxTabWidth = getMaxTabWidth();\n    ctrl.shouldPaginate = shouldPaginate();\n  }\n\n  /**\n   * @param {Array<HTMLElement>} tabs tab item elements for use in computing total width\n   * @returns {number} the width of the tabs in the specified array in pixels\n   */\n  function calcTabsWidth(tabs) {\n    var width = 0;\n\n    angular.forEach(tabs, function (tab) {\n      // Uses the larger value between `getBoundingClientRect().width` and `offsetWidth`.  This\n      // prevents `offsetWidth` value from being rounded down and causing wrapping issues, but\n      // also handles scenarios where `getBoundingClientRect()` is inaccurate (ie. tabs inside\n      // of a dialog).\n      width += Math.max(tab.offsetWidth, tab.getBoundingClientRect().width);\n    });\n\n    return Math.ceil(width);\n  }\n\n  /**\n   * @returns {number} either the max width as constrained by the container or the max width from\n   * the 2017 version of the Material Design spec.\n   */\n  function getMaxTabWidth() {\n    var elements = getElements(),\n      containerWidth = elements.canvas.clientWidth,\n\n      // See https://material.io/archive/guidelines/components/tabs.html#tabs-specs\n      specMax = 264;\n\n    // Do the spec maximum, or the canvas width; whichever is *smaller* (tabs larger than the canvas\n    // width can break the pagination) but not less than 0\n    return Math.max(0, Math.min(containerWidth - 1, specMax));\n  }\n\n  /**\n   * Re-orders the tabs and updates the selected and focus indexes to their new positions.\n   * This is triggered by `tabDirective.js` when the user's tabs have been re-ordered.\n   */\n  function updateTabOrder () {\n    var selectedItem   = ctrl.tabs[ ctrl.selectedIndex ],\n        focusItem      = ctrl.tabs[ ctrl.focusIndex ];\n    ctrl.tabs          = ctrl.tabs.sort(function (a, b) {\n      return a.index - b.index;\n    });\n    ctrl.selectedIndex = ctrl.tabs.indexOf(selectedItem);\n    ctrl.focusIndex    = ctrl.tabs.indexOf(focusItem);\n  }\n\n  /**\n   * This moves the selected or focus index left or right. This is used by the keydown handler.\n   * @param {number} inc amount to increment\n   * @param {boolean} focus true to increment the focus index, false to increment the selected index\n   */\n  function incrementIndex (inc, focus) {\n    var newIndex,\n        key   = focus ? 'focusIndex' : 'selectedIndex',\n        index = ctrl[ key ];\n    for (newIndex = index + inc;\n         ctrl.tabs[ newIndex ] && ctrl.tabs[ newIndex ].scope.disabled;\n         newIndex += inc) { /* do nothing */ }\n\n    newIndex = (index + inc + ctrl.tabs.length) % ctrl.tabs.length;\n\n    if (ctrl.tabs[ newIndex ]) {\n      ctrl[ key ] = newIndex;\n    }\n  }\n\n  /**\n   * This is used to forward focus to tab container elements. This method is necessary to avoid\n   * animation issues when attempting to focus an item that is out of view.\n   */\n  function redirectFocus () {\n    ctrl.styleTabItemFocus = ($mdInteraction.getLastInteractionType() === 'keyboard');\n    var tabToFocus = getElements().tabs[ctrl.focusIndex];\n    if (tabToFocus) {\n      tabToFocus.focus();\n    }\n  }\n\n  /**\n   * Forces the pagination to move the focused tab into view.\n   * @param {number=} index of tab to have its offset adjusted\n   */\n  function adjustOffset (index) {\n    var elements = getElements();\n\n    if (!angular.isNumber(index)) index = ctrl.focusIndex;\n    if (!elements.tabs[ index ]) return;\n    if (ctrl.shouldCenterTabs) return;\n    var tab         = elements.tabs[ index ],\n        left        = tab.offsetLeft,\n        right       = tab.offsetWidth + left,\n        extraOffset = 32;\n\n    // If we are selecting the first tab (in LTR and RTL), always set the offset to 0\n    if (index === 0) {\n      ctrl.offsetLeft = 0;\n      return;\n    }\n\n    if (isRtl()) {\n      var tabWidthsBefore = calcTabsWidth(Array.prototype.slice.call(elements.tabs, 0, index));\n      var tabWidthsIncluding = calcTabsWidth(Array.prototype.slice.call(elements.tabs, 0, index + 1));\n\n      ctrl.offsetLeft = Math.min(ctrl.offsetLeft, fixOffset(tabWidthsBefore));\n      ctrl.offsetLeft = Math.max(ctrl.offsetLeft, fixOffset(tabWidthsIncluding - elements.canvas.clientWidth));\n    } else {\n      ctrl.offsetLeft = Math.max(ctrl.offsetLeft, fixOffset(right - elements.canvas.clientWidth + extraOffset));\n      ctrl.offsetLeft = Math.min(ctrl.offsetLeft, fixOffset(left));\n    }\n  }\n\n  /**\n   * Iterates through all queued functions and clears the queue. This is used for functions that\n   * are called before the UI is ready, such as size calculations.\n   */\n  function processQueue () {\n    queue.forEach(function (func) { $mdUtil.nextTick(func); });\n    queue = [];\n  }\n\n  /**\n   * Determines if the tab content area is needed.\n   */\n  function updateHasContent () {\n    var hasContent = false;\n    var i;\n\n    for (i = 0; i < ctrl.tabs.length; i++) {\n      if (ctrl.tabs[i].hasContent) {\n        hasContent = true;\n        break;\n      }\n    }\n\n    ctrl.hasContent = hasContent;\n  }\n\n  /**\n   * Moves the indexes to their nearest valid values.\n   */\n  function refreshIndex () {\n    ctrl.selectedIndex = getNearestSafeIndex(ctrl.selectedIndex);\n    ctrl.focusIndex    = getNearestSafeIndex(ctrl.focusIndex);\n  }\n\n  /**\n   * Calculates the content height of the current tab.\n   * @returns {*}\n   */\n  function updateHeightFromContent () {\n    if (!ctrl.dynamicHeight) return $element.css('height', '');\n    if (!ctrl.tabs.length) return queue.push(updateHeightFromContent);\n\n    var elements = getElements();\n\n    var tabContent    = elements.contents[ ctrl.selectedIndex ],\n        contentHeight = tabContent ? tabContent.offsetHeight : 0,\n        tabsHeight    = elements.wrapper.offsetHeight,\n        newHeight     = contentHeight + tabsHeight,\n        currentHeight = $element.prop('clientHeight');\n\n    if (currentHeight === newHeight) return;\n\n    // Adjusts calculations for when the buttons are bottom-aligned since this relies on absolute\n    // positioning.  This should probably be cleaned up if a cleaner solution is possible.\n    if ($element.attr('md-align-tabs') === 'bottom') {\n      currentHeight -= tabsHeight;\n      newHeight -= tabsHeight;\n      // Need to include bottom border in these calculations\n      if ($element.attr('md-border-bottom') !== undefined) {\n        ++currentHeight;\n      }\n    }\n\n    // Lock during animation so the user can't change tabs\n    locked = true;\n\n    var fromHeight = { height: currentHeight + 'px' },\n        toHeight = { height: newHeight + 'px' };\n\n    // Set the height to the current, specific pixel height to fix a bug on iOS where the height\n    // first animates to 0, then back to the proper height causing a visual glitch\n    $element.css(fromHeight);\n\n    // Animate the height from the old to the new\n    $animateCss($element, {\n      from: fromHeight,\n      to: toHeight,\n      easing: 'cubic-bezier(0.35, 0, 0.25, 1)',\n      duration: 0.5\n    }).start().done(function () {\n      // Then (to fix the same iOS issue as above), disable transitions and remove the specific\n      // pixel height so the height can size with browser width/content changes, etc.\n      $element.css({\n        transition: 'none',\n        height: ''\n      });\n\n      // In the next tick, re-allow transitions (if we do it all at once, $element.css is \"smart\"\n      // enough to batch it for us instead of doing it immediately, which undoes the original\n      // transition: none)\n      $mdUtil.nextTick(function() {\n        $element.css('transition', '');\n      });\n\n      // And unlock so tab changes can occur\n      locked = false;\n    });\n  }\n\n  /**\n   * Repositions the ink bar to the selected tab.\n   * Parameters are used when calling itself recursively when md-center-tabs is used as we need to\n   * run two passes to properly center the tabs. These parameters ensure that we only run two passes\n   * and that we don't run indefinitely.\n   * @param {number=} previousTotalWidth previous width of pagination wrapper\n   * @param {number=} previousWidthOfTabItems previous width of all tab items\n   */\n  function updateInkBarStyles (previousTotalWidth, previousWidthOfTabItems) {\n    if (ctrl.noInkBar) {\n      return;\n    }\n    var elements = getElements();\n\n    if (!elements.tabs[ ctrl.selectedIndex ]) {\n      angular.element(elements.inkBar).css({ left: 'auto', right: 'auto' });\n      return;\n    }\n\n    if (!ctrl.tabs.length) {\n      queue.push(ctrl.updateInkBarStyles);\n      return;\n    }\n    // If the element is not visible, we will not be able to calculate sizes until it becomes\n    // visible. We should treat that as a resize event rather than just updating the ink bar.\n    if (!$element.prop('offsetParent')) {\n      handleResizeWhenVisible();\n      return;\n    }\n\n    var index      = ctrl.selectedIndex,\n        totalWidth = elements.paging.offsetWidth,\n        tab        = elements.tabs[ index ],\n        left       = tab.offsetLeft,\n        right      = totalWidth - left - tab.offsetWidth;\n\n    if (ctrl.shouldCenterTabs) {\n      // We need to use the same calculate process as in the pagination wrapper, to avoid rounding\n      // deviations.\n      var totalWidthOfTabItems = calcTabsWidth(elements.tabs);\n\n      if (totalWidth > totalWidthOfTabItems &&\n          previousTotalWidth !== totalWidth &&\n          previousWidthOfTabItems !== totalWidthOfTabItems) {\n        $timeout(updateInkBarStyles, 0, true, totalWidth, totalWidthOfTabItems);\n      }\n    }\n    updateInkBarClassName();\n    angular.element(elements.inkBar).css({ left: left + 'px', right: right + 'px' });\n  }\n\n  /**\n   * Adds left/right classes so that the ink bar will animate properly.\n   */\n  function updateInkBarClassName () {\n    var elements = getElements();\n    var newIndex = ctrl.selectedIndex,\n        oldIndex = ctrl.lastSelectedIndex,\n        ink      = angular.element(elements.inkBar);\n    if (!angular.isNumber(oldIndex)) return;\n    ink\n        .toggleClass('md-left', newIndex < oldIndex)\n        .toggleClass('md-right', newIndex > oldIndex);\n  }\n\n  /**\n   * Takes an offset value and makes sure that it is within the min/max allowed values.\n   * @param {number} value\n   * @returns {number}\n   */\n  function fixOffset (value) {\n    var elements = getElements();\n\n    if (!elements.tabs.length || !ctrl.shouldPaginate) return 0;\n\n    var lastTab    = elements.tabs[ elements.tabs.length - 1 ],\n        totalWidth = lastTab.offsetLeft + lastTab.offsetWidth;\n\n    if (isRtl()) {\n      value = Math.min(elements.paging.offsetWidth - elements.canvas.clientWidth, value);\n      value = Math.max(0, value);\n    } else {\n      value = Math.max(0, value);\n      value = Math.min(totalWidth - elements.canvas.clientWidth, value);\n    }\n\n    return value;\n  }\n\n  /**\n   * Attaches a ripple to the tab item element.\n   * @param scope\n   * @param element\n   */\n  function attachRipple (scope, element) {\n    var elements = getElements();\n    var options = { colorElement: angular.element(elements.inkBar) };\n    $mdTabInkRipple.attach(scope, element, options);\n  }\n\n  /**\n   * Sets the `aria-controls` attribute to the elements that correspond to the passed-in tab.\n   * @param tab\n   */\n  function setAriaControls (tab) {\n    if (tab.hasContent) {\n      var nodes = $element[0].querySelectorAll('[md-tab-id=\"' + tab.id + '\"]');\n      angular.element(nodes).attr('aria-controls', ctrl.tabContentPrefix + tab.id);\n    }\n  }\n\n  function isRtl() {\n    return $mdUtil.isRtl($attrs);\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc directive\n * @name mdTabs\n * @module material.components.tabs\n *\n * @restrict E\n *\n * @description\n * The `<md-tabs>` directive serves as the container for 1..n\n * <a ng-href=\"api/directive/mdTab\">`<md-tab>`</a> child directives.\n * In turn, the nested `<md-tab>` directive is used to specify a tab label for the\n * **header button** and <i>optional</i> tab view content that will be associated with each tab\n * button.\n *\n * Below is the markup for its simplest usage:\n *\n *  <hljs lang=\"html\">\n *  <md-tabs>\n *    <md-tab label=\"Tab #1\"></md-tab>\n *    <md-tab label=\"Tab #2\"></md-tab>\n *    <md-tab label=\"Tab #3\"></md-tab>\n *  </md-tabs>\n *  </hljs>\n *\n * Tabs support three (3) usage scenarios:\n *\n *  1. Tabs (buttons only)\n *  2. Tabs with internal view content\n *  3. Tabs with external view content\n *\n * **Tabs-only** support is useful when tab buttons are used for custom navigation regardless of any\n * other components, content, or views.\n *\n * <blockquote><b>Note:</b> If you are using the Tabs component for page-level navigation, please\n * use the <a ng-href=\"./api/directive/mdNavBar\">NavBar component</a> instead. It handles this\n * case a more natively and more performantly.</blockquote>\n *\n * **Tabs with internal views** are the traditional usage where each tab has associated view\n * content and the view switching is managed internally by the Tabs component.\n *\n * **Tabs with external view content** is often useful when content associated with each tab is\n * independently managed and data-binding notifications announce tab selection changes.\n *\n * Additional features include:\n *\n * *  Content can include any markup.\n * *  If a tab is disabled while active/selected, then the next tab will be auto-selected.\n *\n * ### Theming\n *\n * By default, tabs use your app's accent color for the selected tab's text and ink bar.\n *\n * You can use the theming classes to change the color of the `md-tabs` background:\n * * Applying `class=\"md-primary\"` will use your app's primary color for the background, your\n *   accent color for the ink bar, and your primary palette's contrast color for the text of the\n *   selected tab.\n *   * When using the `md-primary` class, you can add the `md-no-ink-bar-color` class to make the\n *     ink bar use your theme's primary contrast color instead of the accent color.\n * * Applying `class=\"md-accent\"` will use your app's accent color for the background and your\n *   accent palette's contrast color for the text and ink bar of the selected tab.\n * * Applying `class=\"md-warn\"` will use your app's warn color for the background and your\n *   warn palette's contrast color for the text and ink bar of the selected tab.\n *\n * ### Explanation of tab stretching\n *\n * Initially, tabs will have an inherent size.  This size will either be defined by how much space\n * is needed to accommodate their text or set by the user through CSS.\n * Calculations will be based on this size.\n *\n * On mobile devices, tabs will be expanded to fill the available horizontal space.\n * When this happens, all tabs will become the same size.\n *\n * On desktops, by default, stretching will never occur.\n *\n * This default behavior can be overridden through the `md-stretch-tabs` attribute.\n * Here is a table showing when stretching will occur:\n *\n * `md-stretch-tabs` | mobile    | desktop\n * ------------------|-----------|--------\n * `auto`            | stretched | ---\n * `always`          | stretched | stretched\n * `never`           | ---       | ---\n *\n * @param {number=} md-selected Index of the active/selected tab.\n * @param {expression=} md-no-ink-bar If `true` or no value, disables the selection ink bar.\n * @param {string=} md-align-tabs Attribute to indicate position of tab buttons: `bottom` or `top`;\n *  Default is `top`.\n * @param {string=} md-stretch-tabs Attribute to indicate whether or not to stretch tabs: `auto`,\n *  `always`, or `never`; Default is `auto`.\n * @param {expression=} md-dynamic-height If `true` or no value, the tab wrapper will resize based\n *  on the contents of the selected tab.\n * @param {boolean=} md-border-bottom If the attribute is present, shows a solid `1px` border\n *  between the tabs and their content.\n * @param {boolean=} md-center-tabs If the attribute is present, tabs will be centered provided\n *  there is no need for pagination.\n * @param {boolean=} md-no-pagination If the attribute is present, pagination will remain off.\n * @param {expression=} md-swipe-content When enabled, swipe gestures will be enabled for the content\n *  area to allow swiping between tabs.\n * @param {boolean=} md-enable-disconnect When enabled, scopes will be disconnected for tabs that\n *  are not being displayed. This provides a performance boost, but may also cause unexpected\n *  issues. It is not recommended for most users.\n * @param {boolean=} md-autoselect If the attribute is present, any tabs added after the initial\n *  load will be automatically selected.\n * @param {boolean=} md-no-select-click When true, click events will not be fired when the value of\n *  `md-active` on an `md-tab` changes. This is useful when using tabs with UI-Router's child\n *  states, as triggering a click event in that case can cause an extra tab change to occur.\n * @param {string=} md-navigation-hint Attribute to override the default `tablist` navigation hint\n *  that screen readers will announce to provide instructions for navigating between tabs. This is\n *  desirable when you want the hint to be in a different language. Default is \"Use the left and\n *  right arrow keys to navigate between tabs\".\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-tabs md-selected=\"selectedIndex\">\n *   <img ng-src=\"img/angular.png\" class=\"centered\" alt=\"Angular icon\">\n *   <md-tab\n *       ng-repeat=\"tab in tabs | orderBy:predicate:reversed\"\n *       md-on-select=\"onTabSelected(tab)\"\n *       md-on-deselect=\"announceDeselected(tab)\"\n *       ng-disabled=\"tab.disabled\">\n *     <md-tab-label>\n *       {{tab.title}}\n *       <img src=\"img/removeTab.png\" ng-click=\"removeTab(tab)\" class=\"delete\" alt=\"Remove tab\">\n *     </md-tab-label>\n *     <md-tab-body>\n *       {{tab.content}}\n *     </md-tab-body>\n *   </md-tab>\n * </md-tabs>\n * </hljs>\n *\n */\nMdTabs.$inject = [\"$$mdSvgRegistry\"];\nangular\n    .module('material.components.tabs')\n    .directive('mdTabs', MdTabs);\n\nfunction MdTabs ($$mdSvgRegistry) {\n  return {\n    scope:            {\n      navigationHint: '@?mdNavigationHint',\n      selectedIndex: '=?mdSelected'\n    },\n    template:         function (element, attr) {\n      attr.$mdTabsTemplate = element.html();\n      return '' +\n        '<md-tabs-wrapper> ' +\n          '<md-tab-data></md-tab-data> ' +\n          '<md-prev-button ' +\n              'tabindex=\"-1\" ' +\n              'role=\"button\" ' +\n              'aria-label=\"Previous Page\" ' +\n              'aria-disabled=\"{{!$mdTabsCtrl.canPageBack()}}\" ' +\n              'ng-class=\"{ \\'md-disabled\\': !$mdTabsCtrl.canPageBack() }\" ' +\n              'ng-if=\"$mdTabsCtrl.shouldPaginate\" ' +\n              'ng-click=\"$mdTabsCtrl.previousPage()\"> ' +\n            '<md-icon md-svg-src=\"'+ $$mdSvgRegistry.mdTabsArrow +'\"></md-icon> ' +\n          '</md-prev-button> ' +\n          '<md-next-button ' +\n              'tabindex=\"-1\" ' +\n              'role=\"button\" ' +\n              'aria-label=\"Next Page\" ' +\n              'aria-disabled=\"{{!$mdTabsCtrl.canPageForward()}}\" ' +\n              'ng-class=\"{ \\'md-disabled\\': !$mdTabsCtrl.canPageForward() }\" ' +\n              'ng-if=\"$mdTabsCtrl.shouldPaginate\" ' +\n              'ng-click=\"$mdTabsCtrl.nextPage()\"> ' +\n            '<md-icon md-svg-src=\"'+ $$mdSvgRegistry.mdTabsArrow +'\"></md-icon> ' +\n          '</md-next-button> ' +\n          '<md-tabs-canvas ' +\n              'tabindex=\"{{ $mdTabsCtrl.hasFocus ? -1 : 0 }}\" ' +\n              'ng-focus=\"$mdTabsCtrl.redirectFocus()\" ' +\n              'ng-class=\"{ ' +\n                  '\\'md-paginated\\': $mdTabsCtrl.shouldPaginate, ' +\n                  '\\'md-center-tabs\\': $mdTabsCtrl.shouldCenterTabs ' +\n              '}\" ' +\n              'ng-keydown=\"$mdTabsCtrl.keydown($event)\"> ' +\n            '<md-pagination-wrapper ' +\n                'ng-class=\"{ \\'md-center-tabs\\': $mdTabsCtrl.shouldCenterTabs }\" ' +\n                'md-tab-scroll=\"$mdTabsCtrl.scroll($event)\" ' +\n                'role=\"tablist\" ' +\n                'aria-label=\"{{::$mdTabsCtrl.navigationHint}}\">' +\n              '<md-tab-item ' +\n                  'tabindex=\"{{ tab.isActive() ? 0 : -1 }}\" ' +\n                  'class=\"md-tab {{::tab.scope.tabClass}}\" ' +\n                  'ng-repeat=\"tab in $mdTabsCtrl.tabs\" ' +\n                  'role=\"tab\" ' +\n                  'id=\"tab-item-{{::tab.id}}\" ' +\n                  'md-tab-id=\"{{::tab.id}}\" ' +\n                  'aria-selected=\"{{tab.isActive()}}\" ' +\n                  'aria-disabled=\"{{tab.scope.disabled || \\'false\\'}}\" ' +\n                  'ng-click=\"$mdTabsCtrl.select(tab.getIndex())\" ' +\n                  'ng-focus=\"$mdTabsCtrl.hasFocus = true\" ' +\n                  'ng-blur=\"$mdTabsCtrl.hasFocus = false\" ' +\n                  'ng-class=\"{ ' +\n                      '\\'md-active\\':    tab.isActive(), ' +\n                      '\\'md-focused\\':   tab.hasFocus(), ' +\n                      '\\'md-disabled\\':  tab.scope.disabled ' +\n                  '}\" ' +\n                  'ng-disabled=\"tab.scope.disabled\" ' +\n                  'md-swipe-left=\"$mdTabsCtrl.nextPage()\" ' +\n                  'md-swipe-right=\"$mdTabsCtrl.previousPage()\" ' +\n                  'md-tabs-template=\"::tab.label\" ' +\n                  'md-scope=\"::tab.parent\"></md-tab-item> ' +\n              '<md-ink-bar></md-ink-bar> ' +\n            '</md-pagination-wrapper> ' +\n            '<md-tabs-dummy-wrapper aria-hidden=\"true\" class=\"md-visually-hidden md-dummy-wrapper\"> ' +\n              '<md-dummy-tab ' +\n                  'class=\"md-tab\" ' +\n                  'tabindex=\"-1\" ' +\n                  'ng-focus=\"$mdTabsCtrl.hasFocus = true\" ' +\n                  'ng-blur=\"$mdTabsCtrl.hasFocus = false\" ' +\n                  'ng-repeat=\"tab in $mdTabsCtrl.tabs\" ' +\n                  'md-tabs-template=\"::tab.label\" ' +\n                  'md-scope=\"::tab.parent\"></md-dummy-tab> ' +\n            '</md-tabs-dummy-wrapper> ' +\n          '</md-tabs-canvas> ' +\n        '</md-tabs-wrapper> ' +\n        '<md-tabs-content-wrapper ng-show=\"$mdTabsCtrl.hasContent && $mdTabsCtrl.selectedIndex >= 0\" class=\"_md\"> ' +\n          '<md-tab-content ' +\n              'id=\"{{:: $mdTabsCtrl.tabContentPrefix + tab.id}}\" ' +\n              'class=\"_md\" ' +\n              'role=\"tabpanel\" ' +\n              'aria-labelledby=\"tab-item-{{::tab.id}}\" ' +\n              'md-swipe-left=\"$mdTabsCtrl.swipeContent && $mdTabsCtrl.incrementIndex(1)\" ' +\n              'md-swipe-right=\"$mdTabsCtrl.swipeContent && $mdTabsCtrl.incrementIndex(-1)\" ' +\n              'ng-if=\"tab.hasContent\" ' +\n              'ng-repeat=\"(index, tab) in $mdTabsCtrl.tabs\" ' +\n              'ng-class=\"{ ' +\n                '\\'md-no-transition\\': $mdTabsCtrl.lastSelectedIndex == null, ' +\n                '\\'md-active\\':        tab.isActive(), ' +\n                '\\'md-left\\':          tab.isLeft(), ' +\n                '\\'md-right\\':         tab.isRight(), ' +\n                '\\'md-no-scroll\\':     $mdTabsCtrl.dynamicHeight ' +\n              '}\"> ' +\n            '<div ' +\n                'md-tabs-template=\"::tab.template\" ' +\n                'md-connected-if=\"tab.isActive()\" ' +\n                'md-scope=\"::tab.parent\" ' +\n                'ng-if=\"$mdTabsCtrl.enableDisconnect || tab.shouldRender()\"></div> ' +\n          '</md-tab-content> ' +\n        '</md-tabs-content-wrapper>';\n    },\n    controller:       'MdTabsController',\n    controllerAs:     '$mdTabsCtrl',\n    bindToController: true\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMdTabsDummyWrapper.$inject = [\"$mdUtil\", \"$window\"];angular\n  .module('material.components.tabs')\n  .directive('mdTabsDummyWrapper', MdTabsDummyWrapper);\n\n/**\n * @private\n *\n * @param $mdUtil\n * @param $window\n * @returns {{require: string, link: link}}\n * @constructor\n *\n * @ngInject\n */\nfunction MdTabsDummyWrapper ($mdUtil, $window) {\n  return {\n    require: '^?mdTabs',\n    link:    function link (scope, element, attr, ctrl) {\n      if (!ctrl) return;\n\n      var observer;\n      var disconnect;\n\n      var mutationCallback = function() {\n        ctrl.updatePagination();\n        ctrl.updateInkBarStyles();\n      };\n\n      if ('MutationObserver' in $window) {\n        var config = {\n          childList: true,\n          subtree: true,\n          // Per https://bugzilla.mozilla.org/show_bug.cgi?id=1138368, browsers will not fire\n          // the childList mutation, once a <span> element's innerText changes.\n          // The characterData of the <span> element will change.\n          characterData: true\n        };\n\n        observer = new MutationObserver(mutationCallback);\n        observer.observe(element[0], config);\n        disconnect = observer.disconnect.bind(observer);\n      } else {\n        var debounced = $mdUtil.debounce(mutationCallback, 15, null, false);\n\n        element.on('DOMSubtreeModified', debounced);\n        disconnect = element.off.bind(element, 'DOMSubtreeModified', debounced);\n      }\n\n      // Disconnect the observer\n      scope.$on('$destroy', function() {\n        disconnect();\n      });\n    }\n  };\n}\n\n})();\n(function(){\n\"use strict\";\n\n\nMdTabsTemplate.$inject = [\"$compile\", \"$mdUtil\"];angular\n    .module('material.components.tabs')\n    .directive('mdTabsTemplate', MdTabsTemplate);\n\nfunction MdTabsTemplate ($compile, $mdUtil) {\n  return {\n    restrict: 'A',\n    link:     link,\n    scope:    {\n      template:     '=mdTabsTemplate',\n      connected:    '=?mdConnectedIf',\n      compileScope: '=mdScope'\n    },\n    require:  '^?mdTabs'\n  };\n  function link (scope, element, attr, ctrl) {\n    if (!ctrl) return;\n\n    var compileScope = ctrl.enableDisconnect ? scope.compileScope.$new() : scope.compileScope;\n\n    element.html(scope.template);\n    $compile(element.contents())(compileScope);\n\n    return $mdUtil.nextTick(handleScope);\n\n    function handleScope () {\n      scope.$watch('connected', function (value) { value === false ? disconnect() : reconnect(); });\n      scope.$on('$destroy', reconnect);\n    }\n\n    function disconnect () {\n      if (ctrl.enableDisconnect) $mdUtil.disconnectScope(compileScope);\n    }\n\n    function reconnect () {\n      if (ctrl.enableDisconnect) $mdUtil.reconnectScope(compileScope);\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.toast\n * @description\n * Toast and Snackbar component.\n */\nMdToastDirective.$inject = [\"$mdToast\"];\nMdToastProvider.$inject = [\"$$interimElementProvider\"];\nangular.module('material.components.toast', [\n  'material.core',\n  'material.components.button'\n])\n  .directive('mdToast', MdToastDirective)\n  .provider('$mdToast', MdToastProvider);\n\n/* @ngInject */\nfunction MdToastDirective($mdToast) {\n  return {\n    restrict: 'E',\n    link: function postLink(scope, element) {\n      element.addClass('_md');     // private md component indicator for styling\n\n      // When navigation force destroys an interimElement, then\n      // listen and $destroy() that interim instance...\n      scope.$on('$destroy', function() {\n        $mdToast.destroy();\n      });\n    }\n  };\n}\n\n/**\n * @ngdoc service\n * @name $mdToast\n * @module material.components.toast\n *\n * @description\n * `$mdToast` is a service to build a toast notification on any position\n * on the screen with an optional duration, and provides a simple promise API.\n *\n * The toast will be always positioned at the `bottom`, when the screen size is\n * between `600px` and `959px` (`sm` breakpoint)\n *\n * ## Restrictions on custom toasts\n * - The toast's template must have an outer `<md-toast>` element.\n * - For a toast action, use element with class `md-action`.\n * - Add the class `md-capsule` for curved corners.\n *\n * ### Custom Presets\n * Developers are also able to create their own preset, which can be easily used without repeating\n * their options each time.\n *\n * <hljs lang=\"js\">\n *   $mdToastProvider.addPreset('testPreset', {\n *     options: function() {\n *       return {\n *         template:\n *           '<md-toast>' +\n *             '<div class=\"md-toast-content\">' +\n *               'This is a custom preset' +\n *             '</div>' +\n *           '</md-toast>',\n *         controllerAs: 'toast',\n *         bindToController: true\n *       };\n *     }\n *   });\n * </hljs>\n *\n * After you created your preset at config phase, you can easily access it.\n *\n * <hljs lang=\"js\">\n *   $mdToast.show(\n *     $mdToast.testPreset()\n *   );\n * </hljs>\n *\n * ## Parent container notes\n *\n * The toast is positioned using absolute positioning relative to its first non-static parent\n * container. Thus, if the requested parent container uses static positioning, we will temporarily\n * set its positioning to `relative` while the toast is visible and reset it when the toast is\n * hidden.\n *\n * Because of this, it is usually best to ensure that the parent container has a fixed height and\n * prevents scrolling by setting the `overflow: hidden;` style. Since the position is based off of\n * the parent's height, the toast may be mispositioned if you allow the parent to scroll.\n *\n * You can, however, have a scrollable element inside of the container; just make sure the\n * container itself does not scroll.\n *\n * <hljs lang=\"html\">\n * <div layout-fill id=\"toast-container\">\n *   <md-content>\n *     I can have lots of content and scroll!\n *   </md-content>\n * </div>\n * </hljs>\n *\n * @usage\n * <hljs lang=\"html\">\n * <div ng-controller=\"MyController\">\n *   <md-button ng-click=\"openToast()\">\n *     Open a Toast!\n *   </md-button>\n * </div>\n * </hljs>\n *\n * <hljs lang=\"js\">\n * var app = angular.module('app', ['ngMaterial']);\n * app.controller('MyController', function($scope, $mdToast) {\n *   $scope.openToast = function($event) {\n *     $mdToast.show($mdToast.simple().textContent('Hello!'));\n *     // Could also do $mdToast.showSimple('Hello');\n *   };\n * });\n * </hljs>\n */\n\n/**\n * @ngdoc method\n * @name $mdToast#showSimple\n *\n * @param {string} message The message to display inside the toast\n * @description\n * Convenience method which builds and shows a simple toast.\n *\n * @returns {promise} A promise that can be resolved with `$mdToast.hide()`.\n */\n\n/**\n * @ngdoc method\n * @name $mdToast#simple\n *\n * @description\n * Builds a preconfigured toast.\n *\n * @returns {obj} a `$mdToastPreset` with the following chainable configuration methods.\n *\n * _**Note:** These configuration methods are provided in addition to the methods provided by\n * the `build()` and `show()` methods below._\n *\n * <table class=\"md-api-table methods\">\n *    <thead>\n *      <tr>\n *        <th>Method</th>\n *        <th>Description</th>\n *      </tr>\n *    </thead>\n *    <tbody>\n *      <tr>\n *        <td>`.textContent(string)`</td>\n *        <td>Sets the toast content to the specified string</td>\n *      </tr>\n *      <tr>\n *        <td>`.action(string)`</td>\n *        <td>\n *          Adds an action button. <br/>\n *          If clicked, the promise (returned from `show()`) will resolve with the value `'ok'`;\n *          otherwise, it is resolved with `true` after a `hideDelay` timeout.\n *        </td>\n *      </tr>\n *      <tr>\n *        <td>`.actionKey(string)`</td>\n *        <td>\n *          Adds a hotkey for the action button to the page. <br/>\n *          If the `actionKey` and `Control` key are pressed, the toast's action will be triggered.\n *        </td>\n *      </tr>\n *      <tr>\n *        <td>`.actionHint(string)`</td>\n *        <td>\n *          Text that a screen reader will announce to let the user know how to activate the\n *          action. <br>\n *          If an `actionKey` is defined, this defaults to:\n *          'Press Control-\"`actionKey`\" to ' followed by the `action`.\n *        </td>\n *      </tr>\n *      <tr>\n *        <td>`.dismissHint(string)`</td>\n *        <td>\n *          Text that a screen reader will announce to let the user know how to dismiss the toast.\n *          <br>Defaults to: \"Press Escape to dismiss.\"\n *        </td>\n *      </tr>\n *      <tr>\n *        <td>`.highlightAction(boolean)`</td>\n *        <td>\n *          Whether or not the action button will have an additional highlight class.<br/>\n *          By default the `accent` color will be applied to the action button.\n *        </td>\n *      </tr>\n *      <tr>\n *        <td>`.highlightClass(string)`</td>\n *        <td>\n *          If set, the given class will be applied to the highlighted action button.<br/>\n *          This allows you to specify the highlight color easily. Highlight classes are\n *          `md-primary`, `md-warn`, and `md-accent`\n *        </td>\n *      </tr>\n *      <tr>\n *        <td>`.capsule(boolean)`</td>\n *        <td>\n *          Whether or not to add the `md-capsule` class to the toast to provide rounded corners\n *        </td>\n *      </tr>\n *      <tr>\n *        <td>`.theme(string)`</td>\n *        <td>\n *          Sets the theme on the toast to the requested theme. Default is `$mdThemingProvider`'s\n *          default.\n *        </td>\n *      </tr>\n *      <tr>\n *        <td>`.toastClass(string)`</td>\n *        <td>Sets a class on the toast element</td>\n *      </tr>\n *    </tbody>\n * </table>\n */\n\n/**\n * @ngdoc method\n * @name $mdToast#updateTextContent\n *\n * @description\n * Updates the content of an existing toast. Useful for updating things like counts, etc.\n */\n\n/**\n * @ngdoc method\n * @name $mdToast#build\n *\n * @description\n * Creates a custom `$mdToastPreset` that you can configure.\n *\n * @returns {obj} a `$mdToastPreset` with the chainable configuration methods for shows' options\n *   (see below).\n */\n\n/**\n * @ngdoc method\n * @name $mdToast#show\n *\n * @description Shows the toast.\n *\n * @param {Object} optionsOrPreset Either provide an `$mdToastPreset` returned from `simple()`\n * and `build()`, or an options object with the following properties:\n *\n *   - `templateUrl` - `{string=}`: The url of an html template file that will\n *     be used as the content of the toast. Restrictions: the template must\n *     have an outer `md-toast` element.\n *   - `template` - `{string=}`: Same as templateUrl, except this is an actual\n *     template string.\n *   - `autoWrap` - `{boolean=}`: Whether or not to automatically wrap the template content with a\n *     `<div class=\"md-toast-content\">` if one is not provided. Defaults to true. Can be disabled\n *     if you provide a custom toast directive.\n *   - `scope` - `{Object=}`: the scope to link the template / controller to. If none is specified,\n *     it will create a new child scope. This scope will be destroyed when the toast is removed\n *     unless `preserveScope` is set to true.\n *   - `preserveScope` - `{boolean=}`: whether to preserve the scope when the element is removed.\n *     Default is false\n *   - `hideDelay` - `{number=}`: The number of milliseconds the toast should stay active before\n *     automatically closing. Set to `0` or `false` to have the toast stay open until closed\n *     manually via an action in the toast, a hotkey, or a swipe gesture. For accessibility, toasts\n *     should not automatically close when they contain an action.<br>\n *     Defaults to: `3000`.\n *   - `position` - `{string=}`: Sets the position of the toast. <br/>\n *     Available: any combination of `'bottom'`, `'left'`, `'top'`, `'right'`, `'end'`, and\n *     `'start'`. The properties `'end'` and `'start'` are dynamic and can be used for RTL support.\n *     <br/>\n *     Default combination: `'bottom left'`.\n *   - `toastClass` - `{string=}`: A class to set on the toast element.\n *   - `controller` - `{string=}`: The controller to associate with this toast.\n *     The controller will be injected the local `$mdToast.hide()`, which is a function\n *     used to hide the toast.\n *   - `locals` - `{Object=}`: An object containing key/value pairs. The keys will be used as names\n *     of values to inject into the controller. For example, `locals: {three: 3}` would inject\n *     `three` into the controller with the value of 3.\n *   - `bindToController` - `{boolean=}`: bind the locals to the controller, instead of passing\n *     them in.\n *   - `resolve` - `{Object=}`: Similar to locals, except it takes promises as values\n *     and the toast will not open until the promises resolve.\n *   - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.\n *   - `parent` - `{element=}`: The element to append the toast to. Defaults to appending\n *     to the root element of the application.\n *\n * @returns {promise} A promise that can be resolved with `$mdToast.hide()`. `$mdToast.hide()` will\n * resolve either with the boolean value `true` or the value passed as an argument to\n * `$mdToast.hide()`.\n */\n\n/**\n * @ngdoc method\n * @name $mdToast#hide\n *\n * @description\n * Hide an existing toast and resolve the promise returned from `$mdToast.show()`.\n *\n * @param {*=} response An argument for the resolved promise.\n *\n * @returns {promise} A promise that is called when the existing element is removed from the DOM.\n * The promise is resolved with either the Boolean value `true` or the value passed as the\n * argument to `$mdToast.hide()`.\n */\n\nfunction MdToastProvider($$interimElementProvider) {\n  // Differentiate promise resolves: hide timeout (value == true) and hide action clicks\n  // (value == ok).\n  MdToastController.$inject = [\"$mdToast\", \"$scope\", \"$log\"];\n  toastDefaultOptions.$inject = [\"$animate\", \"$mdToast\", \"$mdUtil\", \"$mdMedia\", \"$document\", \"$q\"];\n  var ACTION_RESOLVE = 'ok';\n\n  var activeToastContent;\n  var $mdToast = $$interimElementProvider('$mdToast')\n    .setDefaults({\n      methods: ['position', 'hideDelay', 'capsule', 'parent', 'position', 'toastClass'],\n      options: toastDefaultOptions\n    })\n    .addPreset('simple', {\n      argOption: 'textContent',\n      methods: ['textContent', 'action', 'actionKey', 'actionHint', 'highlightAction',\n                'highlightClass', 'theme', 'parent', 'dismissHint'],\n      options: /* @ngInject */ [\"$mdToast\", \"$mdTheming\", function($mdToast, $mdTheming) {\n        return {\n          template:\n            '<md-toast md-theme=\"{{ toast.theme }}\" ng-class=\"{\\'md-capsule\\': toast.capsule}\">' +\n            '  <div class=\"md-toast-content\" aria-live=\"polite\" aria-relevant=\"all\">' +\n            '    <span class=\"md-toast-text\">' +\n            '      {{ toast.content }}' +\n            '    </span>' +\n            '    <span class=\"md-visually-hidden\">{{ toast.dismissHint }}</span>' +\n            '    <span class=\"md-visually-hidden\" ng-if=\"toast.action && toast.actionKey\">' +\n            '      {{ toast.actionHint }}' +\n            '    </span>' +\n            '    <md-button class=\"md-action\" ng-if=\"toast.action\" ng-click=\"toast.resolve()\" ' +\n            '               ng-class=\"highlightClasses\">' +\n            '      {{ toast.action }}' +\n            '    </md-button>' +\n            '  </div>' +\n            '</md-toast>',\n          controller: MdToastController,\n          theme: $mdTheming.defaultTheme(),\n          controllerAs: 'toast',\n          bindToController: true\n        };\n      }]\n    })\n    .addMethod('updateTextContent', updateTextContent);\n\n    function updateTextContent(newContent) {\n      activeToastContent = newContent;\n    }\n\n    return $mdToast;\n\n  /**\n   * Controller for the Toast interim elements.\n   * @ngInject\n   */\n  function MdToastController($mdToast, $scope, $log) {\n    // For compatibility with AngularJS 1.6+, we should always use the $onInit hook in\n    // interimElements. The $mdCompiler simulates the $onInit hook for all versions.\n    this.$onInit = function() {\n      var self = this;\n\n      if (self.highlightAction) {\n        $scope.highlightClasses = [\n          'md-highlight',\n          self.highlightClass\n        ];\n      }\n\n      // If an action is defined and no actionKey is specified, then log a warning.\n      if (self.action && !self.actionKey) {\n        $log.warn('Toasts with actions should define an actionKey for accessibility.',\n          'Details: https://material.angularjs.org/latest/api/service/$mdToast#mdtoast-simple');\n      }\n\n      if (self.actionKey && !self.actionHint) {\n        self.actionHint = 'Press Control-\"' + self.actionKey + '\" to ';\n      }\n\n      if (!self.dismissHint) {\n        self.dismissHint = 'Press Escape to dismiss.';\n      }\n\n      $scope.$watch(function() { return activeToastContent; }, function() {\n        self.content = activeToastContent;\n      });\n\n      this.resolve = function() {\n        $mdToast.hide(ACTION_RESOLVE);\n      };\n    };\n  }\n\n  /* @ngInject */\n  function toastDefaultOptions($animate, $mdToast, $mdUtil, $mdMedia, $document, $q) {\n    var SWIPE_EVENTS = '$md.swipeleft $md.swiperight $md.swipeup $md.swipedown';\n    return {\n      onShow: onShow,\n      onRemove: onRemove,\n      toastClass: '',\n      position: 'bottom left',\n      themable: true,\n      hideDelay: 3000,\n      autoWrap: true,\n      transformTemplate: function(template, options) {\n        var shouldAddWrapper = options.autoWrap && template && !/md-toast-content/g.test(template);\n\n        if (shouldAddWrapper) {\n          // Root element of template will be <md-toast>. We need to wrap all of its content inside\n          // of <div class=\"md-toast-content\">. All templates provided here should be static,\n          // developer-controlled content (meaning we're not attempting to guard against XSS).\n          var templateRoot = document.createElement('md-template');\n          templateRoot.innerHTML = template;\n\n          // Iterate through all root children, to detect possible md-toast directives.\n          for (var i = 0; i < templateRoot.children.length; i++) {\n            if (templateRoot.children[i].nodeName === 'MD-TOAST') {\n              var wrapper = angular.element('<div class=\"md-toast-content\">');\n\n              // Wrap the children of the `md-toast` directive in jqLite, to be able to append\n              // multiple nodes with the same execution.\n              wrapper.append(angular.element(templateRoot.children[i].childNodes));\n\n              // Append the new wrapped element to the `md-toast` directive.\n              templateRoot.children[i].appendChild(wrapper[0]);\n            }\n          }\n\n          // We have to return the innerHTML, because we do not want to have the `md-template`\n          // element to be the root element of our interimElement.\n          return templateRoot.innerHTML;\n        }\n\n        return template || '';\n      }\n    };\n\n    /**\n     * @param {{toast: {actionKey: string=}}=} scope\n     * @param {JQLite} element\n     * @param {Object.<string, string>} options\n     * @return {*}\n     */\n    function onShow(scope, element, options) {\n      activeToastContent = options.textContent;\n\n      var isSmScreen = !$mdMedia('gt-sm');\n\n      element = $mdUtil.extractElementByName(element, 'md-toast', true);\n      options.element = element;\n\n      options.onSwipe = function(ev) {\n        // Add the relevant swipe class to the element so it can animate correctly\n        var swipe = ev.type.replace('$md.','');\n        var direction = swipe.replace('swipe', '');\n\n        // If the swipe direction is down/up but the toast came from top/bottom don't fade away\n        // Unless the screen is small, then the toast always on bottom\n        if ((direction === 'down' && options.position.indexOf('top') !== -1 && !isSmScreen) ||\n            (direction === 'up' && (options.position.indexOf('bottom') !== -1 || isSmScreen))) {\n          return;\n        }\n\n        if ((direction === 'left' || direction === 'right') && isSmScreen) {\n          return;\n        }\n\n        element.addClass('md-' + swipe);\n        $mdUtil.nextTick($mdToast.cancel);\n      };\n      options.openClass = toastOpenClass(options.position);\n\n      element.addClass(options.toastClass);\n\n      // 'top left' -> 'md-top md-left'\n      options.parent.addClass(options.openClass);\n\n      // static is the default position\n      if ($mdUtil.hasComputedStyle(options.parent, 'position', 'static')) {\n        options.parent.css('position', 'relative');\n      }\n\n      setupActionKeyListener(scope.toast && scope.toast.actionKey ?\n        scope.toast.actionKey : undefined);\n\n      element.on(SWIPE_EVENTS, options.onSwipe);\n\n      var verticalPositionDefined = false;\n      var positionClasses = options.position.split(' ').map(function (position) {\n        if (position) {\n          var className = 'md-' + position;\n          if (className === 'md-top' || className === 'md-bottom') {\n            verticalPositionDefined = true;\n          }\n          return className;\n        }\n        return 'md-bottom';\n      });\n      // If only \"right\" or \"left\" are defined, default to a vertical position of \"bottom\"\n      // as documented.\n      if (!verticalPositionDefined) {\n        positionClasses.push('md-bottom');\n      }\n      element.addClass(isSmScreen ? 'md-bottom' : positionClasses.join(' '));\n\n      if (options.parent) {\n        options.parent.addClass('md-toast-animating');\n      }\n      return $animate.enter(element, options.parent).then(function() {\n        if (options.parent) {\n          options.parent.removeClass('md-toast-animating');\n        }\n      });\n    }\n\n    /**\n     * @param {Object} scope the toast's scope\n     * @param {JQLite} element the toast to be removed\n     * @param {Object} options\n     * @return {Promise<*>} a Promise to remove the element immediately or to animate it out.\n     */\n    function onRemove(scope, element, options) {\n      if (scope.toast && scope.toast.actionKey) {\n        removeActionKeyListener();\n      }\n      element.off(SWIPE_EVENTS, options.onSwipe);\n      if (options.parent) options.parent.addClass('md-toast-animating');\n      if (options.openClass) options.parent.removeClass(options.openClass);\n\n      // Don't run the leave animation if the element has already been destroyed.\n      return ((options.$destroy === true) ? $q.when(element.remove()) : $animate.leave(element))\n        .then(function () {\n          if (options.parent) options.parent.removeClass('md-toast-animating');\n          if ($mdUtil.hasComputedStyle(options.parent, 'position', 'static')) {\n            options.parent.css('position', '');\n          }\n        });\n    }\n\n    function toastOpenClass(position) {\n      // For mobile, always open full-width on bottom\n      if (!$mdMedia('gt-xs')) {\n        return 'md-toast-open-bottom';\n      }\n\n      return 'md-toast-open-' + (position.indexOf('top') > -1 ? 'top' : 'bottom');\n    }\n\n    /**\n     * @param {string} actionKey\n     */\n    function setupActionKeyListener(actionKey) {\n      /**\n       * @param {KeyboardEvent} event\n       */\n      var handleKeyDown = function(event) {\n        if (event.key === 'Escape') {\n          $mdToast.hide(false);\n        }\n        if (actionKey && event.key === actionKey && event.ctrlKey) {\n          $mdToast.hide(ACTION_RESOLVE);\n        }\n      };\n      $document.on('keydown', handleKeyDown);\n    }\n\n    function removeActionKeyListener() {\n      $document.off('keydown');\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.toolbar\n */\nmdToolbarDirective.$inject = [\"$$rAF\", \"$mdConstant\", \"$mdUtil\", \"$mdTheming\", \"$animate\", \"$timeout\"];\nangular.module('material.components.toolbar', [\n  'material.core',\n  'material.components.content'\n])\n  .directive('mdToolbar', mdToolbarDirective);\n\n/**\n * @ngdoc directive\n * @name mdToolbar\n * @module material.components.toolbar\n * @restrict E\n * @description\n * `md-toolbar` is used to place a toolbar in your app.\n *\n * Toolbars are usually used above a content area to display the title of the\n * current page, and show relevant action buttons for that page.\n *\n * You can change the height of the toolbar by adding either the\n * `md-medium-tall` or `md-tall` class to the toolbar.\n *\n * @usage\n * <hljs lang=\"html\">\n * <div layout=\"column\" layout-fill>\n *   <md-toolbar>\n *\n *     <div class=\"md-toolbar-tools\">\n *       <h2 md-truncate flex>My App's Title</h2>\n *\n *       <md-button>\n *         Right Bar Button\n *       </md-button>\n *     </div>\n *\n *   </md-toolbar>\n *   <md-content>\n *     Hello!\n *   </md-content>\n * </div>\n * </hljs>\n *\n * <i><b>Note:</b> The code above shows usage with the `md-truncate` component which provides an\n * ellipsis if the title is longer than the width of the Toolbar.</i>\n *\n * ## CSS & Styles\n *\n * The `<md-toolbar>` provides a few custom CSS classes that you may use to enhance the\n * functionality of your toolbar.\n *\n * <div>\n * <docs-css-api-table>\n *\n *   <docs-css-selector code=\"md-toolbar .md-toolbar-tools\">\n *     The `md-toolbar-tools` class provides quite a bit of automatic styling for your toolbar\n *     buttons and text. When applied, it will center the buttons and text vertically for you.\n *   </docs-css-selector>\n *\n * </docs-css-api-table>\n * </div>\n *\n * ### Private Classes\n *\n * Currently, the only private class is the `md-toolbar-transitions` class. All other classes are\n * considered public.\n *\n * @param {boolean=} md-scroll-shrink Whether the header should shrink away as\n * the user scrolls down, and reveal itself as the user scrolls up.\n *\n * _**Note (1):** for scrollShrink to work, the toolbar must be a sibling of a\n * `md-content` element, placed before it. See the scroll shrink demo._\n *\n * _**Note (2):** The `md-scroll-shrink` attribute is only parsed on component\n * initialization, it does not watch for scope changes._\n *\n *\n * @param {number=} md-shrink-speed-factor How much to change the speed of the toolbar's\n * shrinking by. For example, if 0.25 is given then the toolbar will shrink\n * at one fourth the rate at which the user scrolls down. Default 0.5.\n *\n */\n\nfunction mdToolbarDirective($$rAF, $mdConstant, $mdUtil, $mdTheming, $animate, $timeout) {\n  var translateY = angular.bind(null, $mdUtil.supplant, 'translate3d(0,{0}px,0)');\n\n  return {\n    template: '',\n    restrict: 'E',\n\n    link: function(scope, element, attr) {\n\n      element.addClass('_md');     // private md component indicator for styling\n      $mdTheming(element);\n\n      $mdUtil.nextTick(function () {\n        element.addClass('_md-toolbar-transitions');     // adding toolbar transitions after digest\n      }, false);\n\n      if (angular.isDefined(attr.mdScrollShrink)) {\n        setupScrollShrink();\n      }\n\n      function setupScrollShrink() {\n\n        var toolbarHeight;\n        var contentElement;\n        var disableScrollShrink = angular.noop;\n\n        // Current \"y\" position of scroll\n        // Store the last scroll top position\n        var y = 0;\n        var prevScrollTop = 0;\n        var shrinkSpeedFactor = attr.mdShrinkSpeedFactor || 0.5;\n\n        var debouncedContentScroll = $$rAF.throttle(onContentScroll);\n        var debouncedUpdateHeight = $mdUtil.debounce(updateToolbarHeight, 5 * 1000);\n\n        // Wait for $mdContentLoaded event from mdContent directive.\n        // If the mdContent element is a sibling of our toolbar, hook it up\n        // to scroll events.\n\n        scope.$on('$mdContentLoaded', onMdContentLoad);\n\n        // If the toolbar is used inside an ng-if statement, we may miss the\n        // $mdContentLoaded event, so we attempt to fake it if we have a\n        // md-content close enough.\n\n        attr.$observe('mdScrollShrink', onChangeScrollShrink);\n\n        // If the toolbar has ngShow or ngHide we need to update height immediately as it changed\n        // and not wait for $mdUtil.debounce to happen\n\n        if (attr.ngShow) { scope.$watch(attr.ngShow, updateToolbarHeight); }\n        if (attr.ngHide) { scope.$watch(attr.ngHide, updateToolbarHeight); }\n\n        // If the scope is destroyed (which could happen with ng-if), make sure\n        // to disable scroll shrinking again\n\n        scope.$on('$destroy', disableScrollShrink);\n\n        /**\n         * @param {string} shrinkWithScroll value of md-scroll-shrink attribute\n         */\n        function onChangeScrollShrink(shrinkWithScroll) {\n          var closestContent = $mdUtil.getSiblings(element, 'md-content');\n\n          // If there are content elements, fake the call using the first content element.\n          // This might still fail if the content element isn't a sibling of the toolbar.\n          if (!contentElement && closestContent.length) {\n            onMdContentLoad(null, closestContent[0]);\n          }\n\n          // Evaluate the expression\n          shrinkWithScroll = scope.$eval(shrinkWithScroll);\n\n          // Disable only if the attribute's expression evaluates to false\n          if (shrinkWithScroll === false) {\n            disableScrollShrink();\n          } else {\n            disableScrollShrink = enableScrollShrink();\n          }\n        }\n\n        /**\n         * @param {null} $event $mdContentLoaded always has a null event\n         * @param {JQLite} newContentEl JQLite object containing an md-content\n         */\n        function onMdContentLoad($event, newContentEl) {\n          // Toolbar and content must be siblings\n          if (newContentEl && element.parent()[0] === newContentEl.parent()[0]) {\n            // unhook old content event listener if exists\n            if (contentElement) {\n              contentElement.off('scroll', debouncedContentScroll);\n            }\n\n            contentElement = newContentEl;\n            disableScrollShrink = enableScrollShrink();\n          }\n        }\n\n        /**\n         *\n         */\n        function onContentScroll(e) {\n          var scrollTop = e ? e.target.scrollTop : prevScrollTop;\n\n          debouncedUpdateHeight();\n\n          y = Math.min(\n            toolbarHeight / shrinkSpeedFactor,\n            Math.max(0, y + scrollTop - prevScrollTop)\n          );\n\n          element.css($mdConstant.CSS.TRANSFORM, translateY([-y * shrinkSpeedFactor]));\n          contentElement.css($mdConstant.CSS.TRANSFORM, translateY([(toolbarHeight - y) * shrinkSpeedFactor]));\n\n          prevScrollTop = scrollTop;\n\n          $mdUtil.nextTick(function() {\n            var hasWhiteFrame = element.hasClass('md-whiteframe-z1');\n\n            if (hasWhiteFrame && !y) {\n              $animate.removeClass(element, 'md-whiteframe-z1');\n            } else if (!hasWhiteFrame && y) {\n              $animate.addClass(element, 'md-whiteframe-z1');\n            }\n          });\n\n        }\n\n        /**\n         *\n         */\n        function enableScrollShrink() {\n          if (!contentElement)     return angular.noop;           // no md-content\n\n          contentElement.on('scroll', debouncedContentScroll);\n          contentElement.attr('scroll-shrink', 'true');\n\n          $timeout(updateToolbarHeight);\n\n          return function disableScrollShrink() {\n            contentElement.off('scroll', debouncedContentScroll);\n            contentElement.attr('scroll-shrink', 'false');\n\n            updateToolbarHeight();\n          };\n        }\n\n        /**\n         *\n         */\n        function updateToolbarHeight() {\n          toolbarHeight = element.prop('offsetHeight');\n          // Add a negative margin-top the size of the toolbar to the content el.\n          // The content will start transformed down the toolbarHeight amount,\n          // so everything looks normal.\n          //\n          // As the user scrolls down, the content will be transformed up slowly\n          // to put the content underneath where the toolbar was.\n          var margin = (-toolbarHeight * shrinkSpeedFactor) + 'px';\n\n          contentElement.css({\n            \"margin-top\": margin,\n            \"margin-bottom\": margin\n          });\n\n          onContentScroll();\n        }\n\n      }\n\n    }\n  };\n\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.tooltip\n */\nMdTooltipDirective.$inject = [\"$timeout\", \"$window\", \"$$rAF\", \"$document\", \"$interpolate\", \"$mdUtil\", \"$mdPanel\", \"$$mdTooltipRegistry\"];\nangular\n    .module('material.components.tooltip', [\n      'material.core',\n      'material.components.panel'\n    ])\n    .directive('mdTooltip', MdTooltipDirective)\n    .service('$$mdTooltipRegistry', MdTooltipRegistry);\n\n\n/**\n * @ngdoc directive\n * @name mdTooltip\n * @module material.components.tooltip\n * @description\n * Tooltips are used to describe elements that are interactive and primarily\n * graphical (not textual).\n *\n * Place a `<md-tooltip>` as a child of the element it describes.\n *\n * A tooltip will activate when the user hovers over, focuses, or touches the\n * parent element.\n *\n * @usage\n * <hljs lang=\"html\">\n *   <md-button class=\"md-fab md-accent\" aria-label=\"Play\">\n *     <md-tooltip>Play Music</md-tooltip>\n *     <md-icon md-svg-src=\"img/icons/ic_play_arrow_24px.svg\"></md-icon>\n *   </md-button>\n * </hljs>\n *\n * @param {number=} md-z-index The visual level that the tooltip will appear\n *     in comparison with the rest of the elements of the application.\n * @param {expression=} md-visible Boolean bound to whether the tooltip is\n *     currently visible.\n * @param {number=} md-delay How many milliseconds to wait to show the tooltip\n *     after the user hovers over, focuses, or touches the parent element.\n *     Defaults to 0ms on non-touch devices and 75ms on touch.\n * @param {boolean=} md-autohide If present or provided with a boolean value,\n *     the tooltip will hide on mouse leave, regardless of focus.\n * @param {string=} md-direction The direction that the tooltip is shown,\n *     relative to the parent element. Supports top, right, bottom, and left.\n *     Defaults to bottom.\n */\nfunction MdTooltipDirective($timeout, $window, $$rAF, $document, $interpolate,\n    $mdUtil, $mdPanel, $$mdTooltipRegistry) {\n\n  var ENTER_EVENTS = 'focus touchstart mouseenter';\n  var LEAVE_EVENTS = 'blur touchcancel mouseleave';\n  var TOOLTIP_DEFAULT_Z_INDEX = 100;\n  var TOOLTIP_DEFAULT_SHOW_DELAY = 0;\n  var TOOLTIP_DEFAULT_DIRECTION = 'bottom';\n  var TOOLTIP_DIRECTIONS = {\n    top: { x: $mdPanel.xPosition.CENTER, y: $mdPanel.yPosition.ABOVE },\n    right: { x: $mdPanel.xPosition.OFFSET_END, y: $mdPanel.yPosition.CENTER },\n    bottom: { x: $mdPanel.xPosition.CENTER, y: $mdPanel.yPosition.BELOW },\n    left: { x: $mdPanel.xPosition.OFFSET_START, y: $mdPanel.yPosition.CENTER }\n  };\n\n  return {\n    restrict: 'E',\n    priority: 210, // Before ngAria\n    scope: {\n      mdZIndex: '=?mdZIndex',\n      mdDelay: '=?mdDelay',\n      mdVisible: '=?mdVisible',\n      mdAutohide: '=?mdAutohide',\n      mdDirection: '@?mdDirection' // Do not expect expressions.\n    },\n    link: linkFunc\n  };\n\n  function linkFunc(scope, element, attr) {\n    // Set constants.\n    var tooltipId = 'md-tooltip-' + $mdUtil.nextUid();\n    var parent = $mdUtil.getParentWithPointerEvents(element);\n    var debouncedOnResize = $$rAF.throttle(updatePosition);\n    var mouseActive = false;\n    var origin, position, panelPosition, panelRef, autohide, showTimeout,\n        elementFocusedOnWindowBlur = null;\n\n    // Set defaults\n    setDefaults();\n\n    // Set parent aria-label.\n    addAriaLabel();\n\n    // Remove the element from its current DOM position.\n    element.detach();\n\n    updatePosition();\n    bindEvents();\n    configureWatchers();\n\n    function setDefaults() {\n      scope.mdZIndex = scope.mdZIndex || TOOLTIP_DEFAULT_Z_INDEX;\n      scope.mdDelay = scope.mdDelay || TOOLTIP_DEFAULT_SHOW_DELAY;\n      if (!TOOLTIP_DIRECTIONS[scope.mdDirection]) {\n        scope.mdDirection = TOOLTIP_DEFAULT_DIRECTION;\n      }\n    }\n\n    function addAriaLabel(labelText) {\n      // Only interpolate the text from the HTML element because otherwise the custom text could\n      // be interpolated twice and cause XSS violations.\n      var interpolatedText = labelText || $interpolate(element.text().trim())(scope.$parent);\n\n      // Only add the `aria-label` to the parent if there isn't already one, if there isn't an\n      // already present `aria-labelledby`, or if the previous `aria-label` was added by the\n      // tooltip directive.\n      if (\n        (!parent.attr('aria-label') && !parent.attr('aria-labelledby')) ||\n        parent.attr('md-labeled-by-tooltip')\n      ) {\n        parent.attr('aria-label', interpolatedText);\n\n        // Set the `md-labeled-by-tooltip` attribute if it has not already been set.\n        if (!parent.attr('md-labeled-by-tooltip')) {\n          parent.attr('md-labeled-by-tooltip', tooltipId);\n        }\n      }\n    }\n\n    function updatePosition() {\n      setDefaults();\n\n      // If the panel has already been created, remove the current origin\n      // class from the panel element.\n      if (panelRef && panelRef.panelEl) {\n        panelRef.panelEl.removeClass(origin);\n      }\n\n      // Set the panel element origin class based off of the current\n      // mdDirection.\n      origin = 'md-origin-' + scope.mdDirection;\n\n      // Create the position of the panel based off of the mdDirection.\n      position = TOOLTIP_DIRECTIONS[scope.mdDirection];\n\n      // Using the newly created position object, use the MdPanel\n      // panelPosition API to build the panel's position.\n      panelPosition = $mdPanel.newPanelPosition()\n          .relativeTo(parent)\n          .addPanelPosition(position.x, position.y);\n\n      // If the panel has already been created, add the new origin class to\n      // the panel element and update it's position with the panelPosition.\n      if (panelRef && panelRef.panelEl) {\n        panelRef.panelEl.addClass(origin);\n        panelRef.updatePosition(panelPosition);\n      }\n    }\n\n    function bindEvents() {\n      // Add a mutationObserver where there is support for it and the need\n      // for it in the form of viable host(parent[0]).\n      if (parent[0] && 'MutationObserver' in $window) {\n        // Use a mutationObserver to tackle #2602.\n        var attributeObserver = new MutationObserver(function(mutations) {\n          if (isDisabledMutation(mutations)) {\n            $mdUtil.nextTick(function() {\n              setVisible(false);\n            });\n          }\n        });\n\n        attributeObserver.observe(parent[0], {\n          attributes: true\n        });\n      }\n\n      elementFocusedOnWindowBlur = false;\n\n      $$mdTooltipRegistry.register('scroll', windowScrollEventHandler, true);\n      $$mdTooltipRegistry.register('blur', windowBlurEventHandler);\n      $$mdTooltipRegistry.register('resize', debouncedOnResize);\n\n      scope.$on('$destroy', onDestroy);\n\n      // To avoid 'synthetic clicks', we listen to mousedown instead of\n      // 'click'.\n      parent.on('mousedown', mousedownEventHandler);\n      parent.on(ENTER_EVENTS, enterEventHandler);\n\n      function isDisabledMutation(mutations) {\n        mutations.some(function(mutation) {\n          return mutation.attributeName === 'disabled' && parent[0].disabled;\n        });\n        return false;\n      }\n\n      function windowScrollEventHandler() {\n        setVisible(false);\n      }\n\n      function windowBlurEventHandler() {\n        elementFocusedOnWindowBlur = document.activeElement === parent[0];\n      }\n\n      function enterEventHandler($event) {\n        // Prevent the tooltip from showing when the window is receiving\n        // focus.\n        if ($event.type === 'focus' && elementFocusedOnWindowBlur) {\n          elementFocusedOnWindowBlur = false;\n        } else if (!scope.mdVisible) {\n          parent.on(LEAVE_EVENTS, leaveEventHandler);\n          setVisible(true);\n\n          // If the user is on a touch device, we should bind the tap away\n          // after the 'touched' in order to prevent the tooltip being\n          // removed immediately.\n          if ($event.type === 'touchstart') {\n            parent.one('touchend', function() {\n              $mdUtil.nextTick(function() {\n                $document.one('touchend', leaveEventHandler);\n              }, false);\n            });\n          }\n        }\n      }\n\n      function leaveEventHandler() {\n        autohide = scope.hasOwnProperty('mdAutohide') ?\n            scope.mdAutohide :\n            attr.hasOwnProperty('mdAutohide');\n\n        if (autohide || mouseActive ||\n            $document[0].activeElement !== parent[0]) {\n          // When a show timeout is currently in progress, then we have\n          // to cancel it, otherwise the tooltip will remain showing\n          // without focus or hover.\n          if (showTimeout) {\n            $timeout.cancel(showTimeout);\n            setVisible.queued = false;\n            showTimeout = null;\n          }\n\n          parent.off(LEAVE_EVENTS, leaveEventHandler);\n          parent.triggerHandler('blur');\n          setVisible(false);\n        }\n        mouseActive = false;\n      }\n\n      function mousedownEventHandler() {\n        mouseActive = true;\n      }\n\n      function onDestroy() {\n        $$mdTooltipRegistry.deregister('scroll', windowScrollEventHandler, true);\n        $$mdTooltipRegistry.deregister('blur', windowBlurEventHandler);\n        $$mdTooltipRegistry.deregister('resize', debouncedOnResize);\n\n        parent\n            .off(ENTER_EVENTS, enterEventHandler)\n            .off(LEAVE_EVENTS, leaveEventHandler)\n            .off('mousedown', mousedownEventHandler);\n\n        // Trigger the handler in case any of the tooltips are\n        // still visible.\n        leaveEventHandler();\n        attributeObserver && attributeObserver.disconnect();\n      }\n    }\n\n    function configureWatchers() {\n      if (element[0] && 'MutationObserver' in $window) {\n        var attributeObserver = new MutationObserver(function(mutations) {\n          mutations.forEach(function(mutation) {\n            if (mutation.attributeName === 'md-visible' &&\n                !scope.visibleWatcher) {\n              scope.visibleWatcher = scope.$watch('mdVisible',\n                  onVisibleChanged);\n            }\n          });\n        });\n\n        attributeObserver.observe(element[0], {\n          attributes: true\n        });\n\n        // Build watcher only if mdVisible is being used.\n        if (attr.hasOwnProperty('mdVisible')) {\n          scope.visibleWatcher = scope.$watch('mdVisible',\n              onVisibleChanged);\n        }\n      } else {\n        // MutationObserver not supported\n        scope.visibleWatcher = scope.$watch('mdVisible', onVisibleChanged);\n      }\n\n      // Direction watcher\n      scope.$watch('mdDirection', updatePosition);\n\n      // Clean up if the element or parent was removed via jqLite's .remove.\n      // A couple of notes:\n      //   - In these cases the scope might not have been destroyed, which\n      //     is why we destroy it manually. An example of this can be having\n      //     `md-visible=\"false\"` and adding tooltips while they're\n      //     invisible. If `md-visible` becomes true, at some point, you'd\n      //     usually get a lot of tooltips.\n      //   - We use `.one`, not `.on`, because this only needs to fire once.\n      //     If we were using `.on`, it would get thrown into an infinite\n      //     loop.\n      //   - This kicks off the scope's `$destroy` event which finishes the\n      //     cleanup.\n      element.one('$destroy', onElementDestroy);\n      parent.one('$destroy', onElementDestroy);\n      scope.$on('$destroy', function() {\n        setVisible(false);\n        panelRef && panelRef.destroy();\n        attributeObserver && attributeObserver.disconnect();\n        element.remove();\n      });\n\n      // Updates the aria-label when the element text changes. This watch\n      // doesn't need to be set up if the element doesn't have any data\n      // bindings.\n      if (element.text().indexOf($interpolate.startSymbol()) > -1) {\n        scope.$watch(function() {\n          return element.text().trim();\n        }, addAriaLabel);\n      }\n\n      function onElementDestroy() {\n        scope.$destroy();\n      }\n    }\n\n    function setVisible(value) {\n      // Break if passed value is already in queue or there is no queue and\n      // passed value is current in the controller.\n      if (setVisible.queued && setVisible.value === !!value ||\n          !setVisible.queued && scope.mdVisible === !!value) {\n        return;\n      }\n      setVisible.value = !!value;\n\n      if (!setVisible.queued) {\n        if (value) {\n          setVisible.queued = true;\n          showTimeout = $timeout(function() {\n            scope.mdVisible = setVisible.value;\n            setVisible.queued = false;\n            showTimeout = null;\n            if (!scope.visibleWatcher) {\n              onVisibleChanged(scope.mdVisible);\n            }\n          }, scope.mdDelay);\n        } else {\n          $mdUtil.nextTick(function() {\n            scope.mdVisible = false;\n            if (!scope.visibleWatcher) {\n              onVisibleChanged(false);\n            }\n          });\n        }\n      }\n    }\n\n    function onVisibleChanged(isVisible) {\n      isVisible ? showTooltip() : hideTooltip();\n    }\n\n    function showTooltip() {\n      // Do not show the tooltip if the text is empty.\n      if (!element[0].textContent.trim()) {\n        throw new Error('Text for the tooltip has not been provided. ' +\n            'Please include text within the mdTooltip element.');\n      }\n\n      if (!panelRef) {\n        var attachTo = angular.element(document.body);\n        var panelAnimation = $mdPanel.newPanelAnimation()\n            .openFrom(parent)\n            .closeTo(parent)\n            .withAnimation({\n              open: 'md-show',\n              close: 'md-hide'\n            });\n\n        var panelConfig = {\n          id: tooltipId,\n          attachTo: attachTo,\n          contentElement: element,\n          propagateContainerEvents: true,\n          panelClass: 'md-tooltip',\n          animation: panelAnimation,\n          position: panelPosition,\n          zIndex: scope.mdZIndex,\n          focusOnOpen: false,\n          onDomAdded: function() {\n            panelRef.panelEl.addClass(origin);\n          }\n        };\n\n        panelRef = $mdPanel.create(panelConfig);\n      }\n\n      panelRef.open().then(function() {\n        panelRef.panelEl.attr('role', 'tooltip');\n      });\n    }\n\n    function hideTooltip() {\n      panelRef && panelRef.close();\n    }\n  }\n\n}\n\n\n/**\n * Service that is used to reduce the amount of listeners that are being\n * registered on the `window` by the tooltip component. Works by collecting\n * the individual event handlers and dispatching them from a global handler.\n *\n * @ngInject\n */\nfunction MdTooltipRegistry() {\n  var listeners = {};\n  var ngWindow = angular.element(window);\n\n  return {\n    register: register,\n    deregister: deregister\n  };\n\n  /**\n   * Global event handler that dispatches the registered handlers in the\n   * service.\n   * @param {!Event} event Event object passed in by the browser\n   */\n  function globalEventHandler(event) {\n    if (listeners[event.type]) {\n      listeners[event.type].forEach(function(currentHandler) {\n        currentHandler.call(this, event);\n      }, this);\n    }\n  }\n\n  /**\n   * Registers a new handler with the service.\n   * @param {string} type Type of event to be registered.\n   * @param {!Function} handler Event handler.\n   * @param {boolean} useCapture Whether to use event capturing.\n   */\n  function register(type, handler, useCapture) {\n    var handlers = listeners[type] = listeners[type] || [];\n\n    if (!handlers.length) {\n      useCapture ? window.addEventListener(type, globalEventHandler, true) :\n          ngWindow.on(type, globalEventHandler);\n    }\n\n    if (handlers.indexOf(handler) === -1) {\n      handlers.push(handler);\n    }\n  }\n\n  /**\n   * Removes an event handler from the service.\n   * @param {string} type Type of event handler.\n   * @param {!Function} handler The event handler itself.\n   * @param {boolean} useCapture Whether the event handler used event capturing.\n   */\n  function deregister(type, handler, useCapture) {\n    var handlers = listeners[type];\n    var index = handlers ? handlers.indexOf(handler) : -1;\n\n    if (index > -1) {\n      handlers.splice(index, 1);\n\n      if (handlers.length === 0) {\n        useCapture ? window.removeEventListener(type, globalEventHandler, true) :\n            ngWindow.off(type, globalEventHandler);\n      }\n    }\n  }\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.truncate\n */\nMdTruncateController.$inject = [\"$element\"];\nangular.module('material.components.truncate', ['material.core'])\n  .directive('mdTruncate', MdTruncateDirective);\n\n/**\n * @ngdoc directive\n * @name mdTruncate\n * @module material.components.truncate\n * @restrict AE\n * @description\n *\n * The `md-truncate` component displays a label that will automatically clip text which is wider\n * than the component. By default, it displays an ellipsis, but you may apply the `md-clip` CSS\n * class to override this default and use a standard \"clipping\" approach.\n *\n * <i><b>Note:</b> The `md-truncate` component does not automatically adjust it's width. You must\n * provide the `flex` attribute, or some other CSS-based width management. See the\n * <a ng-href=\"./demo/truncate\">demos</a> for examples.</i>\n *\n * @usage\n *\n * ### As an Element\n *\n * <hljs lang=\"html\">\n *   <div layout=\"row\">\n *     <md-button>Back</md-button>\n *\n *     <md-truncate flex>Chapter 1 - The Way of the Old West</md-truncate>\n *\n *     <md-button>Forward</md-button>\n *   </div>\n * </hljs>\n *\n * ### As an Attribute\n *\n * <hljs lang=\"html\">\n *   <h2 md-truncate style=\"max-width: 100px;\">Some Title With a Lot of Text</h2>\n * </hljs>\n *\n * ## CSS & Styles\n *\n * `<md-truncate>` provides two CSS classes that you may use to control the type of clipping.\n *\n * <i><b>Note:</b> The `md-truncate` also applies a setting of `width: 0;` when used with the `flex`\n * attribute to fix an issue with the flex element not shrinking properly.</i>\n *\n * <div>\n * <docs-css-api-table>\n *\n *   <docs-css-selector code=\".md-ellipsis\">\n *     Assigns the \"ellipsis\" behavior (default) which will cut off mid-word and append an ellipsis\n *     (&hellip;) to the end of the text.\n *   </docs-css-selector>\n *\n *   <docs-css-selector code=\".md-clip\">\n *     Assigns the \"clipping\" behavior which will simply chop off the text. This may happen\n *     mid-word or even mid-character.\n *   </docs-css-selector>\n *\n * </docs-css-api-table>\n * </div>\n */\nfunction MdTruncateDirective() {\n  return {\n    restrict: 'AE',\n\n    controller: MdTruncateController\n  };\n}\n\n/**\n * Controller for the <md-truncate> component.\n *\n * @param $element The md-truncate element.\n *\n * @constructor\n * @ngInject\n */\nfunction MdTruncateController($element) {\n  $element.addClass('md-truncate');\n}\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.virtualRepeat\n */\nVirtualRepeatContainerController.$inject = [\"$$rAF\", \"$mdUtil\", \"$mdConstant\", \"$parse\", \"$rootScope\", \"$window\", \"$scope\", \"$element\", \"$attrs\"];\nVirtualRepeatController.$inject = [\"$scope\", \"$element\", \"$attrs\", \"$browser\", \"$document\", \"$rootScope\", \"$$rAF\", \"$mdUtil\"];\nVirtualRepeatDirective.$inject = [\"$parse\"];\nangular.module('material.components.virtualRepeat', [\n  'material.core',\n  'material.components.showHide'\n])\n.directive('mdVirtualRepeatContainer', VirtualRepeatContainerDirective)\n.directive('mdVirtualRepeat', VirtualRepeatDirective)\n.directive('mdForceHeight', ForceHeightDirective);\n\n\n/**\n * @ngdoc directive\n * @name mdVirtualRepeatContainer\n * @module material.components.virtualRepeat\n * @restrict E\n * @description\n * `md-virtual-repeat-container` provides the scroll container for\n * <a ng-href=\"api/directive/mdVirtualRepeat\">md-virtual-repeat</a>.\n *\n * VirtualRepeat is a limited substitute for `ng-repeat` that renders only\n * enough DOM nodes to fill the container, recycling them as the user scrolls.\n *\n * Once an element is not visible anymore, the Virtual Repeat recycles the element and reuses it\n * for another visible item by replacing the previous data set with the set of currently visible\n * elements.\n *\n * ### Common Issues\n *\n * - When having one-time bindings inside of the view template, the Virtual Repeat will not properly\n *   update the bindings for new items, since the view will be recycled.\n * - Directives inside of a Virtual Repeat will be only compiled (linked) once, because those\n *   items will be recycled and used for other items.\n *   The Virtual Repeat just updates the scope bindings.\n *\n *\n * ### Notes\n *\n * > The VirtualRepeat is a similar implementation to the Android\n * [RecyclerView](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html).\n *\n * <!-- This comment forces a break between blockquotes //-->\n *\n * > Please also review the <a ng-href=\"api/directive/mdVirtualRepeat\">mdVirtualRepeat</a>\n * documentation for more information.\n *\n *\n * @usage\n * <hljs lang=\"html\">\n *\n * <md-virtual-repeat-container md-top-index=\"topIndex\">\n *   <div md-virtual-repeat=\"i in items\" md-item-size=\"20\">Hello {{i}}!</div>\n * </md-virtual-repeat-container>\n * </hljs>\n *\n * @param {boolean=} md-auto-shrink When present and the container will shrink to fit\n *     the number of items in the `md-virtual-repeat`.\n * @param {number=} md-auto-shrink-min Minimum number of items that md-auto-shrink\n *     will shrink to. Default: `0`.\n * @param {boolean=} md-orient-horizontal Whether the container should scroll horizontally.\n *     The default is `false` which indicates vertical orientation and scrolling.\n * @param {number=} md-top-index Binds the index of the item that is at the top of the scroll\n *     container to `$scope`. It can both read and set the scroll position.\n */\nfunction VirtualRepeatContainerDirective() {\n  return {\n    controller: VirtualRepeatContainerController,\n    template: virtualRepeatContainerTemplate,\n    compile: function virtualRepeatContainerCompile($element, $attrs) {\n      $element\n          .addClass('md-virtual-repeat-container')\n          .addClass($attrs.hasOwnProperty('mdOrientHorizontal')\n              ? 'md-orient-horizontal'\n              : 'md-orient-vertical');\n    }\n  };\n}\n\n\nfunction virtualRepeatContainerTemplate($element) {\n  return '<div class=\"md-virtual-repeat-scroller\" role=\"presentation\">' +\n    '<div class=\"md-virtual-repeat-sizer\" role=\"presentation\"></div>' +\n    '<div class=\"md-virtual-repeat-offsetter\" role=\"presentation\">' +\n      $element[0].innerHTML +\n    '</div></div>';\n}\n\n/**\n * Number of additional elements to render above and below the visible area inside\n * of the virtual repeat container. A higher number results in less flicker when scrolling\n * very quickly in Safari, but comes with a higher rendering and dirty-checking cost.\n * @const {number}\n */\nvar NUM_EXTRA = 3;\n\n/** @ngInject */\nfunction VirtualRepeatContainerController($$rAF, $mdUtil, $mdConstant, $parse, $rootScope, $window,\n                                          $scope, $element, $attrs) {\n  this.$rootScope = $rootScope;\n  this.$scope = $scope;\n  this.$element = $element;\n  this.$attrs = $attrs;\n\n  /** @type {number} The width or height of the container */\n  this.size = 0;\n  /** @type {number} The scroll width or height of the scroller */\n  this.scrollSize = 0;\n  /** @type {number} The scrollLeft or scrollTop of the scroller */\n  this.scrollOffset = 0;\n  /** @type {boolean} Whether the scroller is oriented horizontally */\n  this.horizontal = this.$attrs.hasOwnProperty('mdOrientHorizontal');\n  /** @type {!VirtualRepeatController} The repeater inside of this container */\n  this.repeater = null;\n  /** @type {boolean} Whether auto-shrink is enabled */\n  this.autoShrink = this.$attrs.hasOwnProperty('mdAutoShrink');\n  /** @type {number} Minimum number of items to auto-shrink to */\n  this.autoShrinkMin = parseInt(this.$attrs.mdAutoShrinkMin, 10) || 0;\n  /** @type {?number} Original container size when shrank */\n  this.originalSize = null;\n  /** @type {number} Amount to offset the total scroll size by. */\n  this.offsetSize = parseInt(this.$attrs.mdOffsetSize, 10) || 0;\n  /** @type {?string} height or width element style on the container prior to auto-shrinking. */\n  this.oldElementSize = null;\n  /** @type {!number} Maximum amount of pixels allowed for a single DOM element */\n  this.maxElementPixels = $mdConstant.ELEMENT_MAX_PIXELS;\n  /** @type {string}  Direction of the text */\n  this.ltr = !$mdUtil.isRtl(this.$attrs);\n\n  if (this.$attrs.mdTopIndex) {\n    /** @type {function(angular.Scope): number} Binds to topIndex on AngularJS scope */\n    this.bindTopIndex = $parse(this.$attrs.mdTopIndex);\n    /** @type {number} The index of the item that is at the top of the scroll container */\n    this.topIndex = this.bindTopIndex(this.$scope);\n\n    if (!angular.isDefined(this.topIndex)) {\n      this.topIndex = 0;\n      this.bindTopIndex.assign(this.$scope, 0);\n    }\n\n    this.$scope.$watch(this.bindTopIndex, angular.bind(this, function(newIndex) {\n      if (newIndex !== this.topIndex) {\n        this.scrollToIndex(newIndex);\n      }\n    }));\n  } else {\n    this.topIndex = 0;\n  }\n\n  this.scroller = $element[0].querySelector('.md-virtual-repeat-scroller');\n  this.sizer = this.scroller.querySelector('.md-virtual-repeat-sizer');\n  this.offsetter = this.scroller.querySelector('.md-virtual-repeat-offsetter');\n\n  // After the DOM stabilizes, measure the initial size of the container and\n  // make a best effort at re-measuring as it changes.\n  var boundUpdateSize = angular.bind(this, this.updateSize);\n\n  $$rAF(angular.bind(this, function() {\n    boundUpdateSize();\n\n    var debouncedUpdateSize = $mdUtil.debounce(boundUpdateSize, 10, null, false);\n    var jWindow = angular.element($window);\n\n    // Make one more attempt to get the size if it is 0.\n    // This is not by any means a perfect approach, but there's really no\n    // silver bullet here.\n    if (!this.size) {\n      debouncedUpdateSize();\n    }\n\n    jWindow.on('resize', debouncedUpdateSize);\n    $scope.$on('$destroy', function() {\n      jWindow.off('resize', debouncedUpdateSize);\n    });\n\n    $scope.$emit('$md-resize-enable');\n    $scope.$on('$md-resize', boundUpdateSize);\n  }));\n}\n\n\n/** Called by the md-virtual-repeat inside of the container at startup. */\nVirtualRepeatContainerController.prototype.register = function(repeaterCtrl) {\n  this.repeater = repeaterCtrl;\n\n  angular.element(this.scroller)\n      .on('scroll wheel touchmove touchend', angular.bind(this, this.handleScroll_));\n};\n\n\n/** @return {boolean} Whether the container is configured for horizontal scrolling. */\nVirtualRepeatContainerController.prototype.isHorizontal = function() {\n  return this.horizontal;\n};\n\n\n/** @return {number} The size (width or height) of the container. */\nVirtualRepeatContainerController.prototype.getSize = function() {\n  return this.size;\n};\n\n\n/**\n * Resizes the container.\n * @private\n * @param {number} size The new size to set.\n */\nVirtualRepeatContainerController.prototype.setSize_ = function(size) {\n  var dimension = this.getDimensionName_();\n\n  this.size = size;\n  this.$element[0].style[dimension] = size + 'px';\n};\n\n\nVirtualRepeatContainerController.prototype.unsetSize_ = function() {\n  this.$element[0].style[this.getDimensionName_()] = this.oldElementSize;\n  this.oldElementSize = null;\n};\n\n\n/** Instructs the container to re-measure its size. */\nVirtualRepeatContainerController.prototype.updateSize = function() {\n  // If the original size is already determined, we can skip the update.\n  if (this.originalSize) return;\n\n  var size = this.isHorizontal()\n      ? this.$element[0].clientWidth\n      : this.$element[0].clientHeight;\n\n  if (size) {\n    this.size = size;\n  }\n\n  // Recheck the scroll position after updating the size. This resolves\n  // problems that can result if the scroll position was measured while the\n  // element was display: none or detached from the document.\n  this.handleScroll_();\n\n  this.repeater && this.repeater.containerUpdated();\n};\n\n\n/** @return {number} The container's scrollHeight or scrollWidth. */\nVirtualRepeatContainerController.prototype.getScrollSize = function() {\n  return this.scrollSize;\n};\n\n/**\n * @returns {string} either width or height dimension\n * @private\n */\nVirtualRepeatContainerController.prototype.getDimensionName_ = function() {\n  return this.isHorizontal() ? 'width' : 'height';\n};\n\n\n/**\n * Sets the scroller element to the specified size.\n * @private\n * @param {number} size The new size.\n */\nVirtualRepeatContainerController.prototype.sizeScroller_ = function(size) {\n  var dimension =  this.getDimensionName_();\n  var crossDimension = this.isHorizontal() ? 'height' : 'width';\n\n  // Clear any existing dimensions.\n  this.sizer.innerHTML = '';\n\n  // If the size falls within the browser's maximum explicit size for a single element, we can\n  // set the size and be done. Otherwise, we have to create children that add up the the desired\n  // size.\n  if (size < this.maxElementPixels) {\n    this.sizer.style[dimension] = size + 'px';\n  } else {\n    this.sizer.style[dimension] = 'auto';\n    this.sizer.style[crossDimension] = 'auto';\n\n    // Divide the total size we have to render into N max-size pieces.\n    var numChildren = Math.floor(size / this.maxElementPixels);\n\n    // Element template to clone for each max-size piece.\n    var sizerChild = document.createElement('div');\n    sizerChild.style[dimension] = this.maxElementPixels + 'px';\n    sizerChild.style[crossDimension] = '1px';\n\n    for (var i = 0; i < numChildren; i++) {\n      this.sizer.appendChild(sizerChild.cloneNode(false));\n    }\n\n    // Re-use the element template for the remainder.\n    sizerChild.style[dimension] = (size - (numChildren * this.maxElementPixels)) + 'px';\n    this.sizer.appendChild(sizerChild);\n  }\n};\n\n\n/**\n * If auto-shrinking is enabled, shrinks or unshrinks as appropriate.\n * @private\n * @param {number} size The new size.\n */\nVirtualRepeatContainerController.prototype.autoShrink_ = function(size) {\n  var shrinkSize = Math.max(size, this.autoShrinkMin * this.repeater.getItemSize());\n\n  if (this.autoShrink && shrinkSize !== this.size) {\n    if (this.oldElementSize === null) {\n      this.oldElementSize = this.$element[0].style[this.getDimensionName_()];\n    }\n\n    var currentSize = this.originalSize || this.size;\n\n    if (!currentSize || shrinkSize < currentSize) {\n      if (!this.originalSize) {\n        this.originalSize = this.size;\n      }\n\n      // Now we update the containers size, because shrinking is enabled.\n      this.setSize_(shrinkSize);\n    } else if (this.originalSize !== null) {\n      // Set the size back to our initial size.\n      this.unsetSize_();\n\n      var _originalSize = this.originalSize;\n      this.originalSize = null;\n\n      // We determine the repeaters size again, if the original size was zero.\n      // The originalSize needs to be null, to be able to determine the size.\n      if (!_originalSize) this.updateSize();\n\n      // Apply the original size or the determined size back to the container, because\n      // it has been overwritten before, in the shrink block.\n      this.setSize_(_originalSize || this.size);\n    }\n\n    this.repeater.containerUpdated();\n  }\n};\n\n\n/**\n * Sets the scrollHeight or scrollWidth. Called by the repeater based on\n * its item count and item size.\n * @param {number} itemsSize The total size of the items.\n */\nVirtualRepeatContainerController.prototype.setScrollSize = function(itemsSize) {\n  var size = itemsSize + this.offsetSize;\n  if (this.scrollSize === size) return;\n\n  this.sizeScroller_(size);\n  this.autoShrink_(size);\n  this.scrollSize = size;\n};\n\n\n/** @return {number} The container's current scroll offset. */\nVirtualRepeatContainerController.prototype.getScrollOffset = function() {\n  return this.scrollOffset;\n};\n\n/**\n * Scrolls to a given scrollTop position.\n * @param {number} position\n */\nVirtualRepeatContainerController.prototype.scrollTo = function(position) {\n  this.scroller[this.isHorizontal() ? 'scrollLeft' : 'scrollTop'] = position;\n  this.handleScroll_();\n};\n\n/**\n * Scrolls the item with the given index to the top of the scroll container.\n * @param {number} index\n */\nVirtualRepeatContainerController.prototype.scrollToIndex = function(index) {\n  var itemSize = this.repeater.getItemSize();\n  var itemsLength = this.repeater.itemsLength;\n  if (index > itemsLength) {\n    index = itemsLength - 1;\n  }\n  this.scrollTo(itemSize * index);\n};\n\nVirtualRepeatContainerController.prototype.resetScroll = function() {\n  this.scrollTo(0);\n};\n\n\nVirtualRepeatContainerController.prototype.handleScroll_ = function() {\n  if (!this.ltr && !this.maxSize) {\n    this.scroller.scrollLeft = this.scrollSize;\n    this.maxSize = this.scroller.scrollLeft;\n  }\n  var offset = this.isHorizontal() ?\n      (this.ltr ? this.scroller.scrollLeft : this.maxSize - this.scroller.scrollLeft)\n      : this.scroller.scrollTop;\n  if (this.scrollSize < this.size) return;\n  if (offset > this.scrollSize - this.size) {\n    offset = this.scrollSize - this.size;\n  }\n  if (offset === this.scrollOffset) return;\n\n  var itemSize = this.repeater.getItemSize();\n  if (!itemSize) return;\n\n  var numItems = Math.max(0, Math.floor(offset / itemSize) - NUM_EXTRA);\n\n  var transform = (this.isHorizontal() ? 'translateX(' : 'translateY(') +\n      (!this.isHorizontal() || this.ltr ? (numItems * itemSize) : - (numItems * itemSize))  + 'px)';\n\n  this.scrollOffset = offset;\n  this.offsetter.style.webkitTransform = transform;\n  this.offsetter.style.transform = transform;\n\n  if (this.bindTopIndex) {\n    var topIndex = Math.floor(offset / itemSize);\n    if (topIndex !== this.topIndex && topIndex < this.repeater.getItemCount()) {\n      this.topIndex = topIndex;\n      this.bindTopIndex.assign(this.$scope, topIndex);\n      if (!this.$rootScope.$$phase) this.$scope.$digest();\n    }\n  }\n\n  this.repeater.containerUpdated();\n};\n\n\n/**\n * @ngdoc directive\n * @name mdVirtualRepeat\n * @module material.components.virtualRepeat\n * @restrict A\n * @priority 1000\n * @description\n * The `md-virtual-repeat` attribute is applied to a template that is repeated using virtual\n * scrolling. This provides smooth and performant scrolling through very large lists of elements.\n *\n * Virtual repeat is a limited substitute for `ng-repeat` that renders only\n * enough DOM nodes to fill the container, recycling them as the user scrolls.\n *\n * ### Notes\n *\n * - Arrays are supported for iteration by default.\n * - An object can used use if `md-on-demand` is specified and the object implements the interface\n *   described in the `md-on-demand` <a ng-href=\"#attributes\">documentation</a>.\n * - `trackBy`, `as` alias, and `(key, value)` syntax from `ng-repeat` are not supported.\n *\n * ### On-Demand Async Item Loading\n *\n * When using the `md-on-demand` attribute and loading some asynchronous data,\n * the `getItemAtIndex` function will mostly return nothing.\n *\n * <hljs lang=\"js\">\n *   DynamicItems.prototype.getItemAtIndex = function(index) {\n *     if (this.pages[index]) {\n *       return this.pages[index];\n *     } else {\n *       // This is an asynchronous action and does not return any value.\n *       this.loadPage(index);\n *     }\n *   };\n * </hljs>\n *\n * This means that the Virtual Repeat will not have any value for the given index.<br/>\n * After the data loading completes, the user expects the Virtual Repeat to recognize the change.\n *\n * To make sure that the Virtual Repeat properly detects any change, you need to run the operation\n * in another digest.\n *\n * <hljs lang=\"js\">\n *   DynamicItems.prototype.loadPage = function(index) {\n *     var self = this;\n *\n *     // Trigger a new digest by using $timeout\n *     $timeout(function() {\n *       self.pages[index] = Data;\n *     });\n *   };\n * </hljs>\n *\n * > <b>Note:</b> Please also review the\n *   <a ng-href=\"api/directive/mdVirtualRepeatContainer\">VirtualRepeatContainer</a> documentation\n *   for more information.\n *\n * @usage\n * <hljs lang=\"html\">\n * <md-virtual-repeat-container>\n *   <div md-virtual-repeat=\"i in items\">Hello {{i}}!</div>\n * </md-virtual-repeat-container>\n *\n * <md-virtual-repeat-container md-orient-horizontal>\n *   <div md-virtual-repeat=\"i in items\" md-item-size=\"20\">Hello {{i}}!</div>\n * </md-virtual-repeat-container>\n * </hljs>\n *\n * @param {expression=} md-extra-name Evaluates to an additional name to which the current iterated\n *   item can be assigned on the repeated scope (needed for use in `md-autocomplete`).\n * @param {number=} md-item-size Optional height or width of the repeated elements (which **must be\n *   identical for each element**). Virtual repeat will attempt to read the size from the DOM,\n *   if missing, but it still assumes that all repeated nodes have the **same height**\n *   (when scrolling vertically) or **same width** (when scrolling horizontally).\n * @param {boolean=} md-on-demand When present, treats the `md-virtual-repeat` argument as an object\n *   that can fetch rows rather than an array.\n *\n *   **NOTE:** This object **must** implement the following interface with two methods:\n *\n *   - `getItemAtIndex` - `{function(index): Object}`: The item at that `index` or `null` if it is\n *     not yet loaded (it should start downloading the item in that case).\n *   - `getLength` - `{function(): number}`: The data length to which the repeater container\n *     should be sized. Ideally, when the count is known, this method should return it.\n *     Otherwise, return a higher number than the currently loaded items to produce an\n *     infinite-scroll behavior.\n */\nfunction VirtualRepeatDirective($parse) {\n  return {\n    controller: VirtualRepeatController,\n    priority: 1000,\n    require: ['mdVirtualRepeat', '^^mdVirtualRepeatContainer'],\n    restrict: 'A',\n    terminal: true,\n    transclude: 'element',\n    compile: function VirtualRepeatCompile($element, $attrs) {\n      var expression = $attrs.mdVirtualRepeat;\n      var match = expression.match(/^\\s*([\\s\\S]+?)\\s+in\\s+([\\s\\S]+?)\\s*$/);\n      var repeatName = match[1];\n      var repeatListExpression = $parse(match[2]);\n      var extraName = $attrs.mdExtraName && $parse($attrs.mdExtraName);\n\n      return function VirtualRepeatLink($scope, $element, $attrs, ctrl, $transclude) {\n        ctrl[0].link_(ctrl[1], $transclude, repeatName, repeatListExpression, extraName);\n      };\n    }\n  };\n}\n\n\n/** @ngInject */\nfunction VirtualRepeatController($scope, $element, $attrs, $browser, $document, $rootScope,\n    $$rAF, $mdUtil) {\n  this.$scope = $scope;\n  this.$element = $element;\n  this.$attrs = $attrs;\n  this.$browser = $browser;\n  this.$document = $document;\n  this.$mdUtil = $mdUtil;\n  this.$rootScope = $rootScope;\n  this.$$rAF = $$rAF;\n\n  /** @type {boolean} Whether we are in on-demand mode. */\n  this.onDemand = $mdUtil.parseAttributeBoolean($attrs.mdOnDemand);\n  /** @type {!Function} Backup reference to $browser.$$checkUrlChange */\n  this.browserCheckUrlChange = $browser.$$checkUrlChange;\n  /** @type {number} Most recent starting repeat index (based on scroll offset) */\n  this.newStartIndex = 0;\n  /** @type {number} Most recent ending repeat index (based on scroll offset) */\n  this.newEndIndex = 0;\n  /** @type {number} Most recent end visible index (based on scroll offset) */\n  this.newVisibleEnd = 0;\n  /** @type {number} Previous starting repeat index (based on scroll offset) */\n  this.startIndex = 0;\n  /** @type {number} Previous ending repeat index (based on scroll offset) */\n  this.endIndex = 0;\n  /** @type {?number} Height/width of repeated elements. */\n  this.itemSize = $scope.$eval($attrs.mdItemSize) || null;\n\n  /** @type {boolean} Whether this is the first time that items are rendered. */\n  this.isFirstRender = true;\n\n  /**\n   * @private {boolean} Whether the items in the list are already being updated. Used to prevent\n   *     nested calls to virtualRepeatUpdate_.\n   */\n  this.isVirtualRepeatUpdating_ = false;\n\n  /** @type {number} Most recently seen length of items. */\n  this.itemsLength = 0;\n\n  /**\n   * @type {!Function} Unwatch callback for item size (when md-items-size is\n   *     not specified), or angular.noop otherwise.\n   */\n  this.unwatchItemSize_ = angular.noop;\n\n  /**\n   * Presently rendered blocks by repeat index.\n   * @type {Object<number, !VirtualRepeatController.Block>}\n   */\n  this.blocks = {};\n  /** @type {Array<!VirtualRepeatController.Block>} A pool of presently unused blocks. */\n  this.pooledBlocks = [];\n\n  $scope.$on('$destroy', angular.bind(this, this.cleanupBlocks_));\n}\n\n\n/**\n * An object representing a repeated item.\n * @typedef {{element: !jqLite, new: boolean, scope: !angular.Scope}}\n */\nVirtualRepeatController.Block;\n\n\n/**\n * Called at startup by the md-virtual-repeat postLink function.\n * @param {!VirtualRepeatContainerController} container The container's controller.\n * @param {!Function} transclude The repeated element's bound transclude function.\n * @param {string} repeatName The left hand side of the repeat expression, indicating\n *     the name for each item in the array.\n * @param {!Function} repeatListExpression A compiled expression based on the right hand side\n *     of the repeat expression. Points to the array to repeat over.\n * @param {string|undefined} extraName The optional extra repeatName.\n */\nVirtualRepeatController.prototype.link_ =\n    function(container, transclude, repeatName, repeatListExpression, extraName) {\n  this.container = container;\n  this.transclude = transclude;\n  this.repeatName = repeatName;\n  this.rawRepeatListExpression = repeatListExpression;\n  this.extraName = extraName;\n  this.sized = false;\n\n  this.repeatListExpression = angular.bind(this, this.repeatListExpression_);\n\n  this.container.register(this);\n};\n\n\n/** @private Cleans up unused blocks. */\nVirtualRepeatController.prototype.cleanupBlocks_ = function() {\n  angular.forEach(this.pooledBlocks, function cleanupBlock(block) {\n    block.element.remove();\n  });\n};\n\n\n/** @private Attempts to set itemSize by measuring a repeated element in the dom */\nVirtualRepeatController.prototype.readItemSize_ = function() {\n  if (this.itemSize) {\n    // itemSize was successfully read in a different asynchronous call.\n    return;\n  }\n\n  this.items = this.repeatListExpression(this.$scope);\n  this.parentNode = this.$element[0].parentNode;\n  var block = this.getBlock_(0);\n  if (!block.element[0].parentNode) {\n    this.parentNode.appendChild(block.element[0]);\n  }\n\n  this.itemSize = block.element[0][\n      this.container.isHorizontal() ? 'offsetWidth' : 'offsetHeight'] || null;\n\n  this.blocks[0] = block;\n  this.poolBlock_(0);\n\n  if (this.itemSize) {\n    this.containerUpdated();\n  }\n};\n\n\n/**\n * Returns the user-specified repeat list, transforming it into an array-like\n * object in the case of infinite scroll/dynamic load mode.\n * @param {!angular.Scope} scope The scope.\n * @return {!Array|!Object} An array or array-like object for iteration.\n */\nVirtualRepeatController.prototype.repeatListExpression_ = function(scope) {\n  var repeatList = this.rawRepeatListExpression(scope);\n\n  if (this.onDemand && repeatList) {\n    var virtualList = new VirtualRepeatModelArrayLike(repeatList);\n    virtualList.$$includeIndexes(this.newStartIndex, this.newVisibleEnd);\n    return virtualList;\n  } else {\n    return repeatList;\n  }\n};\n\n\n/**\n * Called by the container. Informs us that the container's scroll or size has\n * changed.\n */\nVirtualRepeatController.prototype.containerUpdated = function() {\n  // If itemSize is unknown, attempt to measure it.\n  if (!this.itemSize) {\n    // Make sure to clean up watchers if we can (see #8178)\n    if (this.unwatchItemSize_ && this.unwatchItemSize_ !== angular.noop){\n      this.unwatchItemSize_();\n    }\n    this.unwatchItemSize_ = this.$scope.$watchCollection(\n        this.repeatListExpression,\n        angular.bind(this, function(items) {\n          if (items && items.length) {\n            this.readItemSize_();\n          }\n        }));\n    if (!this.$rootScope.$$phase) this.$scope.$digest();\n\n    return;\n  } else if (!this.sized) {\n    this.items = this.repeatListExpression(this.$scope);\n  }\n\n  if (!this.sized) {\n    this.unwatchItemSize_();\n    this.sized = true;\n    this.$scope.$watchCollection(this.repeatListExpression,\n        angular.bind(this, function(items, oldItems) {\n          if (!this.isVirtualRepeatUpdating_) {\n            this.virtualRepeatUpdate_(items, oldItems);\n          }\n        }));\n  }\n\n  this.updateIndexes_();\n\n  if (this.newStartIndex !== this.startIndex ||\n      this.newEndIndex !== this.endIndex ||\n      this.container.getScrollOffset() > this.container.getScrollSize()) {\n    if (this.items instanceof VirtualRepeatModelArrayLike) {\n      this.items.$$includeIndexes(this.newStartIndex, this.newEndIndex);\n    }\n    this.virtualRepeatUpdate_(this.items, this.items);\n  }\n};\n\n\n/**\n * Called by the container. Returns the size of a single repeated item.\n * @return {?number} size of a repeated item.\n */\nVirtualRepeatController.prototype.getItemSize = function() {\n  return this.itemSize;\n};\n\n\n/**\n * Called by the container.\n * @return {?number} the most recently seen length of items.\n */\nVirtualRepeatController.prototype.getItemCount = function() {\n  return this.itemsLength;\n};\n\n\n/**\n * Updates the order and visible offset of repeated blocks in response to scrolling\n * or updates to `items`.\n * @param {Array} items visible elements\n * @param {Array} oldItems previously visible elements\n * @private\n */\nVirtualRepeatController.prototype.virtualRepeatUpdate_ = function(items, oldItems) {\n  this.isVirtualRepeatUpdating_ = true;\n\n  var itemsLength = items && items.length || 0;\n  var lengthChanged = false;\n\n  // If the number of items shrank, keep the scroll position.\n  if (this.items && itemsLength < this.items.length && this.container.getScrollOffset() !== 0) {\n    this.items = items;\n    var previousScrollOffset = this.container.getScrollOffset();\n    this.container.resetScroll();\n    this.container.scrollTo(previousScrollOffset);\n  }\n\n  if (itemsLength !== this.itemsLength) {\n    lengthChanged = true;\n    this.itemsLength = itemsLength;\n  }\n\n  this.items = items;\n  if (items !== oldItems || lengthChanged) {\n    this.updateIndexes_();\n  }\n\n  this.parentNode = this.$element[0].parentNode;\n\n  if (lengthChanged) {\n    this.container.setScrollSize(itemsLength * this.itemSize);\n  }\n\n  // Detach and pool any blocks that are no longer in the viewport.\n  Object.keys(this.blocks).forEach(function(blockIndex) {\n    var index = parseInt(blockIndex, 10);\n    if (index < this.newStartIndex || index >= this.newEndIndex) {\n      this.poolBlock_(index);\n    }\n  }, this);\n\n  // Add needed blocks.\n  // For performance reasons, temporarily block browser url checks as we digest\n  // the restored block scopes ($$checkUrlChange reads window.location to\n  // check for changes and trigger route change, etc, which we don't need when\n  // trying to scroll at 60fps).\n  this.$browser.$$checkUrlChange = angular.noop;\n\n  var i, block,\n      newStartBlocks = [],\n      newEndBlocks = [];\n\n  // Collect blocks at the top.\n  for (i = this.newStartIndex; i < this.newEndIndex && this.blocks[i] == null; i++) {\n    block = this.getBlock_(i);\n    this.updateBlock_(block, i);\n    newStartBlocks.push(block);\n  }\n\n  // Update blocks that are already rendered.\n  for (; this.blocks[i] != null; i++) {\n    this.updateBlock_(this.blocks[i], i);\n  }\n  var maxIndex = i - 1;\n\n  // Collect blocks at the end.\n  for (; i < this.newEndIndex; i++) {\n    block = this.getBlock_(i);\n    this.updateBlock_(block, i);\n    newEndBlocks.push(block);\n  }\n\n  // Attach collected blocks to the document.\n  if (newStartBlocks.length) {\n    this.parentNode.insertBefore(\n        this.domFragmentFromBlocks_(newStartBlocks),\n        this.$element[0].nextSibling);\n  }\n  if (newEndBlocks.length) {\n    this.parentNode.insertBefore(\n        this.domFragmentFromBlocks_(newEndBlocks),\n        this.blocks[maxIndex] && this.blocks[maxIndex].element[0].nextSibling);\n  }\n\n  // Restore $$checkUrlChange.\n  this.$browser.$$checkUrlChange = this.browserCheckUrlChange;\n\n  this.startIndex = this.newStartIndex;\n  this.endIndex = this.newEndIndex;\n\n  if (this.isFirstRender) {\n    this.isFirstRender = false;\n    var firstRenderStartIndex = this.$attrs.mdStartIndex ?\n      this.$scope.$eval(this.$attrs.mdStartIndex) :\n      this.container.topIndex;\n\n    // The first call to virtualRepeatUpdate_ may not be when the virtual repeater is ready.\n    // Introduce a slight delay so that the update happens when it is actually ready.\n    this.$mdUtil.nextTick(function() {\n      this.container.scrollToIndex(firstRenderStartIndex);\n    }.bind(this));\n  }\n\n  this.isVirtualRepeatUpdating_ = false;\n};\n\n\n/**\n * @param {number} index Where the block is to be in the repeated list.\n * @return {!VirtualRepeatController.Block} A new or pooled block to place at the specified index.\n * @private\n */\nVirtualRepeatController.prototype.getBlock_ = function(index) {\n  if (this.pooledBlocks.length) {\n    return this.pooledBlocks.pop();\n  }\n\n  var block;\n  this.transclude(angular.bind(this, function(clone, scope) {\n    block = {\n      element: clone,\n      new: true,\n      scope: scope\n    };\n\n    this.updateScope_(scope, index);\n    this.parentNode.appendChild(clone[0]);\n  }));\n\n  return block;\n};\n\n\n/**\n * Updates and if not in a digest cycle, digests the specified block's scope to the data\n * at the specified index.\n * @param {!VirtualRepeatController.Block} block The block whose scope should be updated.\n * @param {number} index The index to set.\n * @private\n */\nVirtualRepeatController.prototype.updateBlock_ = function(block, index) {\n  this.blocks[index] = block;\n\n  if (!block.new &&\n      (block.scope.$index === index && block.scope[this.repeatName] === this.items[index])) {\n    return;\n  }\n  block.new = false;\n\n  // Update and digest the block's scope.\n  this.updateScope_(block.scope, index);\n\n  // Perform digest before reattaching the block.\n  // Any resulting synchronous DOM mutations should be much faster as a result.\n  // This might break some directives.\n  if (!this.$rootScope.$$phase) {\n    block.scope.$digest();\n  }\n};\n\n\n/**\n * Updates scope to the data at the specified index.\n * @param {!angular.Scope} scope The scope which should be updated.\n * @param {number} index The index to set.\n * @private\n */\nVirtualRepeatController.prototype.updateScope_ = function(scope, index) {\n  scope.$index = index;\n  scope[this.repeatName] = this.items && this.items[index];\n  if (this.extraName) scope[this.extraName(this.$scope)] = this.items[index];\n};\n\n\n/**\n * Pools the block at the specified index (Pulls its element out of the dom and stores it).\n * @param {number} index The index at which the block to pool is stored.\n * @private\n */\nVirtualRepeatController.prototype.poolBlock_ = function(index) {\n  this.pooledBlocks.push(this.blocks[index]);\n  this.parentNode.removeChild(this.blocks[index].element[0]);\n  delete this.blocks[index];\n};\n\n\n/**\n * Produces a dom fragment containing the elements from the list of blocks.\n * @param {!Array<!VirtualRepeatController.Block>} blocks The blocks whose elements\n *     should be added to the document fragment.\n * @return {DocumentFragment}\n * @private\n */\nVirtualRepeatController.prototype.domFragmentFromBlocks_ = function(blocks) {\n  var fragment = this.$document[0].createDocumentFragment();\n  blocks.forEach(function(block) {\n    fragment.appendChild(block.element[0]);\n  });\n  return fragment;\n};\n\n\n/**\n * Updates start and end indexes based on length of repeated items and container size.\n * @private\n */\nVirtualRepeatController.prototype.updateIndexes_ = function() {\n  var itemsLength = this.items ? this.items.length : 0;\n  var containerLength = Math.ceil(this.container.getSize() / this.itemSize);\n\n  this.newStartIndex = Math.max(0, Math.min(\n      itemsLength - containerLength,\n      Math.floor(this.container.getScrollOffset() / this.itemSize)));\n  this.newVisibleEnd = this.newStartIndex + containerLength + NUM_EXTRA;\n  this.newEndIndex = Math.min(itemsLength, this.newVisibleEnd);\n  this.newStartIndex = Math.max(0, this.newStartIndex - NUM_EXTRA);\n};\n\n/**\n * This VirtualRepeatModelArrayLike class enforces the interface requirements\n * for infinite scrolling within a mdVirtualRepeatContainer.\n *\n * @param {Object} model An object with this interface must implement the following interface with\n * two (2) methods:\n *\n * getItemAtIndex: function(index) -> item at that index or null if it is not yet\n *     loaded (It should start downloading the item in that case).\n *\n * getLength: function() -> number The data length to which the repeater container\n *     should be sized. Ideally, when the count is known, this method should return it.\n *     Otherwise, return a higher number than the currently loaded items to produce an\n *     infinite-scroll behavior.\n *\n * @usage\n * <hljs lang=\"html\">\n *  <md-virtual-repeat-container md-orient-horizontal>\n *    <div md-virtual-repeat=\"i in items\" md-on-demand>\n *      Hello {{i}}!\n *    </div>\n *  </md-virtual-repeat-container>\n * </hljs>\n *\n */\nfunction VirtualRepeatModelArrayLike(model) {\n  if (!angular.isFunction(model.getItemAtIndex) ||\n      !angular.isFunction(model.getLength)) {\n    throw Error('When md-on-demand is enabled, the Object passed to md-virtual-repeat must ' +\n        'implement functions getItemAtIndex() and getLength().');\n  }\n\n  this.model = model;\n}\n\n/**\n * @param {number} start\n * @param {number} end\n */\nVirtualRepeatModelArrayLike.prototype.$$includeIndexes = function(start, end) {\n  for (var i = start; i < end; i++) {\n    if (!this.hasOwnProperty(i)) {\n      this[i] = this.model.getItemAtIndex(i);\n    }\n  }\n  this.length = this.model.getLength();\n};\n\n/**\n * @ngdoc directive\n * @name mdForceHeight\n * @module material.components.virtualRepeat\n * @restrict A\n * @description\n *\n * Force an element to have a certain `px` height. This is used in place of a style tag in order to\n * conform to the\n * <a href=\"https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/script-src\">\n *   Content Security Policy</a> regarding `unsafe-inline` `<style>` tags.\n *\n * This directive is related to <a ng-href=\"api/directive/mdVirtualRepeat\">mdVirtualRepeat</a>.\n *\n * @usage\n * <hljs lang=\"html\">\n *   <div md-force-height=\"'100px'\"></div>\n * </hljs>\n */\nfunction ForceHeightDirective($mdUtil) {\n  return {\n    restrict: 'A',\n    link: function(scope, element, attrs) {\n      var height = scope.$eval(attrs.mdForceHeight) || null;\n\n      if (height && element) {\n        element[0].style.height = height;\n      }\n    }\n  };\n}\nForceHeightDirective.$inject = ['$mdUtil'];\n\n})();\n(function(){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.whiteframe\n */\nMdWhiteframeDirective.$inject = [\"$log\"];\nangular\n  .module('material.components.whiteframe', ['material.core'])\n  .directive('mdWhiteframe', MdWhiteframeDirective);\n\n/**\n * @ngdoc directive\n * @module material.components.whiteframe\n * @name mdWhiteframe\n *\n * @description\n * The md-whiteframe directive allows you to apply an elevation shadow to an element.\n *\n * The attribute values needs to be a number between 1 and 24 or -1.\n * When set to -1 no style is applied.\n *\n * ### Notes\n * - If there is no value specified it defaults to 4dp.\n * - If the value is not valid it defaults to 4dp.\n\n * @usage\n * <hljs lang=\"html\">\n * <div md-whiteframe=\"3\">\n *   <span>Elevation of 3dp</span>\n * </div>\n * </hljs>\n *\n * <hljs lang=\"html\">\n * <div md-whiteframe=\"-1\">\n *   <span>No elevation shadow applied</span>\n * </div>\n * </hljs>\n *\n * <hljs lang=\"html\">\n * <div ng-init=\"elevation = 5\" md-whiteframe=\"{{elevation}}\">\n *   <span>Elevation of 5dp with an interpolated value</span>\n * </div>\n * </hljs>\n */\nfunction MdWhiteframeDirective($log) {\n  var DISABLE_DP = -1;\n  var MIN_DP = 1;\n  var MAX_DP = 24;\n  var DEFAULT_DP = 4;\n\n  return {\n    link: postLink\n  };\n\n  function postLink(scope, element, attr) {\n    var oldClass = '';\n\n    attr.$observe('mdWhiteframe', function(elevation) {\n      elevation = parseInt(elevation, 10) || DEFAULT_DP;\n\n      if (elevation != DISABLE_DP && (elevation > MAX_DP || elevation < MIN_DP)) {\n        $log.warn('md-whiteframe attribute value is invalid. It should be a number between ' + MIN_DP + ' and ' + MAX_DP, element[0]);\n        elevation = DEFAULT_DP;\n      }\n\n      var newClass = elevation == DISABLE_DP ? '' : 'md-whiteframe-' + elevation + 'dp';\n      attr.$updateClass(newClass, oldClass);\n      oldClass = newClass;\n    });\n  }\n}\n\n\n})();\n(function(){ \nangular.module(\"material.core\").constant(\"$MD_THEME_CSS\", \"md-autocomplete.md-THEME_NAME-theme{background:\\\"{{background-hue-1}}\\\"}md-autocomplete.md-THEME_NAME-theme[disabled]:not([md-floating-label]){background:\\\"{{background-hue-2}}\\\"}md-autocomplete.md-THEME_NAME-theme button md-icon path{fill:\\\"{{background-600}}\\\"}md-autocomplete.md-THEME_NAME-theme button:after{background:\\\"{{background-600-0.3}}\\\"}md-autocomplete.md-THEME_NAME-theme input{color:\\\"{{foreground-1}}\\\"}md-autocomplete.md-THEME_NAME-theme.md-accent md-input-container.md-input-focused .md-input{border-color:\\\"{{accent-color}}\\\"}md-autocomplete.md-THEME_NAME-theme.md-accent md-input-container.md-input-focused label,md-autocomplete.md-THEME_NAME-theme.md-accent md-input-container.md-input-focused md-icon{color:\\\"{{accent-color}}\\\"}md-autocomplete.md-THEME_NAME-theme.md-accent md-progress-linear .md-container{background-color:\\\"{{accent-100}}\\\"}md-autocomplete.md-THEME_NAME-theme.md-accent md-progress-linear .md-bar{background-color:\\\"{{accent-color}}\\\"}md-autocomplete.md-THEME_NAME-theme.md-warn md-input-container.md-input-focused .md-input{border-color:\\\"{{warn-A700}}\\\"}md-autocomplete.md-THEME_NAME-theme.md-warn md-input-container.md-input-focused label,md-autocomplete.md-THEME_NAME-theme.md-warn md-input-container.md-input-focused md-icon{color:\\\"{{warn-A700}}\\\"}md-autocomplete.md-THEME_NAME-theme.md-warn md-progress-linear .md-container{background-color:\\\"{{warn-100}}\\\"}md-autocomplete.md-THEME_NAME-theme.md-warn md-progress-linear .md-bar{background-color:\\\"{{warn-color}}\\\"}.md-autocomplete-standard-list-container.md-THEME_NAME-theme,.md-autocomplete-suggestions-container.md-THEME_NAME-theme{background:\\\"{{background-hue-1}}\\\"}.md-autocomplete-standard-list-container.md-THEME_NAME-theme .md-autocomplete-suggestion,.md-autocomplete-suggestions-container.md-THEME_NAME-theme .md-autocomplete-suggestion{color:\\\"{{foreground-1}}\\\"}.md-autocomplete-standard-list-container.md-THEME_NAME-theme .md-autocomplete-suggestion.selected,.md-autocomplete-standard-list-container.md-THEME_NAME-theme .md-autocomplete-suggestion:hover,.md-autocomplete-suggestions-container.md-THEME_NAME-theme .md-autocomplete-suggestion.selected,.md-autocomplete-suggestions-container.md-THEME_NAME-theme .md-autocomplete-suggestion:hover{background:\\\"{{background-500-0.18}}\\\"}md-backdrop{background-color:\\\"{{background-900-0.0}}\\\"}md-backdrop.md-opaque.md-THEME_NAME-theme{background-color:\\\"{{background-900-1.0}}\\\"}md-bottom-sheet.md-THEME_NAME-theme{background-color:\\\"{{background-color}}\\\";border-top-color:\\\"{{background-hue-3}}\\\"}md-bottom-sheet.md-THEME_NAME-theme.md-list md-list-item{color:\\\"{{foreground-1}}\\\"}md-bottom-sheet.md-THEME_NAME-theme .md-subheader{background-color:\\\"{{background-color}}\\\";color:\\\"{{foreground-1}}\\\"}.md-button.md-THEME_NAME-theme:not([disabled]):hover{background-color:\\\"{{background-500-0.2}}\\\"}.md-button.md-THEME_NAME-theme:not([disabled]).md-focused{background-color:\\\"{{background-500-0.2}}\\\"}.md-button.md-THEME_NAME-theme:not([disabled]).md-icon-button:hover{background-color:transparent}.md-button.md-THEME_NAME-theme.md-fab{background-color:\\\"{{accent-color}}\\\";color:\\\"{{accent-contrast}}\\\"}.md-button.md-THEME_NAME-theme.md-fab md-icon{color:\\\"{{accent-contrast}}\\\"}.md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover{background-color:\\\"{{accent-A700}}\\\"}.md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused{background-color:\\\"{{accent-A700}}\\\"}.md-button.md-THEME_NAME-theme.md-primary{color:\\\"{{primary-color}}\\\"}.md-button.md-THEME_NAME-theme.md-primary.md-fab,.md-button.md-THEME_NAME-theme.md-primary.md-raised{color:\\\"{{primary-contrast}}\\\";background-color:\\\"{{primary-color}}\\\"}.md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]) md-icon,.md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]) md-icon{color:\\\"{{primary-contrast}}\\\"}.md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]):hover,.md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]):hover{background-color:\\\"{{primary-600}}\\\"}.md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]).md-focused,.md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]).md-focused{background-color:\\\"{{primary-600}}\\\"}.md-button.md-THEME_NAME-theme.md-primary:not([disabled]) md-icon{color:\\\"{{primary-color}}\\\"}.md-button.md-THEME_NAME-theme.md-raised{color:\\\"{{background-900}}\\\";background-color:\\\"{{background-50}}\\\"}.md-button.md-THEME_NAME-theme.md-raised:not([disabled]) md-icon{color:\\\"{{background-900}}\\\"}.md-button.md-THEME_NAME-theme.md-raised:not([disabled]):hover{background-color:\\\"{{background-50}}\\\"}.md-button.md-THEME_NAME-theme.md-raised:not([disabled]).md-focused{background-color:\\\"{{background-200}}\\\"}.md-button.md-THEME_NAME-theme.md-warn{color:\\\"{{warn-color}}\\\"}.md-button.md-THEME_NAME-theme.md-warn.md-fab,.md-button.md-THEME_NAME-theme.md-warn.md-raised{color:\\\"{{warn-contrast}}\\\";background-color:\\\"{{warn-color}}\\\"}.md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]) md-icon,.md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]) md-icon{color:\\\"{{warn-contrast}}\\\"}.md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]):hover,.md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]):hover{background-color:\\\"{{warn-600}}\\\"}.md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]).md-focused,.md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]).md-focused{background-color:\\\"{{warn-600}}\\\"}.md-button.md-THEME_NAME-theme.md-warn:not([disabled]) md-icon{color:\\\"{{warn-color}}\\\"}.md-button.md-THEME_NAME-theme.md-accent{color:\\\"{{accent-color}}\\\"}.md-button.md-THEME_NAME-theme.md-accent.md-fab,.md-button.md-THEME_NAME-theme.md-accent.md-raised{color:\\\"{{accent-contrast}}\\\";background-color:\\\"{{accent-color}}\\\"}.md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]) md-icon,.md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]) md-icon{color:\\\"{{accent-contrast}}\\\"}.md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]):hover,.md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]):hover{background-color:\\\"{{accent-A700}}\\\"}.md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]).md-focused,.md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]).md-focused{background-color:\\\"{{accent-A700}}\\\"}.md-button.md-THEME_NAME-theme.md-accent:not([disabled]) md-icon{color:\\\"{{accent-color}}\\\"}.md-button.md-THEME_NAME-theme.md-accent[disabled],.md-button.md-THEME_NAME-theme.md-fab[disabled],.md-button.md-THEME_NAME-theme.md-raised[disabled],.md-button.md-THEME_NAME-theme.md-warn[disabled],.md-button.md-THEME_NAME-theme[disabled]{color:\\\"{{foreground-3}}\\\";cursor:default}.md-button.md-THEME_NAME-theme.md-accent[disabled] md-icon,.md-button.md-THEME_NAME-theme.md-fab[disabled] md-icon,.md-button.md-THEME_NAME-theme.md-raised[disabled] md-icon,.md-button.md-THEME_NAME-theme.md-warn[disabled] md-icon,.md-button.md-THEME_NAME-theme[disabled] md-icon{color:\\\"{{foreground-3}}\\\"}.md-button.md-THEME_NAME-theme.md-fab[disabled],.md-button.md-THEME_NAME-theme.md-raised[disabled]{background-color:\\\"{{foreground-4}}\\\"}.md-button.md-THEME_NAME-theme[disabled]{background-color:transparent}._md a.md-THEME_NAME-theme:not(.md-button).md-primary{color:\\\"{{primary-color}}\\\"}._md a.md-THEME_NAME-theme:not(.md-button).md-primary:hover{color:\\\"{{primary-700}}\\\"}._md a.md-THEME_NAME-theme:not(.md-button).md-accent{color:\\\"{{accent-color}}\\\"}._md a.md-THEME_NAME-theme:not(.md-button).md-accent:hover{color:\\\"{{accent-A700}}\\\"}._md a.md-THEME_NAME-theme:not(.md-button).md-warn{color:\\\"{{warn-color}}\\\"}._md a.md-THEME_NAME-theme:not(.md-button).md-warn:hover{color:\\\"{{warn-700}}\\\"}md-card.md-THEME_NAME-theme{color:\\\"{{foreground-1}}\\\";background-color:\\\"{{background-hue-1}}\\\";border-radius:2px}md-card.md-THEME_NAME-theme .md-card-image{border-radius:2px 2px 0 0}md-card.md-THEME_NAME-theme md-card-header md-card-avatar md-icon{color:\\\"{{background-color}}\\\";background-color:\\\"{{foreground-3}}\\\"}md-card.md-THEME_NAME-theme md-card-header md-card-header-text .md-subhead{color:\\\"{{foreground-2}}\\\"}md-card.md-THEME_NAME-theme md-card-title md-card-title-text:not(:only-child) .md-subhead{color:\\\"{{foreground-2}}\\\"}md-checkbox.md-THEME_NAME-theme .md-ripple{color:\\\"{{accent-A700}}\\\"}md-checkbox.md-THEME_NAME-theme.md-checked .md-ripple{color:\\\"{{background-600}}\\\"}md-checkbox.md-THEME_NAME-theme.md-checked.md-focused .md-container:before{background-color:\\\"{{accent-color-0.26}}\\\"}md-checkbox.md-THEME_NAME-theme .md-ink-ripple{color:\\\"{{foreground-2}}\\\"}md-checkbox.md-THEME_NAME-theme.md-checked .md-ink-ripple{color:\\\"{{accent-color-0.87}}\\\"}md-checkbox.md-THEME_NAME-theme:not(.md-checked) .md-icon{border-color:\\\"{{foreground-2}}\\\"}md-checkbox.md-THEME_NAME-theme.md-checked .md-icon{background-color:\\\"{{accent-color-0.87}}\\\"}md-checkbox.md-THEME_NAME-theme.md-checked .md-icon:after{border-color:\\\"{{background-default}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-ripple{color:\\\"{{primary-600}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ripple{color:\\\"{{background-600}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-ink-ripple{color:\\\"{{foreground-2}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple{color:\\\"{{primary-color-0.87}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary:not(.md-checked) .md-icon{border-color:\\\"{{foreground-2}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-icon{background-color:\\\"{{primary-color-0.87}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked.md-focused .md-container:before{background-color:\\\"{{primary-color-0.26}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-icon:after{border-color:\\\"{{primary-contrast-0.87}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-indeterminate[disabled] .md-container{color:\\\"{{foreground-3}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn .md-ripple{color:\\\"{{warn-600}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn .md-ink-ripple{color:\\\"{{foreground-2}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple{color:\\\"{{warn-color-0.87}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn:not(.md-checked) .md-icon{border-color:\\\"{{foreground-2}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-icon{background-color:\\\"{{warn-color-0.87}}\\\"}md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked.md-focused:not([disabled]) .md-container:before{background-color:\\\"{{warn-color-0.26}}\\\"}md-checkbox.md-THEME_NAME-theme[disabled]:not(.md-checked) .md-icon{border-color:\\\"{{foreground-3}}\\\"}md-checkbox.md-THEME_NAME-theme[disabled].md-checked .md-icon{background-color:\\\"{{foreground-3}}\\\"}md-checkbox.md-THEME_NAME-theme[disabled] .md-label{color:\\\"{{foreground-3}}\\\"}md-chips.md-THEME_NAME-theme .md-chips{box-shadow:0 1px \\\"{{foreground-4}}\\\"}md-chips.md-THEME_NAME-theme .md-chips.md-focused{box-shadow:0 2px \\\"{{primary-color}}\\\"}md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input{color:\\\"{{foreground-1}}\\\"}md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input::-webkit-input-placeholder{color:\\\"{{foreground-3}}\\\"}md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input:-ms-input-placeholder{color:\\\"{{foreground-3}}\\\"}md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input::-ms-input-placeholder{color:\\\"{{foreground-3}}\\\"}md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input::placeholder{color:\\\"{{foreground-3}}\\\"}md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input:-moz-placeholder,md-chips.md-THEME_NAME-theme .md-chips .md-chip-input-container input::-moz-placeholder{color:\\\"{{foreground-3}}\\\";opacity:1}md-chips.md-THEME_NAME-theme md-chip{background:\\\"{{background-300}}\\\";color:\\\"{{background-800}}\\\"}md-chips.md-THEME_NAME-theme md-chip md-icon{color:\\\"{{background-700}}\\\"}md-chips.md-THEME_NAME-theme md-chip.md-focused{background:\\\"{{primary-color}}\\\";color:\\\"{{primary-contrast}}\\\"}md-chips.md-THEME_NAME-theme md-chip.md-focused md-icon{color:\\\"{{primary-contrast}}\\\"}md-chips.md-THEME_NAME-theme md-chip._md-chip-editing{background:transparent;color:\\\"{{background-800}}\\\"}md-chips.md-THEME_NAME-theme .md-chip-remove-container button.md-chip-remove md-icon,md-chips.md-THEME_NAME-theme .md-chip-remove-container buttonmd-chip-remove md-icon{color:\\\"{{foreground-2}}\\\";fill:\\\"{{foreground-2}}\\\"}.md-contact-suggestion span.md-contact-email{color:\\\"{{background-400}}\\\"}md-content.md-THEME_NAME-theme{color:\\\"{{foreground-1}}\\\";background-color:\\\"{{background-default}}\\\"}.md-THEME_NAME-theme .md-calendar{background:\\\"{{background-hue-1}}\\\";color:\\\"{{foreground-1-0.87}}\\\"}.md-THEME_NAME-theme .md-calendar tr:last-child td{border-bottom-color:\\\"{{background-hue-2}}\\\"}.md-THEME_NAME-theme .md-calendar-day-header{background:\\\"{{background-500-0.32}}\\\";color:\\\"{{foreground-1-0.87}}\\\"}.md-THEME_NAME-theme .md-calendar-date.md-calendar-date-today .md-calendar-date-selection-indicator{border:1px solid \\\"{{primary-500}}\\\"}.md-THEME_NAME-theme .md-calendar-date.md-calendar-date-today.md-calendar-date-disabled{color:\\\"{{primary-500-0.6}}\\\"}.md-calendar-date.md-focus .md-THEME_NAME-theme .md-calendar-date-selection-indicator,.md-THEME_NAME-theme .md-calendar-date-selection-indicator:hover{background:\\\"{{background-500-0.32}}\\\"}.md-THEME_NAME-theme .md-calendar-date.md-calendar-selected-date .md-calendar-date-selection-indicator,.md-THEME_NAME-theme .md-calendar-date.md-focus.md-calendar-selected-date .md-calendar-date-selection-indicator{background:\\\"{{primary-500}}\\\";color:\\\"{{primary-500-contrast}}\\\";border-color:transparent}.md-THEME_NAME-theme .md-calendar-date-disabled,.md-THEME_NAME-theme .md-calendar-month-label-disabled{color:\\\"{{foreground-3}}\\\"}.md-THEME_NAME-theme .md-calendar-month-label md-icon,.md-THEME_NAME-theme .md-datepicker-input{color:\\\"{{foreground-1}}\\\"}.md-THEME_NAME-theme .md-datepicker-input::-webkit-input-placeholder{color:\\\"{{foreground-3}}\\\"}.md-THEME_NAME-theme .md-datepicker-input:-ms-input-placeholder{color:\\\"{{foreground-3}}\\\"}.md-THEME_NAME-theme .md-datepicker-input::-ms-input-placeholder{color:\\\"{{foreground-3}}\\\"}.md-THEME_NAME-theme .md-datepicker-input::placeholder{color:\\\"{{foreground-3}}\\\"}.md-THEME_NAME-theme .md-datepicker-input:-moz-placeholder,.md-THEME_NAME-theme .md-datepicker-input::-moz-placeholder{color:\\\"{{foreground-3}}\\\";opacity:1}.md-THEME_NAME-theme .md-datepicker-input-container{border-bottom-color:\\\"{{foreground-4}}\\\"}.md-THEME_NAME-theme .md-datepicker-input-container.md-datepicker-focused{border-bottom-color:\\\"{{primary-color}}\\\"}.md-accent .md-THEME_NAME-theme .md-datepicker-input-container.md-datepicker-focused{border-bottom-color:\\\"{{accent-color}}\\\"}.md-THEME_NAME-theme .md-datepicker-input-container.md-datepicker-invalid,.md-warn .md-THEME_NAME-theme .md-datepicker-input-container.md-datepicker-focused{border-bottom-color:\\\"{{warn-A700}}\\\"}.md-THEME_NAME-theme .md-datepicker-calendar-pane{border-color:\\\"{{background-hue-1}}\\\"}.md-THEME_NAME-theme .md-datepicker-triangle-button .md-datepicker-expand-triangle{border-top-color:\\\"{{foreground-2}}\\\"}.md-THEME_NAME-theme .md-datepicker-open .md-datepicker-calendar-icon{color:\\\"{{primary-color}}\\\"}.md-accent .md-THEME_NAME-theme .md-datepicker-open .md-datepicker-calendar-icon,.md-THEME_NAME-theme .md-datepicker-open.md-accent .md-datepicker-calendar-icon{color:\\\"{{accent-color}}\\\"}.md-THEME_NAME-theme .md-datepicker-open.md-warn .md-datepicker-calendar-icon,.md-warn .md-THEME_NAME-theme .md-datepicker-open .md-datepicker-calendar-icon{color:\\\"{{warn-A700}}\\\"}.md-THEME_NAME-theme .md-datepicker-calendar{background:\\\"{{background-hue-1}}\\\"}.md-THEME_NAME-theme .md-datepicker-input-mask-opaque{box-shadow:0 0 0 9999px \\\"{{background-hue-1}}\\\"}.md-THEME_NAME-theme .md-datepicker-open .md-datepicker-input-container{background:\\\"{{background-hue-1}}\\\"}md-dialog.md-THEME_NAME-theme{border-radius:4px;background-color:\\\"{{background-hue-1}}\\\";color:\\\"{{foreground-1}}\\\"}md-dialog.md-THEME_NAME-theme.md-content-overflow md-dialog-actions{border-top-color:\\\"{{foreground-4}}\\\"}md-divider.md-THEME_NAME-theme{border-color:\\\"{{foreground-4}}\\\"}md-fab-speed-dial.md-THEME_NAME-theme md-fab-trigger .md-fab.md-button[disabled]{background-color:\\\"{{foreground-4}}\\\"}md-fab-speed-dial.md-THEME_NAME-theme md-fab-actions .md-fab-action-item .md-button.md-fab.md-raised.md-mini.md-focused,md-fab-speed-dial.md-THEME_NAME-theme md-fab-actions .md-fab-action-item .md-button.md-fab.md-raised.md-mini:hover{background-color:\\\"{{background-500}}\\\"}md-icon.md-THEME_NAME-theme{color:\\\"{{foreground-2}}\\\"}md-icon.md-THEME_NAME-theme.md-primary{color:\\\"{{primary-color}}\\\"}md-icon.md-THEME_NAME-theme.md-accent{color:\\\"{{accent-color}}\\\"}md-icon.md-THEME_NAME-theme.md-warn{color:\\\"{{warn-color}}\\\"}md-input-container.md-THEME_NAME-theme .md-input{color:\\\"{{background-default-contrast}}\\\";border-color:\\\"{{background-default-contrast-divider}}\\\"}md-input-container.md-THEME_NAME-theme .md-input::-webkit-input-placeholder{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme .md-input:-ms-input-placeholder{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme .md-input::-ms-input-placeholder{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme .md-input::placeholder{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme .md-input:-moz-placeholder,md-input-container.md-THEME_NAME-theme .md-input::-moz-placeholder{color:\\\"{{background-default-contrast-secondary}}\\\";opacity:1}md-input-container.md-THEME_NAME-theme>md-icon{color:\\\"{{background-default-contrast}}\\\"}md-input-container.md-THEME_NAME-theme .md-placeholder,md-input-container.md-THEME_NAME-theme label{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme label.md-required:after{color:\\\"{{warn-A700}}\\\"}md-input-container.md-THEME_NAME-theme:not(.md-input-focused):not(.md-input-invalid) label.md-required:after{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme .md-input-message-animation,md-input-container.md-THEME_NAME-theme .md-input-messages-animation{color:\\\"{{warn-A700}}\\\"}md-input-container.md-THEME_NAME-theme .md-input-message-animation .md-char-counter,md-input-container.md-THEME_NAME-theme .md-input-messages-animation .md-char-counter{color:\\\"{{background-default-contrast}}\\\"}md-input-container.md-THEME_NAME-theme.md-input-focused .md-input::-webkit-input-placeholder{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme.md-input-focused .md-input:-ms-input-placeholder{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme.md-input-focused .md-input::-ms-input-placeholder{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme.md-input-focused .md-input::placeholder{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme.md-input-focused .md-input:-moz-placeholder,md-input-container.md-THEME_NAME-theme.md-input-focused .md-input::-moz-placeholder{color:\\\"{{background-default-contrast-secondary}}\\\";opacity:1}md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-has-value label{color:\\\"{{background-default-contrast-secondary}}\\\"}md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused .md-input,md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-resized .md-input{border-color:\\\"{{primary-color}}\\\"}md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused label,md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused md-icon{color:\\\"{{primary-color}}\\\"}md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent .md-input{border-color:\\\"{{accent-color}}\\\"}md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent label,md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent md-icon{color:\\\"{{accent-color}}\\\"}md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn .md-input{border-color:\\\"{{warn-A700}}\\\"}md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn label,md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn md-icon{color:\\\"{{warn-A700}}\\\"}md-input-container.md-THEME_NAME-theme.md-input-invalid .md-input{border-color:\\\"{{warn-A700}}\\\"}md-input-container.md-THEME_NAME-theme.md-input-invalid .md-char-counter,md-input-container.md-THEME_NAME-theme.md-input-invalid .md-input-message-animation,md-input-container.md-THEME_NAME-theme.md-input-invalid label{color:\\\"{{warn-A700}}\\\"}[disabled] md-input-container.md-THEME_NAME-theme .md-input,md-input-container.md-THEME_NAME-theme .md-input[disabled]{border-bottom-color:transparent;color:\\\"{{background-default-contrast-disabled}}\\\";background-image:linear-gradient(90deg,\\\"{{background-default-contrast-disabled}}\\\" 0,\\\"{{background-default-contrast-disabled}}\\\" 33%,transparent 0);background-image:-ms-linear-gradient(left,transparent 0,\\\"{{background-default-contrast-disabled}}\\\" 100%)}md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text h3,md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text h4,md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text h3,md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text h4{color:\\\"{{foreground-1}}\\\"}md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text p,md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text p{color:\\\"{{foreground-2}}\\\"}md-list.md-THEME_NAME-theme .md-proxy-focus.md-focused div.md-no-style{background-color:\\\"{{background-100}}\\\"}md-list.md-THEME_NAME-theme md-list-item .md-avatar-icon{background-color:\\\"{{foreground-3}}\\\";color:\\\"{{background-color}}\\\"}md-list.md-THEME_NAME-theme md-list-item>md-icon{color:\\\"{{foreground-2}}\\\"}md-list.md-THEME_NAME-theme md-list-item>md-icon.md-highlight{color:\\\"{{primary-color}}\\\"}md-list.md-THEME_NAME-theme md-list-item>md-icon.md-highlight.md-accent{color:\\\"{{accent-color}}\\\"}md-menu-content.md-THEME_NAME-theme{background-color:\\\"{{background-hue-1}}\\\"}md-menu-content.md-THEME_NAME-theme md-menu-item{color:\\\"{{foreground-1}}\\\"}md-menu-content.md-THEME_NAME-theme md-menu-item md-icon{color:\\\"{{foreground-2}}\\\"}md-menu-content.md-THEME_NAME-theme md-menu-item .md-button[disabled]{color:\\\"{{foreground-3}}\\\"}md-menu-content.md-THEME_NAME-theme md-menu-item .md-button[disabled] md-icon{color:\\\"{{foreground-3}}\\\"}md-menu-content.md-THEME_NAME-theme md-menu-divider{background-color:\\\"{{foreground-4}}\\\"}md-menu-bar.md-THEME_NAME-theme>button.md-button{color:\\\"{{foreground-1}}\\\";border-radius:2px}md-menu-bar.md-THEME_NAME-theme md-menu>button{color:\\\"{{foreground-1}}\\\"}md-menu-bar.md-THEME_NAME-theme md-menu.md-open>button,md-menu-bar.md-THEME_NAME-theme md-menu>button:focus{outline:none;background-color:\\\"{{ background-500-0.18}}\\\"}md-menu-bar.md-THEME_NAME-theme.md-open:not(.md-keyboard-mode) md-menu:hover>button{background-color:\\\"{{ background-500-0.18}}\\\"}md-menu-bar.md-THEME_NAME-theme:not(.md-keyboard-mode):not(.md-open) md-menu button:focus,md-menu-bar.md-THEME_NAME-theme:not(.md-keyboard-mode):not(.md-open) md-menu button:hover{background:transparent}md-menu-content.md-THEME_NAME-theme .md-menu>.md-button:after{color:\\\"{{foreground-2}}\\\"}md-menu-content.md-THEME_NAME-theme .md-menu.md-open>.md-button{background-color:\\\"{{ background-500-0.18}}\\\"}md-toolbar.md-THEME_NAME-theme.md-menu-toolbar{background-color:\\\"{{background-hue-1}}\\\";color:\\\"{{foreground-1}}\\\"}md-toolbar.md-THEME_NAME-theme.md-menu-toolbar md-toolbar-filler{background-color:\\\"{{primary-color}}\\\";color:\\\"{{primary-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme.md-menu-toolbar md-toolbar-filler md-icon{color:\\\"{{primary-contrast}}\\\"}md-nav-bar.md-THEME_NAME-theme .md-nav-bar{background-color:transparent;border-color:\\\"{{foreground-4}}\\\"}md-nav-bar.md-THEME_NAME-theme .md-button._md-nav-button.md-unselected{color:\\\"{{foreground-2}}\\\"}md-nav-bar.md-THEME_NAME-theme .md-button._md-nav-button[disabled]{color:\\\"{{foreground-3}}\\\"}md-nav-bar.md-THEME_NAME-theme md-nav-ink-bar{color:\\\"{{accent-color}}\\\";background:\\\"{{accent-color}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-accent>.md-nav-bar{background-color:\\\"{{accent-color}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-accent>.md-nav-bar .md-button._md-nav-button{color:\\\"{{accent-A100}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-accent>.md-nav-bar .md-button._md-nav-button.md-active,md-nav-bar.md-THEME_NAME-theme.md-accent>.md-nav-bar .md-button._md-nav-button.md-focused{color:\\\"{{accent-contrast}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-accent>.md-nav-bar .md-button._md-nav-button.md-focused{background:\\\"{{accent-contrast-0.1}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-accent>.md-nav-bar md-nav-ink-bar{color:\\\"{{primary-600-1}}\\\";background:\\\"{{primary-600-1}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-warn>.md-nav-bar{background-color:\\\"{{warn-color}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-warn>.md-nav-bar .md-button._md-nav-button{color:\\\"{{warn-100}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-warn>.md-nav-bar .md-button._md-nav-button.md-active,md-nav-bar.md-THEME_NAME-theme.md-warn>.md-nav-bar .md-button._md-nav-button.md-focused{color:\\\"{{warn-contrast}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-warn>.md-nav-bar .md-button._md-nav-button.md-focused{background:\\\"{{warn-contrast-0.1}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-primary>.md-nav-bar{background-color:\\\"{{primary-color}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-primary>.md-nav-bar .md-button._md-nav-button{color:\\\"{{primary-100}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-primary>.md-nav-bar .md-button._md-nav-button.md-active,md-nav-bar.md-THEME_NAME-theme.md-primary>.md-nav-bar .md-button._md-nav-button.md-focused{color:\\\"{{primary-contrast}}\\\"}md-nav-bar.md-THEME_NAME-theme.md-primary>.md-nav-bar .md-button._md-nav-button.md-focused{background:\\\"{{primary-contrast-0.1}}\\\"}md-toolbar>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar{background-color:\\\"{{primary-color}}\\\"}md-toolbar>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button{color:\\\"{{primary-100}}\\\"}md-toolbar>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button.md-active,md-toolbar>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button.md-focused{color:\\\"{{primary-contrast}}\\\"}md-toolbar>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button.md-focused{background:\\\"{{primary-contrast-0.1}}\\\"}md-toolbar.md-accent>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar{background-color:\\\"{{accent-color}}\\\"}md-toolbar.md-accent>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button{color:\\\"{{accent-A100}}\\\"}md-toolbar.md-accent>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button.md-active,md-toolbar.md-accent>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button.md-focused{color:\\\"{{accent-contrast}}\\\"}md-toolbar.md-accent>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button.md-focused{background:\\\"{{accent-contrast-0.1}}\\\"}md-toolbar.md-accent>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar md-nav-ink-bar{color:\\\"{{primary-600-1}}\\\";background:\\\"{{primary-600-1}}\\\"}md-toolbar.md-warn>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar{background-color:\\\"{{warn-color}}\\\"}md-toolbar.md-warn>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button{color:\\\"{{warn-100}}\\\"}md-toolbar.md-warn>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button.md-active,md-toolbar.md-warn>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button.md-focused{color:\\\"{{warn-contrast}}\\\"}md-toolbar.md-warn>md-nav-bar.md-THEME_NAME-theme>.md-nav-bar .md-button._md-nav-button.md-focused{background:\\\"{{warn-contrast-0.1}}\\\"}._md-panel-backdrop.md-THEME_NAME-theme{background-color:\\\"{{background-900-1.0}}\\\"}md-progress-circular.md-THEME_NAME-theme path{stroke:\\\"{{primary-color}}\\\"}md-progress-circular.md-THEME_NAME-theme.md-warn path{stroke:\\\"{{warn-color}}\\\"}md-progress-circular.md-THEME_NAME-theme.md-accent path{stroke:\\\"{{accent-color}}\\\"}md-progress-linear.md-THEME_NAME-theme .md-container{background-color:\\\"{{primary-100}}\\\"}md-progress-linear.md-THEME_NAME-theme .md-bar{background-color:\\\"{{primary-color}}\\\"}md-progress-linear.md-THEME_NAME-theme.md-warn .md-container{background-color:\\\"{{warn-100}}\\\"}md-progress-linear.md-THEME_NAME-theme.md-warn .md-bar{background-color:\\\"{{warn-color}}\\\"}md-progress-linear.md-THEME_NAME-theme.md-accent .md-container{background-color:\\\"{{accent-100}}\\\"}md-progress-linear.md-THEME_NAME-theme.md-accent .md-bar{background-color:\\\"{{accent-color}}\\\"}md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-primary .md-bar1{background-color:\\\"{{primary-100}}\\\"}md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-primary .md-dashed:before{background:radial-gradient(\\\"{{primary-100}}\\\" 0,\\\"{{primary-100}}\\\" 16%,transparent 42%)}md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-warn .md-bar1{background-color:\\\"{{warn-100}}\\\"}md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-warn .md-dashed:before{background:radial-gradient(\\\"{{warn-100}}\\\" 0,\\\"{{warn-100}}\\\" 16%,transparent 42%)}md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-accent .md-bar1{background-color:\\\"{{accent-100}}\\\"}md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-accent .md-dashed:before{background:radial-gradient(\\\"{{accent-100}}\\\" 0,\\\"{{accent-100}}\\\" 16%,transparent 42%)}md-radio-button.md-THEME_NAME-theme .md-off{border-color:\\\"{{foreground-2}}\\\"}md-radio-button.md-THEME_NAME-theme .md-on{background-color:\\\"{{accent-color-0.87}}\\\"}md-radio-button.md-THEME_NAME-theme.md-checked .md-off{border-color:\\\"{{accent-color-0.87}}\\\"}md-radio-button.md-THEME_NAME-theme.md-checked .md-ink-ripple{color:\\\"{{accent-color-0.87}}\\\"}md-radio-button.md-THEME_NAME-theme .md-container .md-ripple{color:\\\"{{accent-A700}}\\\"}md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-on,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-on,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-on,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-on{background-color:\\\"{{primary-color-0.87}}\\\"}md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-off,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-off,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-off,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-off,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-off{border-color:\\\"{{primary-color-0.87}}\\\"}md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-ink-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-ink-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-ink-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-ink-ripple{color:\\\"{{primary-color-0.87}}\\\"}md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-container .md-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-container .md-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-container .md-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-container .md-ripple{color:\\\"{{primary-600}}\\\"}md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-on,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-on,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-on,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-on{background-color:\\\"{{warn-color-0.87}}\\\"}md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-off,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-off,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-off,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-off,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-off,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-off{border-color:\\\"{{warn-color-0.87}}\\\"}md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-ink-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-ink-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-ink-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-ink-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-ink-ripple{color:\\\"{{warn-color-0.87}}\\\"}md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-container .md-ripple,md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-container .md-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-container .md-ripple,md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-container .md-ripple{color:\\\"{{warn-600}}\\\"}md-radio-button.md-THEME_NAME-theme[disabled],md-radio-group.md-THEME_NAME-theme[disabled]{color:\\\"{{foreground-3}}\\\"}md-radio-button.md-THEME_NAME-theme[disabled] .md-container .md-off,md-radio-group.md-THEME_NAME-theme[disabled] .md-container .md-off{border-color:\\\"{{foreground-3}}\\\"}md-radio-button.md-THEME_NAME-theme[disabled] .md-container .md-on,md-radio-group.md-THEME_NAME-theme[disabled] .md-container .md-on{border-color:\\\"{{foreground-3}}\\\"}md-radio-group.md-THEME_NAME-theme .md-checked .md-ink-ripple{color:\\\"{{accent-color-0.26}}\\\"}md-radio-group.md-THEME_NAME-theme .md-checked:not([disabled]).md-primary .md-ink-ripple,md-radio-group.md-THEME_NAME-theme.md-primary .md-checked:not([disabled]) .md-ink-ripple{color:\\\"{{primary-color-0.26}}\\\"}md-radio-group.md-THEME_NAME-theme.md-focused.ng-empty>md-radio-button:first-child .md-container:before{background-color:\\\"{{foreground-3-0.26}}\\\"}md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked .md-container:before{background-color:\\\"{{accent-color-0.26}}\\\"}md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked.md-primary .md-container:before,md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty).md-primary .md-checked .md-container:before{background-color:\\\"{{primary-color-0.26}}\\\"}md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked.md-warn .md-container:before,md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty).md-warn .md-checked .md-container:before{background-color:\\\"{{warn-color-0.26}}\\\"}md-input-container md-select.md-THEME_NAME-theme .md-select-value span:first-child:after{color:\\\"{{warn-A700}}\\\"}md-input-container:not(.md-input-focused):not(.md-input-invalid) md-select.md-THEME_NAME-theme .md-select-value span:first-child:after{color:\\\"{{foreground-3}}\\\"}md-input-container.md-input-focused:not(.md-input-has-value) md-select.md-THEME_NAME-theme .md-select-value{color:\\\"{{primary-color}}\\\"}md-input-container.md-input-focused:not(.md-input-has-value) md-select.md-THEME_NAME-theme .md-select-value.md-select-placeholder{color:\\\"{{primary-color}}\\\"}md-input-container.md-input-invalid md-select.md-THEME_NAME-theme .md-select-value{color:\\\"{{warn-A700}}\\\"!important;border-bottom-color:\\\"{{warn-A700}}\\\"!important}md-input-container.md-input-invalid md-select.md-THEME_NAME-theme.md-no-underline .md-select-value{border-bottom-color:transparent!important}md-input-container:not(.md-input-invalid).md-input-focused.md-accent .md-select-value{border-color:\\\"{{accent-color}}\\\"}md-input-container:not(.md-input-invalid).md-input-focused.md-accent .md-select-value span{color:\\\"{{accent-color}}\\\"}md-input-container:not(.md-input-invalid).md-input-focused.md-warn .md-select-value{border-color:\\\"{{warn-A700}}\\\"}md-input-container:not(.md-input-invalid).md-input-focused.md-warn .md-select-value span{color:\\\"{{warn-A700}}\\\"}md-select.md-THEME_NAME-theme[disabled] .md-select-value{border-bottom-color:transparent;background-image:linear-gradient(90deg,\\\"{{foreground-3}}\\\" 0,\\\"{{foreground-3}}\\\" 33%,transparent 0);background-image:-ms-linear-gradient(left,transparent 0,\\\"{{foreground-3}}\\\" 100%)}md-select.md-THEME_NAME-theme .md-select-value{border-bottom-color:\\\"{{foreground-4}}\\\"}md-select.md-THEME_NAME-theme .md-select-value.md-select-placeholder{color:\\\"{{foreground-3}}\\\"}md-select.md-THEME_NAME-theme .md-select-value span:first-child:after{color:\\\"{{warn-A700}}\\\"}md-select.md-THEME_NAME-theme.md-no-underline .md-select-value{border-bottom-color:transparent!important}md-select.md-THEME_NAME-theme.ng-invalid.ng-touched .md-select-value{color:\\\"{{warn-A700}}\\\"!important;border-bottom-color:\\\"{{warn-A700}}\\\"!important}md-select.md-THEME_NAME-theme.ng-invalid.ng-touched.md-no-underline .md-select-value{border-bottom-color:transparent!important}md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-value{border-bottom-color:\\\"{{primary-color}}\\\";color:\\\"{{ foreground-1 }}\\\"}md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-value.md-select-placeholder{color:\\\"{{ foreground-1 }}\\\"}md-select.md-THEME_NAME-theme:not([disabled]):focus.md-no-underline .md-select-value{border-bottom-color:transparent!important}md-select.md-THEME_NAME-theme:not([disabled]):focus.md-accent .md-select-value{border-bottom-color:\\\"{{accent-color}}\\\"}md-select.md-THEME_NAME-theme:not([disabled]):focus.md-warn .md-select-value{border-bottom-color:\\\"{{warn-color}}\\\"}md-select.md-THEME_NAME-theme[disabled] .md-select-value{color:\\\"{{foreground-3}}\\\"}md-select.md-THEME_NAME-theme[disabled] .md-select-value.md-select-placeholder{color:\\\"{{foreground-3}}\\\"}md-select.md-THEME_NAME-theme[disabled] .md-select-icon{color:\\\"{{foreground-3}}\\\"}md-select.md-THEME_NAME-theme .md-select-icon{color:\\\"{{foreground-2}}\\\"}md-select-menu.md-THEME_NAME-theme md-content{background-color:\\\"{{background-hue-1}}\\\"}md-select-menu.md-THEME_NAME-theme md-content md-optgroup{color:\\\"{{foreground-2}}\\\"}md-select-menu.md-THEME_NAME-theme md-content md-option{color:\\\"{{foreground-1}}\\\"}md-select-menu.md-THEME_NAME-theme md-content md-option[disabled] .md-text{color:\\\"{{foreground-3}}\\\"}md-select-menu.md-THEME_NAME-theme md-content md-option:not([disabled]):hover{background-color:\\\"{{background-500-0.10}}\\\"}md-select-menu.md-THEME_NAME-theme md-content md-option:not([disabled]).md-focused,md-select-menu.md-THEME_NAME-theme md-content md-option:not([disabled]):focus{background-color:\\\"{{background-500-0.18}}\\\"}md-select-menu.md-THEME_NAME-theme md-content md-option[selected]{color:\\\"{{primary-500}}\\\"}md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-focused,md-select-menu.md-THEME_NAME-theme md-content md-option[selected]:focus{color:\\\"{{primary-600}}\\\"}md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-accent{color:\\\"{{accent-color}}\\\"}md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-accent.md-focused,md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-accent:focus{color:\\\"{{accent-A700}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme .md-ripple{color:\\\"{{primary-600}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-ripple{color:\\\"{{background-600}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme .md-ink-ripple{color:\\\"{{foreground-2}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-ink-ripple{color:\\\"{{primary-color-0.87}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme:not(.md-checked) .md-icon{border-color:\\\"{{foreground-2}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-icon{background-color:\\\"{{primary-color-0.87}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme[selected].md-focused .md-container:before{background-color:\\\"{{primary-color-0.26}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-icon:after{border-color:\\\"{{primary-contrast-0.87}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme .md-indeterminate[disabled] .md-container{color:\\\"{{foreground-3}}\\\"}.md-checkbox-enabled.md-THEME_NAME-theme md-option .md-text{color:\\\"{{foreground-1}}\\\"}md-sidenav.md-THEME_NAME-theme,md-sidenav.md-THEME_NAME-theme md-content{background-color:\\\"{{background-hue-1}}\\\"}md-slider.md-THEME_NAME-theme .md-track{background-color:\\\"{{foreground-3}}\\\"}md-slider.md-THEME_NAME-theme .md-track-ticks{color:\\\"{{background-contrast}}\\\"}md-slider.md-THEME_NAME-theme .md-focus-ring{background-color:\\\"{{accent-A200-0.2}}\\\"}md-slider.md-THEME_NAME-theme .md-disabled-thumb{border-color:\\\"{{background-color}}\\\";background-color:\\\"{{background-color}}\\\"}md-slider.md-THEME_NAME-theme.md-min .md-thumb:after{background-color:\\\"{{background-color}}\\\";border-color:\\\"{{foreground-3}}\\\"}md-slider.md-THEME_NAME-theme.md-min .md-focus-ring{background-color:\\\"{{foreground-3-0.38}}\\\"}md-slider.md-THEME_NAME-theme.md-min[md-discrete] .md-thumb:after{background-color:\\\"{{background-contrast}}\\\";border-color:transparent}md-slider.md-THEME_NAME-theme.md-min[md-discrete] .md-sign{background-color:\\\"{{background-400}}\\\"}md-slider.md-THEME_NAME-theme.md-min[md-discrete] .md-sign:after{border-top-color:\\\"{{background-400}}\\\"}md-slider.md-THEME_NAME-theme.md-min[md-discrete][md-vertical] .md-sign:after{border-top-color:transparent;border-left-color:\\\"{{background-400}}\\\"}md-slider.md-THEME_NAME-theme .md-track.md-track-fill{background-color:\\\"{{accent-color}}\\\"}md-slider.md-THEME_NAME-theme .md-thumb:after{border-color:\\\"{{accent-color}}\\\";background-color:\\\"{{accent-color}}\\\"}md-slider.md-THEME_NAME-theme .md-sign{background-color:\\\"{{accent-color}}\\\"}md-slider.md-THEME_NAME-theme .md-sign:after{border-top-color:\\\"{{accent-color}}\\\"}md-slider.md-THEME_NAME-theme[md-vertical] .md-sign:after{border-top-color:transparent;border-left-color:\\\"{{accent-color}}\\\"}md-slider.md-THEME_NAME-theme .md-thumb-text{color:\\\"{{accent-contrast}}\\\"}md-slider.md-THEME_NAME-theme.md-warn .md-focus-ring{background-color:\\\"{{warn-200-0.38}}\\\"}md-slider.md-THEME_NAME-theme.md-warn .md-track.md-track-fill{background-color:\\\"{{warn-color}}\\\"}md-slider.md-THEME_NAME-theme.md-warn .md-thumb:after{border-color:\\\"{{warn-color}}\\\";background-color:\\\"{{warn-color}}\\\"}md-slider.md-THEME_NAME-theme.md-warn .md-sign{background-color:\\\"{{warn-color}}\\\"}md-slider.md-THEME_NAME-theme.md-warn .md-sign:after{border-top-color:\\\"{{warn-color}}\\\"}md-slider.md-THEME_NAME-theme.md-warn[md-vertical] .md-sign:after{border-top-color:transparent;border-left-color:\\\"{{warn-color}}\\\"}md-slider.md-THEME_NAME-theme.md-warn .md-thumb-text{color:\\\"{{warn-contrast}}\\\"}md-slider.md-THEME_NAME-theme.md-primary .md-focus-ring{background-color:\\\"{{primary-200-0.38}}\\\"}md-slider.md-THEME_NAME-theme.md-primary .md-track.md-track-fill{background-color:\\\"{{primary-color}}\\\"}md-slider.md-THEME_NAME-theme.md-primary .md-thumb:after{border-color:\\\"{{primary-color}}\\\";background-color:\\\"{{primary-color}}\\\"}md-slider.md-THEME_NAME-theme.md-primary .md-sign{background-color:\\\"{{primary-color}}\\\"}md-slider.md-THEME_NAME-theme.md-primary .md-sign:after{border-top-color:\\\"{{primary-color}}\\\"}md-slider.md-THEME_NAME-theme.md-primary[md-vertical] .md-sign:after{border-top-color:transparent;border-left-color:\\\"{{primary-color}}\\\"}md-slider.md-THEME_NAME-theme.md-primary .md-thumb-text{color:\\\"{{primary-contrast}}\\\"}md-slider.md-THEME_NAME-theme[disabled] .md-thumb:after{border-color:transparent}md-slider.md-THEME_NAME-theme[disabled]:not(.md-min) .md-thumb:after,md-slider.md-THEME_NAME-theme[disabled][md-discrete] .md-thumb:after{background-color:\\\"{{foreground-3}}\\\";border-color:transparent}md-slider.md-THEME_NAME-theme[disabled][readonly] .md-sign{background-color:\\\"{{background-400}}\\\"}md-slider.md-THEME_NAME-theme[disabled][readonly] .md-sign:after{border-top-color:\\\"{{background-400}}\\\"}md-slider.md-THEME_NAME-theme[disabled][readonly][md-vertical] .md-sign:after{border-top-color:transparent;border-left-color:\\\"{{background-400}}\\\"}md-slider.md-THEME_NAME-theme[disabled][readonly] .md-disabled-thumb{border-color:transparent;background-color:transparent}md-slider-container[disabled]>:first-child:not(md-slider),md-slider-container[disabled]>:last-child:not(md-slider){color:\\\"{{foreground-3}}\\\"}.md-subheader.md-THEME_NAME-theme{color:\\\"{{ foreground-2-0.54 }}\\\";background-color:\\\"{{background-default}}\\\"}.md-subheader.md-THEME_NAME-theme.md-primary{color:\\\"{{primary-color}}\\\"}.md-subheader.md-THEME_NAME-theme.md-accent{color:\\\"{{accent-color}}\\\"}.md-subheader.md-THEME_NAME-theme.md-warn{color:\\\"{{warn-color}}\\\"}md-switch.md-THEME_NAME-theme .md-ink-ripple{color:\\\"{{background-500}}\\\"}md-switch.md-THEME_NAME-theme .md-thumb{background-color:\\\"{{background-50}}\\\"}md-switch.md-THEME_NAME-theme .md-bar{background-color:\\\"{{background-500}}\\\"}md-switch.md-THEME_NAME-theme.md-focused:not(.md-checked) .md-thumb:before{background-color:\\\"{{foreground-4}}\\\"}md-switch.md-THEME_NAME-theme.md-focused[disabled] .md-thumb:before{background-color:\\\"{{foreground-4}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]) .md-ink-ripple{color:\\\"{{accent-color}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]) .md-thumb{background-color:\\\"{{accent-color}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]) .md-bar{background-color:\\\"{{accent-color-0.5}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]).md-focused .md-thumb:before{background-color:\\\"{{accent-color-0.26}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]).md-primary .md-ink-ripple{color:\\\"{{primary-color}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]).md-primary .md-thumb{background-color:\\\"{{primary-color}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]).md-primary .md-bar{background-color:\\\"{{primary-color-0.5}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]).md-primary.md-focused .md-thumb:before{background-color:\\\"{{primary-color-0.26}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]).md-warn .md-ink-ripple{color:\\\"{{warn-color}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]).md-warn .md-thumb{background-color:\\\"{{warn-color}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]).md-warn .md-bar{background-color:\\\"{{warn-color-0.5}}\\\"}md-switch.md-THEME_NAME-theme.md-checked:not([disabled]).md-warn.md-focused .md-thumb:before{background-color:\\\"{{warn-color-0.26}}\\\"}md-switch.md-THEME_NAME-theme[disabled] .md-thumb{background-color:\\\"{{background-400}}\\\"}md-switch.md-THEME_NAME-theme[disabled] .md-bar{background-color:\\\"{{foreground-4}}\\\"}md-tabs.md-THEME_NAME-theme md-tabs-wrapper{background-color:transparent;border-color:\\\"{{foreground-4}}\\\"}md-tabs.md-THEME_NAME-theme md-next-button md-icon,md-tabs.md-THEME_NAME-theme md-prev-button md-icon{color:\\\"{{foreground-2}}\\\"}md-tabs.md-THEME_NAME-theme md-ink-bar{color:\\\"{{accent-color}}\\\";background:\\\"{{accent-color}}\\\"}md-tabs.md-THEME_NAME-theme .md-tab{color:\\\"{{foreground-2}}\\\"}md-tabs.md-THEME_NAME-theme .md-tab[disabled],md-tabs.md-THEME_NAME-theme .md-tab[disabled] md-icon{color:\\\"{{foreground-3}}\\\"}md-tabs.md-THEME_NAME-theme .md-tab.md-active,md-tabs.md-THEME_NAME-theme .md-tab.md-active md-icon,md-tabs.md-THEME_NAME-theme .md-tab.md-focused,md-tabs.md-THEME_NAME-theme .md-tab.md-focused md-icon{color:\\\"{{accent-color}}\\\"}md-tabs.md-THEME_NAME-theme .md-tab.md-focused{background:\\\"{{primary-color-0.1}}\\\"}md-tabs.md-THEME_NAME-theme .md-tab .md-ripple-container{color:\\\"{{accent-A100}}\\\"}md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper{background-color:\\\"{{accent-500}}\\\"}md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper md-next-button md-icon,md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper md-prev-button md-icon{color:\\\"{{accent-500-contrast-0.7}}\\\"}md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]),md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]) md-icon{color:\\\"{{accent-500-contrast-0.7}}\\\"}md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active,md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active md-icon,md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused,md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused md-icon{color:\\\"{{accent-500-contrast-1}}\\\"}md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused{background:\\\"{{accent-500-contrast-0.1}}\\\"}md-tabs.md-THEME_NAME-theme.md-accent>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-ink-bar{color:\\\"{{accent-500-contrast}}\\\";background:\\\"{{accent-500-contrast}}\\\"}md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper{background-color:\\\"{{primary-color}}\\\"}md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper md-next-button md-icon,md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper md-prev-button md-icon{color:\\\"{{primary-contrast}}\\\"}md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]),md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]) md-icon{color:\\\"{{primary-contrast-0.7}}\\\"}md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active,md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active md-icon,md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused,md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused md-icon{color:\\\"{{primary-contrast}}\\\"}md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused{background:\\\"{{primary-contrast-0.1}}\\\"}md-tabs.md-THEME_NAME-theme.md-primary>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-ink-bar{color:\\\"{{accent-color}}\\\";background:\\\"{{accent-color}}\\\"}md-tabs.md-THEME_NAME-theme.md-primary.md-no-ink-bar-color>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-ink-bar{color:\\\"{{primary-contrast}}\\\";background:\\\"{{primary-contrast}}\\\"}md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper{background-color:\\\"{{warn-500}}\\\"}md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper md-next-button md-icon,md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper md-prev-button md-icon{color:\\\"{{warn-500-contrast}}\\\"}md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]),md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]) md-icon{color:\\\"{{warn-500-contrast-0.7}}\\\"}md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active,md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active md-icon,md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused,md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused md-icon{color:\\\"{{warn-500-contrast-1}}\\\"}md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused{background:\\\"{{warn-500-contrast-0.1}}\\\"}md-tabs.md-THEME_NAME-theme.md-warn>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-ink-bar{color:\\\"{{warn-500-contrast}}\\\";background:\\\"{{warn-500-contrast}}\\\"}md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper{background-color:\\\"{{primary-color}}\\\"}md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper md-next-button md-icon,md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper md-prev-button md-icon{color:\\\"{{primary-contrast}}\\\"}md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]),md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]) md-icon{color:\\\"{{primary-contrast-0.7}}\\\"}md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active,md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active md-icon,md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused,md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused md-icon{color:\\\"{{primary-contrast}}\\\"}md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused{background:\\\"{{primary-contrast-0.1}}\\\"}md-toolbar>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-ink-bar{color:\\\"{{accent-color}}\\\";background:\\\"{{accent-color}}\\\"}md-toolbar>md-tabs.md-THEME_NAME-theme.md-no-ink-bar-color>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-ink-bar{color:\\\"{{primary-contrast}}\\\";background:\\\"{{primary-contrast}}\\\"}md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper{background-color:\\\"{{accent-500}}\\\"}md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper md-next-button md-icon,md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper md-prev-button md-icon{color:\\\"{{accent-500-contrast-0.7}}\\\"}md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]),md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]) md-icon{color:\\\"{{accent-500-contrast-0.7}}\\\"}md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active,md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active md-icon,md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused,md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused md-icon{color:\\\"{{accent-500-contrast-1}}\\\"}md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused{background:\\\"{{accent-500-contrast-0.1}}\\\"}md-toolbar.md-accent>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-ink-bar{color:\\\"{{accent-500-contrast}}\\\";background:\\\"{{accent-500-contrast}}\\\"}md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper{background-color:\\\"{{warn-500}}\\\"}md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper md-next-button md-icon,md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper md-prev-button md-icon{color:\\\"{{warn-500-contrast}}\\\"}md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]),md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]) md-icon{color:\\\"{{warn-500-contrast-0.7}}\\\"}md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active,md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-active md-icon,md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused,md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused md-icon{color:\\\"{{warn-500-contrast-1}}\\\"}md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-tab-item:not([disabled]).md-focused{background:\\\"{{warn-500-contrast-0.1}}\\\"}md-toolbar.md-warn>md-tabs.md-THEME_NAME-theme>md-tabs-wrapper>md-tabs-canvas>md-pagination-wrapper>md-ink-bar{color:\\\"{{warn-500-contrast}}\\\";background:\\\"{{warn-500-contrast}}\\\"}md-toast.md-THEME_NAME-theme .md-toast-content{background-color:#323232;color:\\\"{{background-50}}\\\"}md-toast.md-THEME_NAME-theme .md-toast-content .md-button{color:\\\"{{background-50}}\\\"}md-toast.md-THEME_NAME-theme .md-toast-content .md-button.md-highlight{color:\\\"{{accent-color}}\\\"}md-toast.md-THEME_NAME-theme .md-toast-content .md-button.md-highlight.md-primary{color:\\\"{{primary-color}}\\\"}md-toast.md-THEME_NAME-theme .md-toast-content .md-button.md-highlight.md-warn{color:\\\"{{warn-color}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar){background-color:\\\"{{primary-color}}\\\";color:\\\"{{primary-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-icon{color:\\\"{{primary-contrast}}\\\";fill:\\\"{{primary-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) .md-button[disabled] md-icon{color:\\\"{{primary-contrast-0.26}}\\\";fill:\\\"{{primary-contrast-0.26}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float] .md-input{color:\\\"{{primary-default-contrast}}\\\";border-color:\\\"{{primary-default-contrast-divider}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float] .md-input::-webkit-input-placeholder{color:\\\"{{primary-default-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float] .md-input:-ms-input-placeholder{color:\\\"{{primary-default-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float] .md-input::-ms-input-placeholder{color:\\\"{{primary-default-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float] .md-input::placeholder{color:\\\"{{primary-default-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float] .md-input:-moz-placeholder{color:\\\"{{primary-default-contrast-hint}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float] .md-input::-moz-placeholder{color:\\\"{{primary-default-contrast-hint}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float].md-input-focused .md-input::-webkit-input-placeholder{color:\\\"{{primary-default-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float].md-input-focused .md-input:-ms-input-placeholder{color:\\\"{{primary-default-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float].md-input-focused .md-input::-ms-input-placeholder{color:\\\"{{primary-default-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float].md-input-focused .md-input::placeholder{color:\\\"{{primary-default-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float].md-input-focused .md-input:-moz-placeholder{color:\\\"{{primary-default-contrast-secondary}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float].md-input-focused .md-input::-moz-placeholder{color:\\\"{{primary-default-contrast-secondary}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float]:not(.md-input-invalid).md-input-focused .md-input,md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float]:not(.md-input-invalid).md-input-resized .md-input{border-color:\\\"{{primary-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float]:not(.md-input-invalid).md-input-focused.md-accent .md-input{border-color:\\\"{{accent-color}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar) md-input-container[md-no-float]:not(.md-input-invalid).md-input-focused.md-warn .md-input{border-color:\\\"{{warn-A700}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent{background-color:\\\"{{accent-500}}\\\";color:\\\"{{accent-500-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent .md-ink-ripple{color:\\\"{{accent-500-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-icon{color:\\\"{{accent-500-contrast}}\\\";fill:\\\"{{accent-500-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent .md-button[disabled] md-icon{color:\\\"{{accent-500-contrast-0.26}}\\\";fill:\\\"{{accent-500-contrast-0.26}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float] .md-input{color:\\\"{{accent-500-contrast}}\\\";border-color:\\\"{{accent-500-contrast-divider}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float] .md-input::-webkit-input-placeholder{color:\\\"{{accent-500-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float] .md-input:-ms-input-placeholder{color:\\\"{{accent-500-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float] .md-input::-ms-input-placeholder{color:\\\"{{accent-500-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float] .md-input::placeholder{color:\\\"{{accent-500-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float] .md-input:-moz-placeholder{color:\\\"{{accent-500-contrast-hint}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float] .md-input::-moz-placeholder{color:\\\"{{accent-500-contrast-hint}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float].md-input-focused .md-input::-webkit-input-placeholder{color:\\\"{{accent-500-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float].md-input-focused .md-input:-ms-input-placeholder{color:\\\"{{accent-500-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float].md-input-focused .md-input::-ms-input-placeholder{color:\\\"{{accent-500-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float].md-input-focused .md-input::placeholder{color:\\\"{{accent-500-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float].md-input-focused .md-input:-moz-placeholder{color:\\\"{{accent-500-contrast-secondary}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float].md-input-focused .md-input::-moz-placeholder{color:\\\"{{accent-500-contrast-secondary}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float]:not(.md-input-invalid).md-input-focused .md-input,md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float]:not(.md-input-invalid).md-input-resized .md-input{border-color:\\\"{{primary-color}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float]:not(.md-input-invalid).md-input-focused.md-accent .md-input{border-color:\\\"{{accent-500-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-accent md-input-container[md-no-float]:not(.md-input-invalid).md-input-focused.md-warn .md-input{border-color:\\\"{{warn-A700}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn{background-color:\\\"{{warn-500}}\\\";color:\\\"{{warn-500-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-icon{color:\\\"{{warn-500-contrast}}\\\";fill:\\\"{{warn-500-contrast}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float] .md-input{color:\\\"{{warn-500-contrast}}\\\";border-color:\\\"{{warn-500-contrast-divider}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float] .md-input::-webkit-input-placeholder{color:\\\"{{warn-500-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float] .md-input:-ms-input-placeholder{color:\\\"{{warn-500-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float] .md-input::-ms-input-placeholder{color:\\\"{{warn-500-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float] .md-input::placeholder{color:\\\"{{warn-500-contrast-hint}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float] .md-input:-moz-placeholder{color:\\\"{{warn-500-contrast-hint}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float] .md-input::-moz-placeholder{color:\\\"{{warn-500-contrast-hint}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float].md-input-focused .md-input::-webkit-input-placeholder{color:\\\"{{warn-500-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float].md-input-focused .md-input:-ms-input-placeholder{color:\\\"{{warn-500-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float].md-input-focused .md-input::-ms-input-placeholder{color:\\\"{{warn-500-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float].md-input-focused .md-input::placeholder{color:\\\"{{warn-500-contrast-secondary}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float].md-input-focused .md-input:-moz-placeholder{color:\\\"{{warn-500-contrast-secondary}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float].md-input-focused .md-input::-moz-placeholder{color:\\\"{{warn-500-contrast-secondary}}\\\";opacity:1}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float]:not(.md-input-invalid).md-input-focused .md-input,md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float]:not(.md-input-invalid).md-input-resized .md-input{border-color:\\\"{{primary-color}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float]:not(.md-input-invalid).md-input-focused.md-accent .md-input{border-color:\\\"{{accent-color}}\\\"}md-toolbar.md-THEME_NAME-theme:not(.md-menu-toolbar).md-warn md-input-container[md-no-float]:not(.md-input-invalid).md-input-focused.md-warn .md-input{border-color:\\\"{{warn-500-contrast}}\\\"}.md-panel.md-tooltip.md-THEME_NAME-theme{color:\\\"{{background-700-contrast}}\\\";background-color:\\\"{{background-700}}\\\"}body.md-THEME_NAME-theme,html.md-THEME_NAME-theme{color:\\\"{{foreground-1}}\\\";background-color:\\\"{{background-color}}\\\"}\"); \n})();\n\n\n})(window, window.angular);;window.ngMaterial={version:{full: \"1.2.2\"}};","/*!\n * Angular Material Design\n * https://github.com/angular/material\n * @license MIT\n * v1.1.0-rc4\n */\n(function( window, angular, undefined ){\n\"use strict\";\n\n/**\n * @ngdoc module\n * @name material.components.bottomSheetCollapsible\n * @description\n * BottomSheetCollapsible\n */\nangular\n  .module('material.components.bottomSheetCollapsible', [\n    'material.core',\n    'material.components.backdrop'\n  ])\n  .directive('mdBottomSheetCollapsible', MdBottomSheetCollapsibleDirective)\n  .provider('$mdBottomSheetCollapsible', MdBottomSheetCollapsibleProvider);\n\n/* ngInject */\nfunction MdBottomSheetCollapsibleDirective($mdBottomSheetCollapsible) {\n  return {\n    restrict: 'E',\n    link : function postLink(scope, element) {\n      element.addClass('_md');     // private md component indicator for styling\n\n      // When navigation force destroys an interimElement, then\n      // listen and $destroy() that interim instance...\n      scope.$on('$destroy', function() {\n        $mdBottomSheetCollapsible.destroy();\n      });\n    }\n  };\n}\nMdBottomSheetCollapsibleDirective.$inject = [\"$mdBottomSheetCollapsible\"];\n\n\n/**\n * @ngdoc service\n * @name $mdBottomSheetCollapsible\n * @module material.components.bottomSheetCollapsible\n *\n * @description\n * `$mdBottomSheetCollapsible` opens a collapsible bottom sheet over the app and provides a simple promise API.\n *\n * ## Restrictions\n *\n * - The collapsible bottom sheet's template must have an outer `<md-bottom-sheet-collapsible>` element.\n * - Add the `md-grid` class to the collapsible bottom sheet for a grid layout.\n * - Add the `md-list` class to the collapsible bottom sheet for a list layout.\n *\n * @usage\n * <hljs lang=\"html\">\n * <div ng-controller=\"MyController\">\n *   <md-button ng-click=\"openBottomSheetCollapsible()\">\n *     Open a Collapsible Bottom Sheet!\n *   </md-button>\n * </div>\n * </hljs>\n * <hljs lang=\"js\">\n * let app = angular.module('app', ['ngMaterial']);\n * app.controller('MyController', function($scope, $mdBottomSheetCollapsible) {\n *   $scope.openBottomSheetCollapsible = function() {\n *     $mdBottomSheetCollapsible.show({\n *       template: '<md-bottom-sheet-collapsible>Hello!</md-bottom-sheet-collapsible>'\n *     });\n *   };\n * });\n * </hljs>\n */\n\n /**\n * @ngdoc method\n * @name $mdBottomSheetCollapsible#show\n *\n * @description\n * Show a collapsible bottom sheet with the specified options.\n *\n * @param {object} options An options object, with the following properties:\n *\n *   - `templateUrl` - `{string=}`: The url of an html template file that will\n *   be used as the content of the collapsible bottom sheet. Restrictions: the template must\n *   have an outer `md-bottom-sheet-collapsible` element.\n *   - `template` - `{string=}`: Same as templateUrl, except this is an actual\n *   template string.\n *   - `scope` - `{object=}`: the scope to link the template / controller to. If none is specified, it will create a new child scope.\n *     This scope will be destroyed when the collapsible bottom sheet is removed unless `preserveScope` is set to true.\n *   - `preserveScope` - `{boolean=}`: whether to preserve the scope when the element is removed. Default is false\n *   - `controller` - `{string=}`: The controller to associate with this collapsible bottom sheet.\n *   - `locals` - `{string=}`: An object containing key/value pairs. The keys will\n *   be used as names of values to inject into the controller. For example,\n *   `locals: {three: 3}` would inject `three` into the controller with the value\n *   of 3.\n *   - `clickOutsideToClose` - `{boolean=}`: Whether the user can click outside the collapsible bottom sheet to\n *     close it. Default true.\n *   - `disableBackdrop` - `{boolean=}`: When set to true, the collapsible bottom sheet will not show a backdrop.\n *   - `escapeToClose` - `{boolean=}`: Whether the user can press escape to close the collapsible bottom sheet.\n *     Default true.\n *   - `resolve` - `{object=}`: Similar to locals, except it takes promises as values\n *   and the collapsible bottom sheet will not open until the promises resolve.\n *   - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.\n *   - `parent` - `{element=}`: The element to append the collapsible bottom sheet to. The `parent` may be a `function`, `string`,\n *   `object`, or null. Defaults to appending to the body of the root element (or the root element) of the application.\n *   e.g. angular.element(document.getElementById('content')) or \"#content\"\n *   - `disableParentScroll` - `{boolean=}`: Whether to disable scrolling while the collapsible bottom sheet is open.\n *     Default true.\n *\n * @returns {promise} A promise that can be resolved with `$mdBottomSheetCollapsible.hide()` or\n * rejected with `$mdBottomSheetCollapsible.cancel()`.\n */\n\n/**\n * @ngdoc method\n * @name $mdBottomSheetCollapsible#hide\n *\n * @description\n * Hide the existing collapsible bottom sheet and resolve the promise returned from\n * `$mdBottomSheetCollapsible.show()`. This call will close the most recently opened/current collapsible bottom sheet (if any).\n *\n * @param {*=} response An argument for the resolved promise.\n *\n */\n\n/**\n * @ngdoc method\n * @name $mdBottomSheetCollapsible#cancel\n *\n * @description\n * Hide the existing collapsible bottom sheet and reject the promise returned from\n * `$mdBottomSheetCollapsible.show()`.\n *\n * @param {*=} response An argument for the rejected promise.\n *\n */\n\nfunction MdBottomSheetCollapsibleProvider($$interimElementProvider) {\n  // how fast we need to flick down to close the sheet, pixels/ms\n  const STATE_VELOCITY = 0.5;\n  const PADDING = 0; // same as css\n  // const PADDING = 88; // same as css\n\n  bottomSheetCollapsibleDefaults.$inject = [\"$animate\", \"$mdConstant\", \"$mdUtil\", \"$mdTheming\", \"$mdBottomSheetCollapsible\", \"$rootElement\", \"$mdGesture\"];\n  return $$interimElementProvider('$mdBottomSheetCollapsible')\n    .setDefaults({\n      methods: ['disableParentScroll', 'escapeToClose', 'clickOutsideToClose'],\n      options: bottomSheetCollapsibleDefaults\n    });\n\n  /* ngInject */\n  function bottomSheetCollapsibleDefaults($animate, $mdConstant, $mdUtil, $mdTheming, $mdBottomSheetCollapsible, $rootElement, $mdGesture) {\n    let backdrop;\n\n    return {\n      themable: true,\n      onShow: onShow,\n      onRemove: onRemove,\n      disableBackdrop: false,\n      escapeToClose: true,\n      clickOutsideToClose: true,\n      disableParentScroll: true,\n    };\n\n\n    function onShow(scope, element, options, controller) {\n\n      element = $mdUtil.extractElementByName(element, 'md-bottom-sheet-collapsible');\n\n      // prevent tab focus or click focus on the bottom-sheet-collapsible container\n      element.attr('tabindex',\"-1\");\n\n      if (!options.disableBackdrop) {\n        // Add a backdrop that will close on click\n        backdrop = $mdUtil.createBackdrop(scope, \"_md-bottom-sheet-backdrop md-opaque\");\n\n        // Prevent mouse focus on backdrop; ONLY programatic focus allowed.\n        // This allows clicks on backdrop to propogate to the $rootElement and\n        // ESC key events to be detected properly.\n\n        backdrop[0].tabIndex = -1;\n\n        if (options.clickOutsideToClose) {\n          backdrop.on('click', function() {\n            $mdUtil.nextTick($mdBottomSheetCollapsible.cancel, true);\n          });\n        }\n\n        $mdTheming.inherit(backdrop, options.parent);\n\n        $animate.enter(backdrop, options.parent, null);\n      }\n\n      let bottomSheetCollapsible = new BottomSheetCollapsible(element, options.parent);\n\n      if (options.onLoad) options.onLoad(bottomSheetCollapsible);\n\n      $mdTheming.inherit(bottomSheetCollapsible.element, options.parent);\n\n      if (options.disableParentScroll) {\n        options.restoreScroll = $mdUtil.disableScrollAround(bottomSheetCollapsible.element, options.parent);\n      }\n\n      bottomSheetCollapsible.setHalfway();\n\n      return $animate.enter(bottomSheetCollapsible.element, options.parent, backdrop)\n        .then(function() {\n          let focusable = $mdUtil.findFocusTarget(element) || angular.element(\n            element[0].querySelector('button') ||\n            element[0].querySelector('a') ||\n            element[0].querySelector('[ng-click]')\n          ) || backdrop;\n\n          if (options.escapeToClose) {\n            options.rootElementKeyupCallback = function(e) {\n              if (e.keyCode === $mdConstant.KEY_CODE.ESCAPE) {\n                $mdUtil.nextTick($mdBottomSheetCollapsible.cancel,true);\n              }\n            };\n\n            $rootElement.on('keyup', options.rootElementKeyupCallback);\n            focusable && focusable.focus();\n          }\n\n\n        });\n\n    }\n\n    function onRemove(scope, element, options) {\n\n      let bottomSheetCollapsible = options.bottomSheetCollapsible;\n\n      if (!options.disableBackdrop) $animate.leave(backdrop);\n      return $animate.leave(bottomSheetCollapsible.element).then(function() {\n        if (options.disableParentScroll) {\n          options.restoreScroll();\n          delete options.restoreScroll;\n        }\n\n        bottomSheetCollapsible.cleanup();\n      });\n    }\n\n    /**\n     * BottomSheetCollapsible class to apply bottom-sheet-collapsible behavior to an element\n     */\n    function BottomSheetCollapsible(element, parent) {\n      let deregisterDrag = $mdGesture.register(parent, 'drag', { horizontal: false });\n      const transitionDuration = 500;\n      let LHeight = window.innerHeight;\n      let MHeight = window.innerHeight * .6;\n      let SHeight = 56; // or toolbar height\n      const peekHeight = 100;\n      const minOffset = 400;\n      let dragging = false;\n      let state = \"halfway\";\n\n      parent.on('$md.dragstart', onDragStart)\n        .on('$md.drag', onDrag)\n        .on('$md.dragend', onDragEnd);\n\n      return {\n        element: element,\n        cleanup: function cleanup() {\n          deregisterDrag();\n          parent.off('$md.dragstart', onDragStart);\n          parent.off('$md.drag', onDrag);\n          parent.off('$md.dragend', onDragEnd);\n        },\n        setExpanded: setExpanded,\n        setHalfway: setHalfway,\n        setMinimized: setMinimized,\n        getState: getState,\n      };\n\n      function composedPath (el) {\n          let path = [];\n          while (el) {\n              path.push(el);\n              if (el.tagName === 'HTML') {\n                  path.push(document);\n                  path.push(window);\n                  return path;\n             }\n             el = el.parentElement;\n          }\n      }\n\n      function getState() {\n        return state;\n      }\n\n      function setExpanded() {\n        element.css($mdConstant.CSS.TRANSITION_DURATION, '');\n        element.css($mdConstant.CSS.TRANSFORM, '');\n        element.removeClass(\"minimized halfway\");\n        element.addClass(\"expanded\");\n        state = \"expanded\";\n      }\n\n      function setHalfway() {\n        element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDuration + 'ms');\n        element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + window.innerHeight - MHeight) + 'px,0)');\n        element.removeClass(\"minimized expanded\");\n        element.addClass(\"halfway\");\n        state = \"halfway\";\n      }\n\n      function setMinimized() {\n        element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDuration + 'ms');\n        element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + window.innerHeight - SHeight) + 'px,0)');\n        element.removeClass(\"expanded halfway\");\n        element.addClass(\"minimized\");\n        state = \"minimized\";\n      }\n\n      function onDragStart(ev) {\n        // Disable transitions on transform so that it feels fast\n        element.css($mdConstant.CSS.TRANSITION_DURATION, '0ms');\n\n        dragging = false;\n        // ev.path.forEach(function(el) {\n        composedPath(ev.target).forEach(function(el) {\n          if (el.tagName == \"MD-BOTTOM-SHEET-COLLAPSIBLE\") {\n            dragging = true;\n          }\n        });\n      }\n      \n      function onDrag(ev) {\n        if (dragging) {\n          let transform = ev.pointer.distanceY;\n          if (transform > 0) {\n          }\n\n          if (state === \"expanded\") {\n            var offset = transform > 0 ? transform : 0;\n            element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + offset) + 'px,0)');\n          } else if (state === \"halfway\") {\n            // console.log(transform, MHeight - window.innerHeight);\n            // var offset;\n            // if (transform < MHeight - window.innerHeight) {\n            //   offset = MHeight - window.innerHeight;\n            // } else {\n            //   offset = transform;\n            // }\n            var offset = transform > MHeight - window.innerHeight ? transform : MHeight - window.innerHeight;\n            element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + offset + window.innerHeight - MHeight) + 'px,0)');\n          } else {\n            // var offset;\n            // if (transform < SHeight - window.innerHeight) {\n            //   offset = SHeight - window.innerHeight;\n            // } else {\n            //   offset = transform;\n            // }\n            var offset = transform > SHeight - window.innerHeight ? transform : SHeight - window.innerHeight;\n            element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + offset + window.innerHeight - SHeight) + 'px,0)');\n          }\n        }\n      }\n\n      function onDragEnd(ev) {\n        if (dragging) {\n          onDrag(ev);\n\n          // console.log(ev.pointer.velocityY);\n          if (state === \"expanded\") {\n            if ((ev.pointer.distanceY > 20 && ev.pointer.distanceY < (LHeight - MHeight) && ev.pointer.velocityY > 0) || (ev.pointer.distanceY > 0 && ev.pointer.distanceY < (LHeight - MHeight) && ev.pointer.velocityY > STATE_VELOCITY)) {\n              setHalfway();\n            } else if (ev.pointer.distanceY > (20 + LHeight - MHeight) || (ev.pointer.distanceY > (LHeight - MHeight) && ev.pointer.velocityY > STATE_VELOCITY)) {\n              if (ev.pointer.velocityY > 0) {\n                setMinimized();\n              } else if (ev.pointer.velocityY < 0) {\n                setHalfway();\n              }\n            } else {\n              setExpanded();\n            }\n          } else if (state === \"halfway\") {\n            if (ev.pointer.distanceY > 0 && (ev.pointer.distanceY > 20 || ev.pointer.velocityY > STATE_VELOCITY)) {\n              if (ev.pointer.velocityY > 0) {\n                setMinimized();\n              }\n            } else if (ev.pointer.distanceY < 0 && (ev.pointer.distanceY < -20 || ev.pointer.velocityY < STATE_VELOCITY * -1)) {\n              if (ev.pointer.velocityY < 0) {\n                setExpanded();\n              }\n            } else {\n              setHalfway()\n            }\n          } else if (state === \"minimized\") {\n            if ((ev.pointer.distanceY < -20 && ev.pointer.distanceY > (SHeight - MHeight) && ev.pointer.velocityY < 0) || (ev.pointer.distanceY < 0 && ev.pointer.distanceY > (SHeight - MHeight) && ev.pointer.velocityY < STATE_VELOCITY * -1)) {\n              setHalfway();\n            } else if (ev.pointer.distanceY < (SHeight - MHeight - 20) || (ev.pointer.distanceY < (SHeight - MHeight) && ev.pointer.velocityY < STATE_VELOCITY * -1)) {\n              if (ev.pointer.velocityY < 0) {\n                setExpanded();\n              } else if (ev.pointer.velocityY > 0) {\n                setHalfway();\n              }\n            } else {\n              setMinimized();\n            }\n          }\n          /////\n          // if (ev.pointer.distanceY > 0 &&\n          //     (ev.pointer.distanceY > 20 || Math.abs(ev.pointer.velocityY) > CLOSING_VELOCITY)) {\n\n          //   if (state === \"expanded\") {\n          //     // let transitionDuration = 500;\n          //     element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDuration + 'ms');\n          //     element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + window.innerHeight*.7) + 'px,0)');\n          //     // element.css($mdConstant.CSS.TRANSITION_DURATION, '');\n          //     // element.css($mdConstant.CSS.TRANSFORM, '');\n          //     state = \"halfway\"\n          //   } else if (state === \"halfway\") {\n          //     // let transitionDuration = 500;\n          //     element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDuration + 'ms');\n          //     element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + window.innerHeight - 56) + 'px,0)');\n          //     // $mdUtil.nextTick($mdBottomSheetCollapsible.cancel, true);\n          //     state = \"minimized\"\n          //   }\n          // } else if (ev.pointer.distanceY < 0) {\n          //   if (state === \"minimized\") {\n\n          //   } else if (state === \"halfway\") {\n          //     // let transitionDuration = 500;\n          //     element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDuration + 'ms');\n          //     element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING - minOffset) + 'px,0)');\n          //     state = \"expanded\";\n          //   }\n          // } else {\n          //   element.css($mdConstant.CSS.TRANSITION_DURATION, '');\n          //   element.css($mdConstant.CSS.TRANSFORM, '');\n          //   state = \"halfway\"\n          // }\n          /////\n        }\n      }\n    }\n\n  }\n\n}\nMdBottomSheetCollapsibleProvider.$inject = [\"$$interimElementProvider\"];\n\n})(window, window.angular);\n","var api = require(\"!../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../mini-css-extract-plugin/dist/loader.js??ref--5-1!../css-loader/dist/cjs.js!./angular-material.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {};\n\noptions.insert = \"head\";\noptions.singleton = false;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","require('./angular-animate');\nmodule.exports = 'ngAnimate';\n","var api = require(\"!../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../mini-css-extract-plugin/dist/loader.js??ref--5-1!../css-loader/dist/cjs.js!./bottomSheetCollapsible.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {};\n\noptions.insert = \"head\";\noptions.singleton = false;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","/**\n * @license AngularJS v1.8.2\n * (c) 2010-2020 Google LLC. http://angularjs.org\n * License: MIT\n */\n(function(window, angular) {'use strict';\n\n/**\n * @ngdoc module\n * @name ngAria\n * @description\n *\n * The `ngAria` module provides support for common\n * [<abbr title=\"Accessible Rich Internet Applications\">ARIA</abbr>](http://www.w3.org/TR/wai-aria/)\n * attributes that convey state or semantic information about the application for users\n * of assistive technologies, such as screen readers.\n *\n * ## Usage\n *\n * For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following\n * directives are supported:\n * `ngModel`, `ngChecked`, `ngReadonly`, `ngRequired`, `ngValue`, `ngDisabled`, `ngShow`, `ngHide`,\n * `ngClick`, `ngDblClick`, and `ngMessages`.\n *\n * Below is a more detailed breakdown of the attributes handled by ngAria:\n *\n * | Directive                                   | Supported Attributes                                                                                |\n * |---------------------------------------------|-----------------------------------------------------------------------------------------------------|\n * | {@link ng.directive:ngModel ngModel}        | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required, input roles |\n * | {@link ng.directive:ngDisabled ngDisabled}  | aria-disabled                                                                                       |\n * | {@link ng.directive:ngRequired ngRequired}  | aria-required                                                                                       |\n * | {@link ng.directive:ngChecked ngChecked}    | aria-checked                                                                                        |\n * | {@link ng.directive:ngReadonly ngReadonly}  | aria-readonly                                                                                       |\n * | {@link ng.directive:ngValue ngValue}        | aria-checked                                                                                        |\n * | {@link ng.directive:ngShow ngShow}          | aria-hidden                                                                                         |\n * | {@link ng.directive:ngHide ngHide}          | aria-hidden                                                                                         |\n * | {@link ng.directive:ngDblclick ngDblclick}  | tabindex                                                                                            |\n * | {@link module:ngMessages ngMessages}        | aria-live                                                                                           |\n * | {@link ng.directive:ngClick ngClick}        | tabindex, keydown event, button role                                                                |\n *\n * Find out more information about each directive by reading the\n * {@link guide/accessibility ngAria Developer Guide}.\n *\n * ## Example\n * Using ngDisabled with ngAria:\n * ```html\n * <md-checkbox ng-disabled=\"disabled\">\n * ```\n * Becomes:\n * ```html\n * <md-checkbox ng-disabled=\"disabled\" aria-disabled=\"true\">\n * ```\n *\n * ## Disabling Specific Attributes\n * It is possible to disable individual attributes added by ngAria with the\n * {@link ngAria.$ariaProvider#config config} method. For more details, see the\n * {@link guide/accessibility Developer Guide}.\n *\n * ## Disabling `ngAria` on Specific Elements\n * It is possible to make `ngAria` ignore a specific element, by adding the `ng-aria-disable`\n * attribute on it. Note that only the element itself (and not its child elements) will be ignored.\n */\nvar ARIA_DISABLE_ATTR = 'ngAriaDisable';\n\nvar ngAriaModule = angular.module('ngAria', ['ng']).\n                        info({ angularVersion: '1.8.2' }).\n                        provider('$aria', $AriaProvider);\n\n/**\n* Internal Utilities\n*/\nvar nativeAriaNodeNames = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'DETAILS', 'SUMMARY'];\n\nvar isNodeOneOf = function(elem, nodeTypeArray) {\n  if (nodeTypeArray.indexOf(elem[0].nodeName) !== -1) {\n    return true;\n  }\n};\n/**\n * @ngdoc provider\n * @name $ariaProvider\n * @this\n *\n * @description\n *\n * Used for configuring the ARIA attributes injected and managed by ngAria.\n *\n * ```js\n * angular.module('myApp', ['ngAria'], function config($ariaProvider) {\n *   $ariaProvider.config({\n *     ariaValue: true,\n *     tabindex: false\n *   });\n * });\n *```\n *\n * ## Dependencies\n * Requires the {@link ngAria} module to be installed.\n *\n */\nfunction $AriaProvider() {\n  var config = {\n    ariaHidden: true,\n    ariaChecked: true,\n    ariaReadonly: true,\n    ariaDisabled: true,\n    ariaRequired: true,\n    ariaInvalid: true,\n    ariaValue: true,\n    tabindex: true,\n    bindKeydown: true,\n    bindRoleForClick: true\n  };\n\n  /**\n   * @ngdoc method\n   * @name $ariaProvider#config\n   *\n   * @param {object} config object to enable/disable specific ARIA attributes\n   *\n   *  - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags\n   *  - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags\n   *  - **ariaReadonly** – `{boolean}` – Enables/disables aria-readonly tags\n   *  - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags\n   *  - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags\n   *  - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid tags\n   *  - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and\n   *    aria-valuenow tags\n   *  - **tabindex** – `{boolean}` – Enables/disables tabindex tags\n   *  - **bindKeydown** – `{boolean}` – Enables/disables keyboard event binding on non-interactive\n   *    elements (such as `div` or `li`) using ng-click, making them more accessible to users of\n   *    assistive technologies\n   *  - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements (such as\n   *    `div` or `li`) using ng-click, making them more accessible to users of assistive\n   *    technologies\n   *\n   * @description\n   * Enables/disables various ARIA attributes\n   */\n  this.config = function(newConfig) {\n    config = angular.extend(config, newConfig);\n  };\n\n  function watchExpr(attrName, ariaAttr, nativeAriaNodeNames, negate) {\n    return function(scope, elem, attr) {\n      if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;\n\n      var ariaCamelName = attr.$normalize(ariaAttr);\n      if (config[ariaCamelName] && !isNodeOneOf(elem, nativeAriaNodeNames) && !attr[ariaCamelName]) {\n        scope.$watch(attr[attrName], function(boolVal) {\n          // ensure boolean value\n          boolVal = negate ? !boolVal : !!boolVal;\n          elem.attr(ariaAttr, boolVal);\n        });\n      }\n    };\n  }\n  /**\n   * @ngdoc service\n   * @name $aria\n   *\n   * @description\n   *\n   * The $aria service contains helper methods for applying common\n   * [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.\n   *\n   * ngAria injects common accessibility attributes that tell assistive technologies when HTML\n   * elements are enabled, selected, hidden, and more. To see how this is performed with ngAria,\n   * let's review a code snippet from ngAria itself:\n   *\n   *```js\n   * ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {\n   *   return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nativeAriaNodeNames, false);\n   * }])\n   *```\n   * Shown above, the ngAria module creates a directive with the same signature as the\n   * traditional `ng-disabled` directive. But this ngAria version is dedicated to\n   * solely managing accessibility attributes on custom elements. The internal `$aria` service is\n   * used to watch the boolean attribute `ngDisabled`. If it has not been explicitly set by the\n   * developer, `aria-disabled` is injected as an attribute with its value synchronized to the\n   * value in `ngDisabled`.\n   *\n   * Because ngAria hooks into the `ng-disabled` directive, developers do not have to do\n   * anything to enable this feature. The `aria-disabled` attribute is automatically managed\n   * simply as a silent side-effect of using `ng-disabled` with the ngAria module.\n   *\n   * The full list of directives that interface with ngAria:\n   * * **ngModel**\n   * * **ngChecked**\n   * * **ngReadonly**\n   * * **ngRequired**\n   * * **ngDisabled**\n   * * **ngValue**\n   * * **ngShow**\n   * * **ngHide**\n   * * **ngClick**\n   * * **ngDblclick**\n   * * **ngMessages**\n   *\n   * Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each\n   * directive.\n   *\n   *\n   * ## Dependencies\n   * Requires the {@link ngAria} module to be installed.\n   */\n  this.$get = function() {\n    return {\n      config: function(key) {\n        return config[key];\n      },\n      $$watchExpr: watchExpr\n    };\n  };\n}\n\n\nngAriaModule.directive('ngShow', ['$aria', function($aria) {\n  return $aria.$$watchExpr('ngShow', 'aria-hidden', [], true);\n}])\n.directive('ngHide', ['$aria', function($aria) {\n  return $aria.$$watchExpr('ngHide', 'aria-hidden', [], false);\n}])\n.directive('ngValue', ['$aria', function($aria) {\n  return $aria.$$watchExpr('ngValue', 'aria-checked', nativeAriaNodeNames, false);\n}])\n.directive('ngChecked', ['$aria', function($aria) {\n  return $aria.$$watchExpr('ngChecked', 'aria-checked', nativeAriaNodeNames, false);\n}])\n.directive('ngReadonly', ['$aria', function($aria) {\n  return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nativeAriaNodeNames, false);\n}])\n.directive('ngRequired', ['$aria', function($aria) {\n  return $aria.$$watchExpr('ngRequired', 'aria-required', nativeAriaNodeNames, false);\n}])\n.directive('ngModel', ['$aria', function($aria) {\n\n  function shouldAttachAttr(attr, normalizedAttr, elem, allowNonAriaNodes) {\n    return $aria.config(normalizedAttr) &&\n      !elem.attr(attr) &&\n      (allowNonAriaNodes || !isNodeOneOf(elem, nativeAriaNodeNames)) &&\n      (elem.attr('type') !== 'hidden' || elem[0].nodeName !== 'INPUT');\n  }\n\n  function shouldAttachRole(role, elem) {\n    // if element does not have role attribute\n    // AND element type is equal to role (if custom element has a type equaling shape) <-- remove?\n    // AND element is not in nativeAriaNodeNames\n    return !elem.attr('role') && (elem.attr('type') === role) && !isNodeOneOf(elem, nativeAriaNodeNames);\n  }\n\n  function getShape(attr, elem) {\n    var type = attr.type,\n        role = attr.role;\n\n    return ((type || role) === 'checkbox' || role === 'menuitemcheckbox') ? 'checkbox' :\n           ((type || role) === 'radio'    || role === 'menuitemradio') ? 'radio' :\n           (type === 'range'              || role === 'progressbar' || role === 'slider') ? 'range' : '';\n  }\n\n  return {\n    restrict: 'A',\n    require: 'ngModel',\n    priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value\n    compile: function(elem, attr) {\n      if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;\n\n      var shape = getShape(attr, elem);\n\n      return {\n        post: function(scope, elem, attr, ngModel) {\n          var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem, false);\n\n          function ngAriaWatchModelValue() {\n            return ngModel.$modelValue;\n          }\n\n          function getRadioReaction(newVal) {\n            // Strict comparison would cause a BC\n            // eslint-disable-next-line eqeqeq\n            var boolVal = (attr.value == ngModel.$viewValue);\n            elem.attr('aria-checked', boolVal);\n          }\n\n          function getCheckboxReaction() {\n            elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));\n          }\n\n          switch (shape) {\n            case 'radio':\n            case 'checkbox':\n              if (shouldAttachRole(shape, elem)) {\n                elem.attr('role', shape);\n              }\n              if (shouldAttachAttr('aria-checked', 'ariaChecked', elem, false)) {\n                scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?\n                    getRadioReaction : getCheckboxReaction);\n              }\n              if (needsTabIndex) {\n                elem.attr('tabindex', 0);\n              }\n              break;\n            case 'range':\n              if (shouldAttachRole(shape, elem)) {\n                elem.attr('role', 'slider');\n              }\n              if ($aria.config('ariaValue')) {\n                var needsAriaValuemin = !elem.attr('aria-valuemin') &&\n                    (attr.hasOwnProperty('min') || attr.hasOwnProperty('ngMin'));\n                var needsAriaValuemax = !elem.attr('aria-valuemax') &&\n                    (attr.hasOwnProperty('max') || attr.hasOwnProperty('ngMax'));\n                var needsAriaValuenow = !elem.attr('aria-valuenow');\n\n                if (needsAriaValuemin) {\n                  attr.$observe('min', function ngAriaValueMinReaction(newVal) {\n                    elem.attr('aria-valuemin', newVal);\n                  });\n                }\n                if (needsAriaValuemax) {\n                  attr.$observe('max', function ngAriaValueMinReaction(newVal) {\n                    elem.attr('aria-valuemax', newVal);\n                  });\n                }\n                if (needsAriaValuenow) {\n                  scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) {\n                    elem.attr('aria-valuenow', newVal);\n                  });\n                }\n              }\n              if (needsTabIndex) {\n                elem.attr('tabindex', 0);\n              }\n              break;\n          }\n\n          if (!attr.hasOwnProperty('ngRequired') && ngModel.$validators.required\n            && shouldAttachAttr('aria-required', 'ariaRequired', elem, false)) {\n            // ngModel.$error.required is undefined on custom controls\n            attr.$observe('required', function() {\n              elem.attr('aria-required', !!attr['required']);\n            });\n          }\n\n          if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem, true)) {\n            scope.$watch(function ngAriaInvalidWatch() {\n              return ngModel.$invalid;\n            }, function ngAriaInvalidReaction(newVal) {\n              elem.attr('aria-invalid', !!newVal);\n            });\n          }\n        }\n      };\n    }\n  };\n}])\n.directive('ngDisabled', ['$aria', function($aria) {\n  return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nativeAriaNodeNames, false);\n}])\n.directive('ngMessages', function() {\n  return {\n    restrict: 'A',\n    require: '?ngMessages',\n    link: function(scope, elem, attr, ngMessages) {\n      if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;\n\n      if (!elem.attr('aria-live')) {\n        elem.attr('aria-live', 'assertive');\n      }\n    }\n  };\n})\n.directive('ngClick',['$aria', '$parse', function($aria, $parse) {\n  return {\n    restrict: 'A',\n    compile: function(elem, attr) {\n      if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;\n\n      var fn = $parse(attr.ngClick);\n      return function(scope, elem, attr) {\n\n        if (!isNodeOneOf(elem, nativeAriaNodeNames)) {\n\n          if ($aria.config('bindRoleForClick') && !elem.attr('role')) {\n            elem.attr('role', 'button');\n          }\n\n          if ($aria.config('tabindex') && !elem.attr('tabindex')) {\n            elem.attr('tabindex', 0);\n          }\n\n          if ($aria.config('bindKeydown') && !attr.ngKeydown && !attr.ngKeypress && !attr.ngKeyup) {\n            elem.on('keydown', function(event) {\n              var keyCode = event.which || event.keyCode;\n\n              if (keyCode === 13 || keyCode === 32) {\n                // If the event is triggered on a non-interactive element ...\n                if (nativeAriaNodeNames.indexOf(event.target.nodeName) === -1 && !event.target.isContentEditable) {\n                  // ... prevent the default browser behavior (e.g. scrolling when pressing spacebar)\n                  // See https://github.com/angular/angular.js/issues/16664\n                  event.preventDefault();\n                }\n                scope.$apply(callback);\n              }\n\n              function callback() {\n                fn(scope, { $event: event });\n              }\n            });\n          }\n        }\n      };\n    }\n  };\n}])\n.directive('ngDblclick', ['$aria', function($aria) {\n  return function(scope, elem, attr) {\n    if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;\n\n    if ($aria.config('tabindex') && !elem.attr('tabindex') && !isNodeOneOf(elem, nativeAriaNodeNames)) {\n      elem.attr('tabindex', 0);\n    }\n  };\n}]);\n\n\n})(window, window.angular);\n","// Should already be required, here for clarity\nrequire('angular');\n\n// Load Angular and dependent libs\nrequire('angular-animate');\nrequire('angular-aria');\n\n// Now load Angular Material\nrequire('./angular-material');\n\n// Export namespace\nmodule.exports = 'ngMaterial';\n","require('./angular-aria');\nmodule.exports = 'ngAria';\n","/**\n * @license AngularJS v1.8.2\n * (c) 2010-2020 Google LLC. http://angularjs.org\n * License: MIT\n */\n(function(window, angular) {'use strict';\n\nvar ELEMENT_NODE = 1;\nvar COMMENT_NODE = 8;\n\nvar ADD_CLASS_SUFFIX = '-add';\nvar REMOVE_CLASS_SUFFIX = '-remove';\nvar EVENT_CLASS_PREFIX = 'ng-';\nvar ACTIVE_CLASS_SUFFIX = '-active';\nvar PREPARE_CLASS_SUFFIX = '-prepare';\n\nvar NG_ANIMATE_CLASSNAME = 'ng-animate';\nvar NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren';\n\n// Detect proper transitionend/animationend event names.\nvar CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;\n\n// If unprefixed events are not supported but webkit-prefixed are, use the latter.\n// Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.\n// Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`\n// but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.\n// Register both events in case `window.onanimationend` is not supported because of that,\n// do the same for `transitionend` as Safari is likely to exhibit similar behavior.\n// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit\n// therefore there is no reason to test anymore for other vendor prefixes:\n// http://caniuse.com/#search=transition\nif ((window.ontransitionend === undefined) && (window.onwebkittransitionend !== undefined)) {\n  CSS_PREFIX = '-webkit-';\n  TRANSITION_PROP = 'WebkitTransition';\n  TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';\n} else {\n  TRANSITION_PROP = 'transition';\n  TRANSITIONEND_EVENT = 'transitionend';\n}\n\nif ((window.onanimationend === undefined) && (window.onwebkitanimationend !== undefined)) {\n  CSS_PREFIX = '-webkit-';\n  ANIMATION_PROP = 'WebkitAnimation';\n  ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';\n} else {\n  ANIMATION_PROP = 'animation';\n  ANIMATIONEND_EVENT = 'animationend';\n}\n\nvar DURATION_KEY = 'Duration';\nvar PROPERTY_KEY = 'Property';\nvar DELAY_KEY = 'Delay';\nvar TIMING_KEY = 'TimingFunction';\nvar ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';\nvar ANIMATION_PLAYSTATE_KEY = 'PlayState';\nvar SAFE_FAST_FORWARD_DURATION_VALUE = 9999;\n\nvar ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;\nvar ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;\nvar TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;\nvar TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;\n\nvar ngMinErr = angular.$$minErr('ng');\nfunction assertArg(arg, name, reason) {\n  if (!arg) {\n    throw ngMinErr('areq', 'Argument \\'{0}\\' is {1}', (name || '?'), (reason || 'required'));\n  }\n  return arg;\n}\n\nfunction mergeClasses(a,b) {\n  if (!a && !b) return '';\n  if (!a) return b;\n  if (!b) return a;\n  if (isArray(a)) a = a.join(' ');\n  if (isArray(b)) b = b.join(' ');\n  return a + ' ' + b;\n}\n\nfunction packageStyles(options) {\n  var styles = {};\n  if (options && (options.to || options.from)) {\n    styles.to = options.to;\n    styles.from = options.from;\n  }\n  return styles;\n}\n\nfunction pendClasses(classes, fix, isPrefix) {\n  var className = '';\n  classes = isArray(classes)\n      ? classes\n      : classes && isString(classes) && classes.length\n          ? classes.split(/\\s+/)\n          : [];\n  forEach(classes, function(klass, i) {\n    if (klass && klass.length > 0) {\n      className += (i > 0) ? ' ' : '';\n      className += isPrefix ? fix + klass\n                            : klass + fix;\n    }\n  });\n  return className;\n}\n\nfunction removeFromArray(arr, val) {\n  var index = arr.indexOf(val);\n  if (val >= 0) {\n    arr.splice(index, 1);\n  }\n}\n\nfunction stripCommentsFromElement(element) {\n  if (element instanceof jqLite) {\n    switch (element.length) {\n      case 0:\n        return element;\n\n      case 1:\n        // there is no point of stripping anything if the element\n        // is the only element within the jqLite wrapper.\n        // (it's important that we retain the element instance.)\n        if (element[0].nodeType === ELEMENT_NODE) {\n          return element;\n        }\n        break;\n\n      default:\n        return jqLite(extractElementNode(element));\n    }\n  }\n\n  if (element.nodeType === ELEMENT_NODE) {\n    return jqLite(element);\n  }\n}\n\nfunction extractElementNode(element) {\n  if (!element[0]) return element;\n  for (var i = 0; i < element.length; i++) {\n    var elm = element[i];\n    if (elm.nodeType === ELEMENT_NODE) {\n      return elm;\n    }\n  }\n}\n\nfunction $$addClass($$jqLite, element, className) {\n  forEach(element, function(elm) {\n    $$jqLite.addClass(elm, className);\n  });\n}\n\nfunction $$removeClass($$jqLite, element, className) {\n  forEach(element, function(elm) {\n    $$jqLite.removeClass(elm, className);\n  });\n}\n\nfunction applyAnimationClassesFactory($$jqLite) {\n  return function(element, options) {\n    if (options.addClass) {\n      $$addClass($$jqLite, element, options.addClass);\n      options.addClass = null;\n    }\n    if (options.removeClass) {\n      $$removeClass($$jqLite, element, options.removeClass);\n      options.removeClass = null;\n    }\n  };\n}\n\nfunction prepareAnimationOptions(options) {\n  options = options || {};\n  if (!options.$$prepared) {\n    var domOperation = options.domOperation || noop;\n    options.domOperation = function() {\n      options.$$domOperationFired = true;\n      domOperation();\n      domOperation = noop;\n    };\n    options.$$prepared = true;\n  }\n  return options;\n}\n\nfunction applyAnimationStyles(element, options) {\n  applyAnimationFromStyles(element, options);\n  applyAnimationToStyles(element, options);\n}\n\nfunction applyAnimationFromStyles(element, options) {\n  if (options.from) {\n    element.css(options.from);\n    options.from = null;\n  }\n}\n\nfunction applyAnimationToStyles(element, options) {\n  if (options.to) {\n    element.css(options.to);\n    options.to = null;\n  }\n}\n\nfunction mergeAnimationDetails(element, oldAnimation, newAnimation) {\n  var target = oldAnimation.options || {};\n  var newOptions = newAnimation.options || {};\n\n  var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || '');\n  var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');\n  var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);\n\n  if (newOptions.preparationClasses) {\n    target.preparationClasses = concatWithSpace(newOptions.preparationClasses, target.preparationClasses);\n    delete newOptions.preparationClasses;\n  }\n\n  // noop is basically when there is no callback; otherwise something has been set\n  var realDomOperation = target.domOperation !== noop ? target.domOperation : null;\n\n  extend(target, newOptions);\n\n  // TODO(matsko or sreeramu): proper fix is to maintain all animation callback in array and call at last,but now only leave has the callback so no issue with this.\n  if (realDomOperation) {\n    target.domOperation = realDomOperation;\n  }\n\n  if (classes.addClass) {\n    target.addClass = classes.addClass;\n  } else {\n    target.addClass = null;\n  }\n\n  if (classes.removeClass) {\n    target.removeClass = classes.removeClass;\n  } else {\n    target.removeClass = null;\n  }\n\n  oldAnimation.addClass = target.addClass;\n  oldAnimation.removeClass = target.removeClass;\n\n  return target;\n}\n\nfunction resolveElementClasses(existing, toAdd, toRemove) {\n  var ADD_CLASS = 1;\n  var REMOVE_CLASS = -1;\n\n  var flags = {};\n  existing = splitClassesToLookup(existing);\n\n  toAdd = splitClassesToLookup(toAdd);\n  forEach(toAdd, function(value, key) {\n    flags[key] = ADD_CLASS;\n  });\n\n  toRemove = splitClassesToLookup(toRemove);\n  forEach(toRemove, function(value, key) {\n    flags[key] = flags[key] === ADD_CLASS ? null : REMOVE_CLASS;\n  });\n\n  var classes = {\n    addClass: '',\n    removeClass: ''\n  };\n\n  forEach(flags, function(val, klass) {\n    var prop, allow;\n    if (val === ADD_CLASS) {\n      prop = 'addClass';\n      allow = !existing[klass] || existing[klass + REMOVE_CLASS_SUFFIX];\n    } else if (val === REMOVE_CLASS) {\n      prop = 'removeClass';\n      allow = existing[klass] || existing[klass + ADD_CLASS_SUFFIX];\n    }\n    if (allow) {\n      if (classes[prop].length) {\n        classes[prop] += ' ';\n      }\n      classes[prop] += klass;\n    }\n  });\n\n  function splitClassesToLookup(classes) {\n    if (isString(classes)) {\n      classes = classes.split(' ');\n    }\n\n    var obj = {};\n    forEach(classes, function(klass) {\n      // sometimes the split leaves empty string values\n      // incase extra spaces were applied to the options\n      if (klass.length) {\n        obj[klass] = true;\n      }\n    });\n    return obj;\n  }\n\n  return classes;\n}\n\nfunction getDomNode(element) {\n  return (element instanceof jqLite) ? element[0] : element;\n}\n\nfunction applyGeneratedPreparationClasses($$jqLite, element, event, options) {\n  var classes = '';\n  if (event) {\n    classes = pendClasses(event, EVENT_CLASS_PREFIX, true);\n  }\n  if (options.addClass) {\n    classes = concatWithSpace(classes, pendClasses(options.addClass, ADD_CLASS_SUFFIX));\n  }\n  if (options.removeClass) {\n    classes = concatWithSpace(classes, pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX));\n  }\n  if (classes.length) {\n    options.preparationClasses = classes;\n    element.addClass(classes);\n  }\n}\n\nfunction clearGeneratedClasses(element, options) {\n  if (options.preparationClasses) {\n    element.removeClass(options.preparationClasses);\n    options.preparationClasses = null;\n  }\n  if (options.activeClasses) {\n    element.removeClass(options.activeClasses);\n    options.activeClasses = null;\n  }\n}\n\nfunction blockKeyframeAnimations(node, applyBlock) {\n  var value = applyBlock ? 'paused' : '';\n  var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;\n  applyInlineStyle(node, [key, value]);\n  return [key, value];\n}\n\nfunction applyInlineStyle(node, styleTuple) {\n  var prop = styleTuple[0];\n  var value = styleTuple[1];\n  node.style[prop] = value;\n}\n\nfunction concatWithSpace(a,b) {\n  if (!a) return b;\n  if (!b) return a;\n  return a + ' ' + b;\n}\n\nvar helpers = {\n  blockTransitions: function(node, duration) {\n    // we use a negative delay value since it performs blocking\n    // yet it doesn't kill any existing transitions running on the\n    // same element which makes this safe for class-based animations\n    var value = duration ? '-' + duration + 's' : '';\n    applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);\n    return [TRANSITION_DELAY_PROP, value];\n  }\n};\n\nvar $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {\n  var queue, cancelFn;\n\n  function scheduler(tasks) {\n    // we make a copy since RAFScheduler mutates the state\n    // of the passed in array variable and this would be difficult\n    // to track down on the outside code\n    queue = queue.concat(tasks);\n    nextTick();\n  }\n\n  queue = scheduler.queue = [];\n\n  /* waitUntilQuiet does two things:\n   * 1. It will run the FINAL `fn` value only when an uncanceled RAF has passed through\n   * 2. It will delay the next wave of tasks from running until the quiet `fn` has run.\n   *\n   * The motivation here is that animation code can request more time from the scheduler\n   * before the next wave runs. This allows for certain DOM properties such as classes to\n   * be resolved in time for the next animation to run.\n   */\n  scheduler.waitUntilQuiet = function(fn) {\n    if (cancelFn) cancelFn();\n\n    cancelFn = $$rAF(function() {\n      cancelFn = null;\n      fn();\n      nextTick();\n    });\n  };\n\n  return scheduler;\n\n  function nextTick() {\n    if (!queue.length) return;\n\n    var items = queue.shift();\n    for (var i = 0; i < items.length; i++) {\n      items[i]();\n    }\n\n    if (!cancelFn) {\n      $$rAF(function() {\n        if (!cancelFn) nextTick();\n      });\n    }\n  }\n}];\n\n/**\n * @ngdoc directive\n * @name ngAnimateChildren\n * @restrict AE\n * @element ANY\n *\n * @description\n *\n * ngAnimateChildren allows you to specify that children of this element should animate even if any\n * of the children's parents are currently animating. By default, when an element has an active `enter`, `leave`, or `move`\n * (structural) animation, child elements that also have an active structural animation are not animated.\n *\n * Note that even if `ngAnimateChildren` is set, no child animations will run when the parent element is removed from the DOM (`leave` animation).\n *\n *\n * @param {string} ngAnimateChildren If the value is empty, `true` or `on`,\n *     then child animations are allowed. If the value is `false`, child animations are not allowed.\n *\n * @example\n * <example module=\"ngAnimateChildren\" name=\"ngAnimateChildren\" deps=\"angular-animate.js\" animations=\"true\">\n     <file name=\"index.html\">\n       <div ng-controller=\"MainController as main\">\n         <label>Show container? <input type=\"checkbox\" ng-model=\"main.enterElement\" /></label>\n         <label>Animate children? <input type=\"checkbox\" ng-model=\"main.animateChildren\" /></label>\n         <hr>\n         <div ng-animate-children=\"{{main.animateChildren}}\">\n           <div ng-if=\"main.enterElement\" class=\"container\">\n             List of items:\n             <div ng-repeat=\"item in [0, 1, 2, 3]\" class=\"item\">Item {{item}}</div>\n           </div>\n         </div>\n       </div>\n     </file>\n     <file name=\"animations.css\">\n\n      .container.ng-enter,\n      .container.ng-leave {\n        transition: all ease 1.5s;\n      }\n\n      .container.ng-enter,\n      .container.ng-leave-active {\n        opacity: 0;\n      }\n\n      .container.ng-leave,\n      .container.ng-enter-active {\n        opacity: 1;\n      }\n\n      .item {\n        background: firebrick;\n        color: #FFF;\n        margin-bottom: 10px;\n      }\n\n      .item.ng-enter,\n      .item.ng-leave {\n        transition: transform 1.5s ease;\n      }\n\n      .item.ng-enter {\n        transform: translateX(50px);\n      }\n\n      .item.ng-enter-active {\n        transform: translateX(0);\n      }\n    </file>\n    <file name=\"script.js\">\n      angular.module('ngAnimateChildren', ['ngAnimate'])\n        .controller('MainController', function MainController() {\n          this.animateChildren = false;\n          this.enterElement = false;\n        });\n    </file>\n  </example>\n */\nvar $$AnimateChildrenDirective = ['$interpolate', function($interpolate) {\n  return {\n    link: function(scope, element, attrs) {\n      var val = attrs.ngAnimateChildren;\n      if (isString(val) && val.length === 0) { //empty attribute\n        element.data(NG_ANIMATE_CHILDREN_DATA, true);\n      } else {\n        // Interpolate and set the value, so that it is available to\n        // animations that run right after compilation\n        setData($interpolate(val)(scope));\n        attrs.$observe('ngAnimateChildren', setData);\n      }\n\n      function setData(value) {\n        value = value === 'on' || value === 'true';\n        element.data(NG_ANIMATE_CHILDREN_DATA, value);\n      }\n    }\n  };\n}];\n\n/* exported $AnimateCssProvider */\n\nvar ANIMATE_TIMER_KEY = '$$animateCss';\n\n/**\n * @ngdoc service\n * @name $animateCss\n * @kind object\n *\n * @description\n * The `$animateCss` service is a useful utility to trigger customized CSS-based transitions/keyframes\n * from a JavaScript-based animation or directly from a directive. The purpose of `$animateCss` is NOT\n * to side-step how `$animate` and ngAnimate work, but the goal is to allow pre-existing animations or\n * directives to create more complex animations that can be purely driven using CSS code.\n *\n * Note that only browsers that support CSS transitions and/or keyframe animations are capable of\n * rendering animations triggered via `$animateCss` (bad news for IE9 and lower).\n *\n * ## General Use\n * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that\n * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however,\n * any automatic control over cancelling animations and/or preventing animations from being run on\n * child elements will not be handled by AngularJS. For this to work as expected, please use `$animate` to\n * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger\n * the CSS animation.\n *\n * The example below shows how we can create a folding animation on an element using `ng-if`:\n *\n * ```html\n * <!-- notice the `fold-animation` CSS class -->\n * <div ng-if=\"onOff\" class=\"fold-animation\">\n *   This element will go BOOM\n * </div>\n * <button ng-click=\"onOff=true\">Fold In</button>\n * ```\n *\n * Now we create the **JavaScript animation** that will trigger the CSS transition:\n *\n * ```js\n * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {\n *   return {\n *     enter: function(element, doneFn) {\n *       var height = element[0].offsetHeight;\n *       return $animateCss(element, {\n *         from: { height:'0px' },\n *         to: { height:height + 'px' },\n *         duration: 1 // one second\n *       });\n *     }\n *   }\n * }]);\n * ```\n *\n * ## More Advanced Uses\n *\n * `$animateCss` is the underlying code that ngAnimate uses to power **CSS-based animations** behind the scenes. Therefore CSS hooks\n * like `.ng-EVENT`, `.ng-EVENT-active`, `.ng-EVENT-stagger` are all features that can be triggered using `$animateCss` via JavaScript code.\n *\n * This also means that just about any combination of adding classes, removing classes, setting styles, dynamically setting a keyframe animation,\n * applying a hardcoded duration or delay value, changing the animation easing or applying a stagger animation are all options that work with\n * `$animateCss`. The service itself is smart enough to figure out the combination of options and examine the element styling properties in order\n * to provide a working animation that will run in CSS.\n *\n * The example below showcases a more advanced version of the `.fold-animation` from the example above:\n *\n * ```js\n * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {\n *   return {\n *     enter: function(element, doneFn) {\n *       var height = element[0].offsetHeight;\n *       return $animateCss(element, {\n *         addClass: 'red large-text pulse-twice',\n *         easing: 'ease-out',\n *         from: { height:'0px' },\n *         to: { height:height + 'px' },\n *         duration: 1 // one second\n *       });\n *     }\n *   }\n * }]);\n * ```\n *\n * Since we're adding/removing CSS classes then the CSS transition will also pick those up:\n *\n * ```css\n * /&#42; since a hardcoded duration value of 1 was provided in the JavaScript animation code,\n * the CSS classes below will be transitioned despite them being defined as regular CSS classes &#42;/\n * .red { background:red; }\n * .large-text { font-size:20px; }\n *\n * /&#42; we can also use a keyframe animation and $animateCss will make it work alongside the transition &#42;/\n * .pulse-twice {\n *   animation: 0.5s pulse linear 2;\n *   -webkit-animation: 0.5s pulse linear 2;\n * }\n *\n * @keyframes pulse {\n *   from { transform: scale(0.5); }\n *   to { transform: scale(1.5); }\n * }\n *\n * @-webkit-keyframes pulse {\n *   from { -webkit-transform: scale(0.5); }\n *   to { -webkit-transform: scale(1.5); }\n * }\n * ```\n *\n * Given this complex combination of CSS classes, styles and options, `$animateCss` will figure everything out and make the animation happen.\n *\n * ## How the Options are handled\n *\n * `$animateCss` is very versatile and intelligent when it comes to figuring out what configurations to apply to the element to ensure the animation\n * works with the options provided. Say for example we were adding a class that contained a keyframe value and we wanted to also animate some inline\n * styles using the `from` and `to` properties.\n *\n * ```js\n * var animator = $animateCss(element, {\n *   from: { background:'red' },\n *   to: { background:'blue' }\n * });\n * animator.start();\n * ```\n *\n * ```css\n * .rotating-animation {\n *   animation:0.5s rotate linear;\n *   -webkit-animation:0.5s rotate linear;\n * }\n *\n * @keyframes rotate {\n *   from { transform: rotate(0deg); }\n *   to { transform: rotate(360deg); }\n * }\n *\n * @-webkit-keyframes rotate {\n *   from { -webkit-transform: rotate(0deg); }\n *   to { -webkit-transform: rotate(360deg); }\n * }\n * ```\n *\n * The missing pieces here are that we do not have a transition set (within the CSS code nor within the `$animateCss` options) and the duration of the animation is\n * going to be detected from what the keyframe styles on the CSS class are. In this event, `$animateCss` will automatically create an inline transition\n * style matching the duration detected from the keyframe style (which is present in the CSS class that is being added) and then prepare both the transition\n * and keyframe animations to run in parallel on the element. Then when the animation is underway the provided `from` and `to` CSS styles will be applied\n * and spread across the transition and keyframe animation.\n *\n * ## What is returned\n *\n * `$animateCss` works in two stages: a preparation phase and an animation phase. Therefore when `$animateCss` is first called it will NOT actually\n * start the animation. All that is going on here is that the element is being prepared for the animation (which means that the generated CSS classes are\n * added and removed on the element). Once `$animateCss` is called it will return an object with the following properties:\n *\n * ```js\n * var animator = $animateCss(element, { ... });\n * ```\n *\n * Now what do the contents of our `animator` variable look like:\n *\n * ```js\n * {\n *   // starts the animation\n *   start: Function,\n *\n *   // ends (aborts) the animation\n *   end: Function\n * }\n * ```\n *\n * To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends.\n * If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and styles may have been\n * applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties\n * and that changing them will not reconfigure the parameters of the animation.\n *\n * ### runner.done() vs runner.then()\n * It is documented that `animation.start()` will return a promise object and this is true, however, there is also an additional method available on the\n * runner called `.done(callbackFn)`. The done method works the same as `.finally(callbackFn)`, however, it does **not trigger a digest to occur**.\n * Therefore, for performance reasons, it's always best to use `runner.done(callback)` instead of `runner.then()`, `runner.catch()` or `runner.finally()`\n * unless you really need a digest to kick off afterwards.\n *\n * Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss\n * (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code).\n * Check the {@link ngAnimate.$animateCss#usage animation code above} to see how this works.\n *\n * @param {DOMElement} element the element that will be animated\n * @param {object} options the animation-related options that will be applied during the animation\n *\n * * `event` - The DOM event (e.g. enter, leave, move). When used, a generated CSS class of `ng-EVENT` and `ng-EVENT-active` will be applied\n * to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.)\n * * `structural` - Indicates that the `ng-` prefix will be added to the event class. Setting to `false` or omitting will turn `ng-EVENT` and\n * `ng-EVENT-active` in `EVENT` and `EVENT-active`. Unused if `event` is omitted.\n * * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both).\n * * `transitionStyle` - The raw CSS transition style that will be used (e.g. `1s linear all`).\n * * `keyframeStyle` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`).\n * * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation.\n * * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition.\n * * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation.\n * * `removeClass` - A space separated list of CSS classes that will be removed from the element and spread across the animation.\n * * `duration` - A number value representing the total duration of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `0`\n * is provided then the animation will be skipped entirely.\n * * `delay` - A number value representing the total delay of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `true` is\n * used then whatever delay value is detected from the CSS classes will be mirrored on the elements styles (e.g. by setting delay true then the style value\n * of the element will be `transition-delay: DETECTED_VALUE`). Using `true` is useful when you want the CSS classes and inline styles to all share the same\n * CSS delay value.\n * * `stagger` - A numeric time value representing the delay between successively animated elements\n * ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})\n * * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a\n *   `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)\n * * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occurring on the classes being added and removed.)\n * * `cleanupStyles` - Whether or not the provided `from` and `to` styles will be removed once\n *    the animation is closed. This is useful for when the styles are used purely for the sake of\n *    the animation and do not have a lasting visual effect on the element (e.g. a collapse and open animation).\n *    By default this value is set to `false`.\n *\n * @return {object} an object with start and end methods and details about the animation.\n *\n * * `start` - The method to start the animation. This will return a `Promise` when called.\n * * `end` - This method will cancel the animation and remove all applied CSS classes and styles.\n */\nvar ONE_SECOND = 1000;\n\nvar ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;\nvar CLOSING_TIME_BUFFER = 1.5;\n\nvar DETECT_CSS_PROPERTIES = {\n  transitionDuration:      TRANSITION_DURATION_PROP,\n  transitionDelay:         TRANSITION_DELAY_PROP,\n  transitionProperty:      TRANSITION_PROP + PROPERTY_KEY,\n  animationDuration:       ANIMATION_DURATION_PROP,\n  animationDelay:          ANIMATION_DELAY_PROP,\n  animationIterationCount: ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY\n};\n\nvar DETECT_STAGGER_CSS_PROPERTIES = {\n  transitionDuration:      TRANSITION_DURATION_PROP,\n  transitionDelay:         TRANSITION_DELAY_PROP,\n  animationDuration:       ANIMATION_DURATION_PROP,\n  animationDelay:          ANIMATION_DELAY_PROP\n};\n\nfunction getCssKeyframeDurationStyle(duration) {\n  return [ANIMATION_DURATION_PROP, duration + 's'];\n}\n\nfunction getCssDelayStyle(delay, isKeyframeAnimation) {\n  var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;\n  return [prop, delay + 's'];\n}\n\nfunction computeCssStyles($window, element, properties) {\n  var styles = Object.create(null);\n  var detectedStyles = $window.getComputedStyle(element) || {};\n  forEach(properties, function(formalStyleName, actualStyleName) {\n    var val = detectedStyles[formalStyleName];\n    if (val) {\n      var c = val.charAt(0);\n\n      // only numerical-based values have a negative sign or digit as the first value\n      if (c === '-' || c === '+' || c >= 0) {\n        val = parseMaxTime(val);\n      }\n\n      // by setting this to null in the event that the delay is not set or is set directly as 0\n      // then we can still allow for negative values to be used later on and not mistake this\n      // value for being greater than any other negative value.\n      if (val === 0) {\n        val = null;\n      }\n      styles[actualStyleName] = val;\n    }\n  });\n\n  return styles;\n}\n\nfunction parseMaxTime(str) {\n  var maxValue = 0;\n  var values = str.split(/\\s*,\\s*/);\n  forEach(values, function(value) {\n    // it's always safe to consider only second values and omit `ms` values since\n    // getComputedStyle will always handle the conversion for us\n    if (value.charAt(value.length - 1) === 's') {\n      value = value.substring(0, value.length - 1);\n    }\n    value = parseFloat(value) || 0;\n    maxValue = maxValue ? Math.max(value, maxValue) : value;\n  });\n  return maxValue;\n}\n\nfunction truthyTimingValue(val) {\n  return val === 0 || val != null;\n}\n\nfunction getCssTransitionDurationStyle(duration, applyOnlyDuration) {\n  var style = TRANSITION_PROP;\n  var value = duration + 's';\n  if (applyOnlyDuration) {\n    style += DURATION_KEY;\n  } else {\n    value += ' linear all';\n  }\n  return [style, value];\n}\n\n// we do not reassign an already present style value since\n// if we detect the style property value again we may be\n// detecting styles that were added via the `from` styles.\n// We make use of `isDefined` here since an empty string\n// or null value (which is what getPropertyValue will return\n// for a non-existing style) will still be marked as a valid\n// value for the style (a falsy value implies that the style\n// is to be removed at the end of the animation). If we had a simple\n// \"OR\" statement then it would not be enough to catch that.\nfunction registerRestorableStyles(backup, node, properties) {\n  forEach(properties, function(prop) {\n    backup[prop] = isDefined(backup[prop])\n        ? backup[prop]\n        : node.style.getPropertyValue(prop);\n  });\n}\n\nvar $AnimateCssProvider = ['$animateProvider', /** @this */ function($animateProvider) {\n\n  this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout', '$$animateCache',\n               '$$forceReflow', '$sniffer', '$$rAFScheduler', '$$animateQueue',\n       function($window,   $$jqLite,   $$AnimateRunner,   $timeout,   $$animateCache,\n                $$forceReflow,   $sniffer,   $$rAFScheduler, $$animateQueue) {\n\n    var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\n\n    function computeCachedCssStyles(node, className, cacheKey, allowNoDuration, properties) {\n      var timings = $$animateCache.get(cacheKey);\n\n      if (!timings) {\n        timings = computeCssStyles($window, node, properties);\n        if (timings.animationIterationCount === 'infinite') {\n          timings.animationIterationCount = 1;\n        }\n      }\n\n      // if a css animation has no duration we\n      // should mark that so that repeated addClass/removeClass calls are skipped\n      var hasDuration = allowNoDuration || (timings.transitionDuration > 0 || timings.animationDuration > 0);\n\n      // we keep putting this in multiple times even though the value and the cacheKey are the same\n      // because we're keeping an internal tally of how many duplicate animations are detected.\n      $$animateCache.put(cacheKey, timings, hasDuration);\n\n      return timings;\n    }\n\n    function computeCachedCssStaggerStyles(node, className, cacheKey, properties) {\n      var stagger;\n      var staggerCacheKey = 'stagger-' + cacheKey;\n\n      // if we have one or more existing matches of matching elements\n      // containing the same parent + CSS styles (which is how cacheKey works)\n      // then staggering is possible\n      if ($$animateCache.count(cacheKey) > 0) {\n        stagger = $$animateCache.get(staggerCacheKey);\n\n        if (!stagger) {\n          var staggerClassName = pendClasses(className, '-stagger');\n\n          $$jqLite.addClass(node, staggerClassName);\n\n          stagger = computeCssStyles($window, node, properties);\n\n          // force the conversion of a null value to zero incase not set\n          stagger.animationDuration = Math.max(stagger.animationDuration, 0);\n          stagger.transitionDuration = Math.max(stagger.transitionDuration, 0);\n\n          $$jqLite.removeClass(node, staggerClassName);\n\n          $$animateCache.put(staggerCacheKey, stagger, true);\n        }\n      }\n\n      return stagger || {};\n    }\n\n    var rafWaitQueue = [];\n    function waitUntilQuiet(callback) {\n      rafWaitQueue.push(callback);\n      $$rAFScheduler.waitUntilQuiet(function() {\n        $$animateCache.flush();\n\n        // DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable.\n        // PLEASE EXAMINE THE `$$forceReflow` service to understand why.\n        var pageWidth = $$forceReflow();\n\n        // we use a for loop to ensure that if the queue is changed\n        // during this looping then it will consider new requests\n        for (var i = 0; i < rafWaitQueue.length; i++) {\n          rafWaitQueue[i](pageWidth);\n        }\n        rafWaitQueue.length = 0;\n      });\n    }\n\n    function computeTimings(node, className, cacheKey, allowNoDuration) {\n      var timings = computeCachedCssStyles(node, className, cacheKey, allowNoDuration, DETECT_CSS_PROPERTIES);\n      var aD = timings.animationDelay;\n      var tD = timings.transitionDelay;\n      timings.maxDelay = aD && tD\n          ? Math.max(aD, tD)\n          : (aD || tD);\n      timings.maxDuration = Math.max(\n          timings.animationDuration * timings.animationIterationCount,\n          timings.transitionDuration);\n\n      return timings;\n    }\n\n    return function init(element, initialOptions) {\n      // all of the animation functions should create\n      // a copy of the options data, however, if a\n      // parent service has already created a copy then\n      // we should stick to using that\n      var options = initialOptions || {};\n      if (!options.$$prepared) {\n        options = prepareAnimationOptions(copy(options));\n      }\n\n      var restoreStyles = {};\n      var node = getDomNode(element);\n      if (!node\n          || !node.parentNode\n          || !$$animateQueue.enabled()) {\n        return closeAndReturnNoopAnimator();\n      }\n\n      var temporaryStyles = [];\n      var classes = element.attr('class');\n      var styles = packageStyles(options);\n      var animationClosed;\n      var animationPaused;\n      var animationCompleted;\n      var runner;\n      var runnerHost;\n      var maxDelay;\n      var maxDelayTime;\n      var maxDuration;\n      var maxDurationTime;\n      var startTime;\n      var events = [];\n\n      if (options.duration === 0 || (!$sniffer.animations && !$sniffer.transitions)) {\n        return closeAndReturnNoopAnimator();\n      }\n\n      var method = options.event && isArray(options.event)\n            ? options.event.join(' ')\n            : options.event;\n\n      var isStructural = method && options.structural;\n      var structuralClassName = '';\n      var addRemoveClassName = '';\n\n      if (isStructural) {\n        structuralClassName = pendClasses(method, EVENT_CLASS_PREFIX, true);\n      } else if (method) {\n        structuralClassName = method;\n      }\n\n      if (options.addClass) {\n        addRemoveClassName += pendClasses(options.addClass, ADD_CLASS_SUFFIX);\n      }\n\n      if (options.removeClass) {\n        if (addRemoveClassName.length) {\n          addRemoveClassName += ' ';\n        }\n        addRemoveClassName += pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX);\n      }\n\n      // there may be a situation where a structural animation is combined together\n      // with CSS classes that need to resolve before the animation is computed.\n      // However this means that there is no explicit CSS code to block the animation\n      // from happening (by setting 0s none in the class name). If this is the case\n      // we need to apply the classes before the first rAF so we know to continue if\n      // there actually is a detected transition or keyframe animation\n      if (options.applyClassesEarly && addRemoveClassName.length) {\n        applyAnimationClasses(element, options);\n      }\n\n      var preparationClasses = [structuralClassName, addRemoveClassName].join(' ').trim();\n      var fullClassName = classes + ' ' + preparationClasses;\n      var hasToStyles = styles.to && Object.keys(styles.to).length > 0;\n      var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0;\n\n      // there is no way we can trigger an animation if no styles and\n      // no classes are being applied which would then trigger a transition,\n      // unless there a is raw keyframe value that is applied to the element.\n      if (!containsKeyframeAnimation\n           && !hasToStyles\n           && !preparationClasses) {\n        return closeAndReturnNoopAnimator();\n      }\n\n      var stagger, cacheKey = $$animateCache.cacheKey(node, method, options.addClass, options.removeClass);\n      if ($$animateCache.containsCachedAnimationWithoutDuration(cacheKey)) {\n        preparationClasses = null;\n        return closeAndReturnNoopAnimator();\n      }\n\n      if (options.stagger > 0) {\n        var staggerVal = parseFloat(options.stagger);\n        stagger = {\n          transitionDelay: staggerVal,\n          animationDelay: staggerVal,\n          transitionDuration: 0,\n          animationDuration: 0\n        };\n      } else {\n        stagger = computeCachedCssStaggerStyles(node, preparationClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);\n      }\n\n      if (!options.$$skipPreparationClasses) {\n        $$jqLite.addClass(element, preparationClasses);\n      }\n\n      var applyOnlyDuration;\n\n      if (options.transitionStyle) {\n        var transitionStyle = [TRANSITION_PROP, options.transitionStyle];\n        applyInlineStyle(node, transitionStyle);\n        temporaryStyles.push(transitionStyle);\n      }\n\n      if (options.duration >= 0) {\n        applyOnlyDuration = node.style[TRANSITION_PROP].length > 0;\n        var durationStyle = getCssTransitionDurationStyle(options.duration, applyOnlyDuration);\n\n        // we set the duration so that it will be picked up by getComputedStyle later\n        applyInlineStyle(node, durationStyle);\n        temporaryStyles.push(durationStyle);\n      }\n\n      if (options.keyframeStyle) {\n        var keyframeStyle = [ANIMATION_PROP, options.keyframeStyle];\n        applyInlineStyle(node, keyframeStyle);\n        temporaryStyles.push(keyframeStyle);\n      }\n\n      var itemIndex = stagger\n          ? options.staggerIndex >= 0\n              ? options.staggerIndex\n              : $$animateCache.count(cacheKey)\n          : 0;\n\n      var isFirst = itemIndex === 0;\n\n      // this is a pre-emptive way of forcing the setup classes to be added and applied INSTANTLY\n      // without causing any combination of transitions to kick in. By adding a negative delay value\n      // it forces the setup class' transition to end immediately. We later then remove the negative\n      // transition delay to allow for the transition to naturally do it's thing. The beauty here is\n      // that if there is no transition defined then nothing will happen and this will also allow\n      // other transitions to be stacked on top of each other without any chopping them out.\n      if (isFirst && !options.skipBlocking) {\n        helpers.blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);\n      }\n\n      var timings = computeTimings(node, fullClassName, cacheKey, !isStructural);\n      var relativeDelay = timings.maxDelay;\n      maxDelay = Math.max(relativeDelay, 0);\n      maxDuration = timings.maxDuration;\n\n      var flags = {};\n      flags.hasTransitions          = timings.transitionDuration > 0;\n      flags.hasAnimations           = timings.animationDuration > 0;\n      flags.hasTransitionAll        = flags.hasTransitions && timings.transitionProperty === 'all';\n      flags.applyTransitionDuration = hasToStyles && (\n                                        (flags.hasTransitions && !flags.hasTransitionAll)\n                                         || (flags.hasAnimations && !flags.hasTransitions));\n      flags.applyAnimationDuration  = options.duration && flags.hasAnimations;\n      flags.applyTransitionDelay    = truthyTimingValue(options.delay) && (flags.applyTransitionDuration || flags.hasTransitions);\n      flags.applyAnimationDelay     = truthyTimingValue(options.delay) && flags.hasAnimations;\n      flags.recalculateTimingStyles = addRemoveClassName.length > 0;\n\n      if (flags.applyTransitionDuration || flags.applyAnimationDuration) {\n        maxDuration = options.duration ? parseFloat(options.duration) : maxDuration;\n\n        if (flags.applyTransitionDuration) {\n          flags.hasTransitions = true;\n          timings.transitionDuration = maxDuration;\n          applyOnlyDuration = node.style[TRANSITION_PROP + PROPERTY_KEY].length > 0;\n          temporaryStyles.push(getCssTransitionDurationStyle(maxDuration, applyOnlyDuration));\n        }\n\n        if (flags.applyAnimationDuration) {\n          flags.hasAnimations = true;\n          timings.animationDuration = maxDuration;\n          temporaryStyles.push(getCssKeyframeDurationStyle(maxDuration));\n        }\n      }\n\n      if (maxDuration === 0 && !flags.recalculateTimingStyles) {\n        return closeAndReturnNoopAnimator();\n      }\n\n      var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX);\n\n      if (options.delay != null) {\n        var delayStyle;\n        if (typeof options.delay !== 'boolean') {\n          delayStyle = parseFloat(options.delay);\n          // number in options.delay means we have to recalculate the delay for the closing timeout\n          maxDelay = Math.max(delayStyle, 0);\n        }\n\n        if (flags.applyTransitionDelay) {\n          temporaryStyles.push(getCssDelayStyle(delayStyle));\n        }\n\n        if (flags.applyAnimationDelay) {\n          temporaryStyles.push(getCssDelayStyle(delayStyle, true));\n        }\n      }\n\n      // we need to recalculate the delay value since we used a pre-emptive negative\n      // delay value and the delay value is required for the final event checking. This\n      // property will ensure that this will happen after the RAF phase has passed.\n      if (options.duration == null && timings.transitionDuration > 0) {\n        flags.recalculateTimingStyles = flags.recalculateTimingStyles || isFirst;\n      }\n\n      maxDelayTime = maxDelay * ONE_SECOND;\n      maxDurationTime = maxDuration * ONE_SECOND;\n      if (!options.skipBlocking) {\n        flags.blockTransition = timings.transitionDuration > 0;\n        flags.blockKeyframeAnimation = timings.animationDuration > 0 &&\n                                       stagger.animationDelay > 0 &&\n                                       stagger.animationDuration === 0;\n      }\n\n      if (options.from) {\n        if (options.cleanupStyles) {\n          registerRestorableStyles(restoreStyles, node, Object.keys(options.from));\n        }\n        applyAnimationFromStyles(element, options);\n      }\n\n      if (flags.blockTransition || flags.blockKeyframeAnimation) {\n        applyBlocking(maxDuration);\n      } else if (!options.skipBlocking) {\n        helpers.blockTransitions(node, false);\n      }\n\n      // TODO(matsko): for 1.5 change this code to have an animator object for better debugging\n      return {\n        $$willAnimate: true,\n        end: endFn,\n        start: function() {\n          if (animationClosed) return;\n\n          runnerHost = {\n            end: endFn,\n            cancel: cancelFn,\n            resume: null, //this will be set during the start() phase\n            pause: null\n          };\n\n          runner = new $$AnimateRunner(runnerHost);\n\n          waitUntilQuiet(start);\n\n          // we don't have access to pause/resume the animation\n          // since it hasn't run yet. AnimateRunner will therefore\n          // set noop functions for resume and pause and they will\n          // later be overridden once the animation is triggered\n          return runner;\n        }\n      };\n\n      function endFn() {\n        close();\n      }\n\n      function cancelFn() {\n        close(true);\n      }\n\n      function close(rejected) {\n        // if the promise has been called already then we shouldn't close\n        // the animation again\n        if (animationClosed || (animationCompleted && animationPaused)) return;\n        animationClosed = true;\n        animationPaused = false;\n\n        if (preparationClasses && !options.$$skipPreparationClasses) {\n          $$jqLite.removeClass(element, preparationClasses);\n        }\n\n        if (activeClasses) {\n          $$jqLite.removeClass(element, activeClasses);\n        }\n\n        blockKeyframeAnimations(node, false);\n        helpers.blockTransitions(node, false);\n\n        forEach(temporaryStyles, function(entry) {\n          // There is only one way to remove inline style properties entirely from elements.\n          // By using `removeProperty` this works, but we need to convert camel-cased CSS\n          // styles down to hyphenated values.\n          node.style[entry[0]] = '';\n        });\n\n        applyAnimationClasses(element, options);\n        applyAnimationStyles(element, options);\n\n        if (Object.keys(restoreStyles).length) {\n          forEach(restoreStyles, function(value, prop) {\n            if (value) {\n              node.style.setProperty(prop, value);\n            } else {\n              node.style.removeProperty(prop);\n            }\n          });\n        }\n\n        // the reason why we have this option is to allow a synchronous closing callback\n        // that is fired as SOON as the animation ends (when the CSS is removed) or if\n        // the animation never takes off at all. A good example is a leave animation since\n        // the element must be removed just after the animation is over or else the element\n        // will appear on screen for one animation frame causing an overbearing flicker.\n        if (options.onDone) {\n          options.onDone();\n        }\n\n        if (events && events.length) {\n          // Remove the transitionend / animationend listener(s)\n          element.off(events.join(' '), onAnimationProgress);\n        }\n\n        //Cancel the fallback closing timeout and remove the timer data\n        var animationTimerData = element.data(ANIMATE_TIMER_KEY);\n        if (animationTimerData) {\n          $timeout.cancel(animationTimerData[0].timer);\n          element.removeData(ANIMATE_TIMER_KEY);\n        }\n\n        // if the preparation function fails then the promise is not setup\n        if (runner) {\n          runner.complete(!rejected);\n        }\n      }\n\n      function applyBlocking(duration) {\n        if (flags.blockTransition) {\n          helpers.blockTransitions(node, duration);\n        }\n\n        if (flags.blockKeyframeAnimation) {\n          blockKeyframeAnimations(node, !!duration);\n        }\n      }\n\n      function closeAndReturnNoopAnimator() {\n        runner = new $$AnimateRunner({\n          end: endFn,\n          cancel: cancelFn\n        });\n\n        // should flush the cache animation\n        waitUntilQuiet(noop);\n        close();\n\n        return {\n          $$willAnimate: false,\n          start: function() {\n            return runner;\n          },\n          end: endFn\n        };\n      }\n\n      function onAnimationProgress(event) {\n        event.stopPropagation();\n        var ev = event.originalEvent || event;\n\n        if (ev.target !== node) {\n          // Since TransitionEvent / AnimationEvent bubble up,\n          // we have to ignore events by finished child animations\n          return;\n        }\n\n        // we now always use `Date.now()` due to the recent changes with\n        // event.timeStamp in Firefox, Webkit and Chrome (see #13494 for more info)\n        var timeStamp = ev.$manualTimeStamp || Date.now();\n\n        /* Firefox (or possibly just Gecko) likes to not round values up\n         * when a ms measurement is used for the animation */\n        var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));\n\n        /* $manualTimeStamp is a mocked timeStamp value which is set\n         * within browserTrigger(). This is only here so that tests can\n         * mock animations properly. Real events fallback to event.timeStamp,\n         * or, if they don't, then a timeStamp is automatically created for them.\n         * We're checking to see if the timeStamp surpasses the expected delay,\n         * but we're using elapsedTime instead of the timeStamp on the 2nd\n         * pre-condition since animationPauseds sometimes close off early */\n        if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {\n          // we set this flag to ensure that if the transition is paused then, when resumed,\n          // the animation will automatically close itself since transitions cannot be paused.\n          animationCompleted = true;\n          close();\n        }\n      }\n\n      function start() {\n        if (animationClosed) return;\n        if (!node.parentNode) {\n          close();\n          return;\n        }\n\n        // even though we only pause keyframe animations here the pause flag\n        // will still happen when transitions are used. Only the transition will\n        // not be paused since that is not possible. If the animation ends when\n        // paused then it will not complete until unpaused or cancelled.\n        var playPause = function(playAnimation) {\n          if (!animationCompleted) {\n            animationPaused = !playAnimation;\n            if (timings.animationDuration) {\n              var value = blockKeyframeAnimations(node, animationPaused);\n              if (animationPaused) {\n                temporaryStyles.push(value);\n              } else {\n                removeFromArray(temporaryStyles, value);\n              }\n            }\n          } else if (animationPaused && playAnimation) {\n            animationPaused = false;\n            close();\n          }\n        };\n\n        // checking the stagger duration prevents an accidentally cascade of the CSS delay style\n        // being inherited from the parent. If the transition duration is zero then we can safely\n        // rely that the delay value is an intentional stagger delay style.\n        var maxStagger = itemIndex > 0\n                         && ((timings.transitionDuration && stagger.transitionDuration === 0) ||\n                            (timings.animationDuration && stagger.animationDuration === 0))\n                         && Math.max(stagger.animationDelay, stagger.transitionDelay);\n        if (maxStagger) {\n          $timeout(triggerAnimationStart,\n                   Math.floor(maxStagger * itemIndex * ONE_SECOND),\n                   false);\n        } else {\n          triggerAnimationStart();\n        }\n\n        // this will decorate the existing promise runner with pause/resume methods\n        runnerHost.resume = function() {\n          playPause(true);\n        };\n\n        runnerHost.pause = function() {\n          playPause(false);\n        };\n\n        function triggerAnimationStart() {\n          // just incase a stagger animation kicks in when the animation\n          // itself was cancelled entirely\n          if (animationClosed) return;\n\n          applyBlocking(false);\n\n          forEach(temporaryStyles, function(entry) {\n            var key = entry[0];\n            var value = entry[1];\n            node.style[key] = value;\n          });\n\n          applyAnimationClasses(element, options);\n          $$jqLite.addClass(element, activeClasses);\n\n          if (flags.recalculateTimingStyles) {\n            fullClassName = node.getAttribute('class') + ' ' + preparationClasses;\n            cacheKey = $$animateCache.cacheKey(node, method, options.addClass, options.removeClass);\n\n            timings = computeTimings(node, fullClassName, cacheKey, false);\n            relativeDelay = timings.maxDelay;\n            maxDelay = Math.max(relativeDelay, 0);\n            maxDuration = timings.maxDuration;\n\n            if (maxDuration === 0) {\n              close();\n              return;\n            }\n\n            flags.hasTransitions = timings.transitionDuration > 0;\n            flags.hasAnimations = timings.animationDuration > 0;\n          }\n\n          if (flags.applyAnimationDelay) {\n            relativeDelay = typeof options.delay !== 'boolean' && truthyTimingValue(options.delay)\n                  ? parseFloat(options.delay)\n                  : relativeDelay;\n\n            maxDelay = Math.max(relativeDelay, 0);\n            timings.animationDelay = relativeDelay;\n            delayStyle = getCssDelayStyle(relativeDelay, true);\n            temporaryStyles.push(delayStyle);\n            node.style[delayStyle[0]] = delayStyle[1];\n          }\n\n          maxDelayTime = maxDelay * ONE_SECOND;\n          maxDurationTime = maxDuration * ONE_SECOND;\n\n          if (options.easing) {\n            var easeProp, easeVal = options.easing;\n            if (flags.hasTransitions) {\n              easeProp = TRANSITION_PROP + TIMING_KEY;\n              temporaryStyles.push([easeProp, easeVal]);\n              node.style[easeProp] = easeVal;\n            }\n            if (flags.hasAnimations) {\n              easeProp = ANIMATION_PROP + TIMING_KEY;\n              temporaryStyles.push([easeProp, easeVal]);\n              node.style[easeProp] = easeVal;\n            }\n          }\n\n          if (timings.transitionDuration) {\n            events.push(TRANSITIONEND_EVENT);\n          }\n\n          if (timings.animationDuration) {\n            events.push(ANIMATIONEND_EVENT);\n          }\n\n          startTime = Date.now();\n          var timerTime = maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime;\n          var endTime = startTime + timerTime;\n\n          var animationsData = element.data(ANIMATE_TIMER_KEY) || [];\n          var setupFallbackTimer = true;\n          if (animationsData.length) {\n            var currentTimerData = animationsData[0];\n            setupFallbackTimer = endTime > currentTimerData.expectedEndTime;\n            if (setupFallbackTimer) {\n              $timeout.cancel(currentTimerData.timer);\n            } else {\n              animationsData.push(close);\n            }\n          }\n\n          if (setupFallbackTimer) {\n            var timer = $timeout(onAnimationExpired, timerTime, false);\n            animationsData[0] = {\n              timer: timer,\n              expectedEndTime: endTime\n            };\n            animationsData.push(close);\n            element.data(ANIMATE_TIMER_KEY, animationsData);\n          }\n\n          if (events.length) {\n            element.on(events.join(' '), onAnimationProgress);\n          }\n\n          if (options.to) {\n            if (options.cleanupStyles) {\n              registerRestorableStyles(restoreStyles, node, Object.keys(options.to));\n            }\n            applyAnimationToStyles(element, options);\n          }\n        }\n\n        function onAnimationExpired() {\n          var animationsData = element.data(ANIMATE_TIMER_KEY);\n\n          // this will be false in the event that the element was\n          // removed from the DOM (via a leave animation or something\n          // similar)\n          if (animationsData) {\n            for (var i = 1; i < animationsData.length; i++) {\n              animationsData[i]();\n            }\n            element.removeData(ANIMATE_TIMER_KEY);\n          }\n        }\n      }\n    };\n  }];\n}];\n\nvar $$AnimateCssDriverProvider = ['$$animationProvider', /** @this */ function($$animationProvider) {\n  $$animationProvider.drivers.push('$$animateCssDriver');\n\n  var NG_ANIMATE_SHIM_CLASS_NAME = 'ng-animate-shim';\n  var NG_ANIMATE_ANCHOR_CLASS_NAME = 'ng-anchor';\n\n  var NG_OUT_ANCHOR_CLASS_NAME = 'ng-anchor-out';\n  var NG_IN_ANCHOR_CLASS_NAME = 'ng-anchor-in';\n\n  function isDocumentFragment(node) {\n    return node.parentNode && node.parentNode.nodeType === 11;\n  }\n\n  this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$sniffer', '$$jqLite', '$document',\n       function($animateCss,   $rootScope,   $$AnimateRunner,   $rootElement,   $sniffer,   $$jqLite,   $document) {\n\n    // only browsers that support these properties can render animations\n    if (!$sniffer.animations && !$sniffer.transitions) return noop;\n\n    var bodyNode = $document[0].body;\n    var rootNode = getDomNode($rootElement);\n\n    var rootBodyElement = jqLite(\n      // this is to avoid using something that exists outside of the body\n      // we also special case the doc fragment case because our unit test code\n      // appends the $rootElement to the body after the app has been bootstrapped\n      isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode\n    );\n\n    return function initDriverFn(animationDetails) {\n      return animationDetails.from && animationDetails.to\n          ? prepareFromToAnchorAnimation(animationDetails.from,\n                                         animationDetails.to,\n                                         animationDetails.classes,\n                                         animationDetails.anchors)\n          : prepareRegularAnimation(animationDetails);\n    };\n\n    function filterCssClasses(classes) {\n      //remove all the `ng-` stuff\n      return classes.replace(/\\bng-\\S+\\b/g, '');\n    }\n\n    function getUniqueValues(a, b) {\n      if (isString(a)) a = a.split(' ');\n      if (isString(b)) b = b.split(' ');\n      return a.filter(function(val) {\n        return b.indexOf(val) === -1;\n      }).join(' ');\n    }\n\n    function prepareAnchoredAnimation(classes, outAnchor, inAnchor) {\n      var clone = jqLite(getDomNode(outAnchor).cloneNode(true));\n      var startingClasses = filterCssClasses(getClassVal(clone));\n\n      outAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);\n      inAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);\n\n      clone.addClass(NG_ANIMATE_ANCHOR_CLASS_NAME);\n\n      rootBodyElement.append(clone);\n\n      var animatorIn, animatorOut = prepareOutAnimation();\n\n      // the user may not end up using the `out` animation and\n      // only making use of the `in` animation or vice-versa.\n      // In either case we should allow this and not assume the\n      // animation is over unless both animations are not used.\n      if (!animatorOut) {\n        animatorIn = prepareInAnimation();\n        if (!animatorIn) {\n          return end();\n        }\n      }\n\n      var startingAnimator = animatorOut || animatorIn;\n\n      return {\n        start: function() {\n          var runner;\n\n          var currentAnimation = startingAnimator.start();\n          currentAnimation.done(function() {\n            currentAnimation = null;\n            if (!animatorIn) {\n              animatorIn = prepareInAnimation();\n              if (animatorIn) {\n                currentAnimation = animatorIn.start();\n                currentAnimation.done(function() {\n                  currentAnimation = null;\n                  end();\n                  runner.complete();\n                });\n                return currentAnimation;\n              }\n            }\n            // in the event that there is no `in` animation\n            end();\n            runner.complete();\n          });\n\n          runner = new $$AnimateRunner({\n            end: endFn,\n            cancel: endFn\n          });\n\n          return runner;\n\n          function endFn() {\n            if (currentAnimation) {\n              currentAnimation.end();\n            }\n          }\n        }\n      };\n\n      function calculateAnchorStyles(anchor) {\n        var styles = {};\n\n        var coords = getDomNode(anchor).getBoundingClientRect();\n\n        // we iterate directly since safari messes up and doesn't return\n        // all the keys for the coords object when iterated\n        forEach(['width','height','top','left'], function(key) {\n          var value = coords[key];\n          switch (key) {\n            case 'top':\n              value += bodyNode.scrollTop;\n              break;\n            case 'left':\n              value += bodyNode.scrollLeft;\n              break;\n          }\n          styles[key] = Math.floor(value) + 'px';\n        });\n        return styles;\n      }\n\n      function prepareOutAnimation() {\n        var animator = $animateCss(clone, {\n          addClass: NG_OUT_ANCHOR_CLASS_NAME,\n          delay: true,\n          from: calculateAnchorStyles(outAnchor)\n        });\n\n        // read the comment within `prepareRegularAnimation` to understand\n        // why this check is necessary\n        return animator.$$willAnimate ? animator : null;\n      }\n\n      function getClassVal(element) {\n        return element.attr('class') || '';\n      }\n\n      function prepareInAnimation() {\n        var endingClasses = filterCssClasses(getClassVal(inAnchor));\n        var toAdd = getUniqueValues(endingClasses, startingClasses);\n        var toRemove = getUniqueValues(startingClasses, endingClasses);\n\n        var animator = $animateCss(clone, {\n          to: calculateAnchorStyles(inAnchor),\n          addClass: NG_IN_ANCHOR_CLASS_NAME + ' ' + toAdd,\n          removeClass: NG_OUT_ANCHOR_CLASS_NAME + ' ' + toRemove,\n          delay: true\n        });\n\n        // read the comment within `prepareRegularAnimation` to understand\n        // why this check is necessary\n        return animator.$$willAnimate ? animator : null;\n      }\n\n      function end() {\n        clone.remove();\n        outAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);\n        inAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);\n      }\n    }\n\n    function prepareFromToAnchorAnimation(from, to, classes, anchors) {\n      var fromAnimation = prepareRegularAnimation(from, noop);\n      var toAnimation = prepareRegularAnimation(to, noop);\n\n      var anchorAnimations = [];\n      forEach(anchors, function(anchor) {\n        var outElement = anchor['out'];\n        var inElement = anchor['in'];\n        var animator = prepareAnchoredAnimation(classes, outElement, inElement);\n        if (animator) {\n          anchorAnimations.push(animator);\n        }\n      });\n\n      // no point in doing anything when there are no elements to animate\n      if (!fromAnimation && !toAnimation && anchorAnimations.length === 0) return;\n\n      return {\n        start: function() {\n          var animationRunners = [];\n\n          if (fromAnimation) {\n            animationRunners.push(fromAnimation.start());\n          }\n\n          if (toAnimation) {\n            animationRunners.push(toAnimation.start());\n          }\n\n          forEach(anchorAnimations, function(animation) {\n            animationRunners.push(animation.start());\n          });\n\n          var runner = new $$AnimateRunner({\n            end: endFn,\n            cancel: endFn // CSS-driven animations cannot be cancelled, only ended\n          });\n\n          $$AnimateRunner.all(animationRunners, function(status) {\n            runner.complete(status);\n          });\n\n          return runner;\n\n          function endFn() {\n            forEach(animationRunners, function(runner) {\n              runner.end();\n            });\n          }\n        }\n      };\n    }\n\n    function prepareRegularAnimation(animationDetails) {\n      var element = animationDetails.element;\n      var options = animationDetails.options || {};\n\n      if (animationDetails.structural) {\n        options.event = animationDetails.event;\n        options.structural = true;\n        options.applyClassesEarly = true;\n\n        // we special case the leave animation since we want to ensure that\n        // the element is removed as soon as the animation is over. Otherwise\n        // a flicker might appear or the element may not be removed at all\n        if (animationDetails.event === 'leave') {\n          options.onDone = options.domOperation;\n        }\n      }\n\n      // We assign the preparationClasses as the actual animation event since\n      // the internals of $animateCss will just suffix the event token values\n      // with `-active` to trigger the animation.\n      if (options.preparationClasses) {\n        options.event = concatWithSpace(options.event, options.preparationClasses);\n      }\n\n      var animator = $animateCss(element, options);\n\n      // the driver lookup code inside of $$animation attempts to spawn a\n      // driver one by one until a driver returns a.$$willAnimate animator object.\n      // $animateCss will always return an object, however, it will pass in\n      // a flag as a hint as to whether an animation was detected or not\n      return animator.$$willAnimate ? animator : null;\n    }\n  }];\n}];\n\n// TODO(matsko): use caching here to speed things up for detection\n// TODO(matsko): add documentation\n//  by the time...\n\nvar $$AnimateJsProvider = ['$animateProvider', /** @this */ function($animateProvider) {\n  this.$get = ['$injector', '$$AnimateRunner', '$$jqLite',\n       function($injector,   $$AnimateRunner,   $$jqLite) {\n\n    var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\n         // $animateJs(element, 'enter');\n    return function(element, event, classes, options) {\n      var animationClosed = false;\n\n      // the `classes` argument is optional and if it is not used\n      // then the classes will be resolved from the element's className\n      // property as well as options.addClass/options.removeClass.\n      if (arguments.length === 3 && isObject(classes)) {\n        options = classes;\n        classes = null;\n      }\n\n      options = prepareAnimationOptions(options);\n      if (!classes) {\n        classes = element.attr('class') || '';\n        if (options.addClass) {\n          classes += ' ' + options.addClass;\n        }\n        if (options.removeClass) {\n          classes += ' ' + options.removeClass;\n        }\n      }\n\n      var classesToAdd = options.addClass;\n      var classesToRemove = options.removeClass;\n\n      // the lookupAnimations function returns a series of animation objects that are\n      // matched up with one or more of the CSS classes. These animation objects are\n      // defined via the module.animation factory function. If nothing is detected then\n      // we don't return anything which then makes $animation query the next driver.\n      var animations = lookupAnimations(classes);\n      var before, after;\n      if (animations.length) {\n        var afterFn, beforeFn;\n        if (event === 'leave') {\n          beforeFn = 'leave';\n          afterFn = 'afterLeave'; // TODO(matsko): get rid of this\n        } else {\n          beforeFn = 'before' + event.charAt(0).toUpperCase() + event.substr(1);\n          afterFn = event;\n        }\n\n        if (event !== 'enter' && event !== 'move') {\n          before = packageAnimations(element, event, options, animations, beforeFn);\n        }\n        after  = packageAnimations(element, event, options, animations, afterFn);\n      }\n\n      // no matching animations\n      if (!before && !after) return;\n\n      function applyOptions() {\n        options.domOperation();\n        applyAnimationClasses(element, options);\n      }\n\n      function close() {\n        animationClosed = true;\n        applyOptions();\n        applyAnimationStyles(element, options);\n      }\n\n      var runner;\n\n      return {\n        $$willAnimate: true,\n        end: function() {\n          if (runner) {\n            runner.end();\n          } else {\n            close();\n            runner = new $$AnimateRunner();\n            runner.complete(true);\n          }\n          return runner;\n        },\n        start: function() {\n          if (runner) {\n            return runner;\n          }\n\n          runner = new $$AnimateRunner();\n          var closeActiveAnimations;\n          var chain = [];\n\n          if (before) {\n            chain.push(function(fn) {\n              closeActiveAnimations = before(fn);\n            });\n          }\n\n          if (chain.length) {\n            chain.push(function(fn) {\n              applyOptions();\n              fn(true);\n            });\n          } else {\n            applyOptions();\n          }\n\n          if (after) {\n            chain.push(function(fn) {\n              closeActiveAnimations = after(fn);\n            });\n          }\n\n          runner.setHost({\n            end: function() {\n              endAnimations();\n            },\n            cancel: function() {\n              endAnimations(true);\n            }\n          });\n\n          $$AnimateRunner.chain(chain, onComplete);\n          return runner;\n\n          function onComplete(success) {\n            close(success);\n            runner.complete(success);\n          }\n\n          function endAnimations(cancelled) {\n            if (!animationClosed) {\n              (closeActiveAnimations || noop)(cancelled);\n              onComplete(cancelled);\n            }\n          }\n        }\n      };\n\n      function executeAnimationFn(fn, element, event, options, onDone) {\n        var args;\n        switch (event) {\n          case 'animate':\n            args = [element, options.from, options.to, onDone];\n            break;\n\n          case 'setClass':\n            args = [element, classesToAdd, classesToRemove, onDone];\n            break;\n\n          case 'addClass':\n            args = [element, classesToAdd, onDone];\n            break;\n\n          case 'removeClass':\n            args = [element, classesToRemove, onDone];\n            break;\n\n          default:\n            args = [element, onDone];\n            break;\n        }\n\n        args.push(options);\n\n        var value = fn.apply(fn, args);\n        if (value) {\n          if (isFunction(value.start)) {\n            value = value.start();\n          }\n\n          if (value instanceof $$AnimateRunner) {\n            value.done(onDone);\n          } else if (isFunction(value)) {\n            // optional onEnd / onCancel callback\n            return value;\n          }\n        }\n\n        return noop;\n      }\n\n      function groupEventedAnimations(element, event, options, animations, fnName) {\n        var operations = [];\n        forEach(animations, function(ani) {\n          var animation = ani[fnName];\n          if (!animation) return;\n\n          // note that all of these animations will run in parallel\n          operations.push(function() {\n            var runner;\n            var endProgressCb;\n\n            var resolved = false;\n            var onAnimationComplete = function(rejected) {\n              if (!resolved) {\n                resolved = true;\n                (endProgressCb || noop)(rejected);\n                runner.complete(!rejected);\n              }\n            };\n\n            runner = new $$AnimateRunner({\n              end: function() {\n                onAnimationComplete();\n              },\n              cancel: function() {\n                onAnimationComplete(true);\n              }\n            });\n\n            endProgressCb = executeAnimationFn(animation, element, event, options, function(result) {\n              var cancelled = result === false;\n              onAnimationComplete(cancelled);\n            });\n\n            return runner;\n          });\n        });\n\n        return operations;\n      }\n\n      function packageAnimations(element, event, options, animations, fnName) {\n        var operations = groupEventedAnimations(element, event, options, animations, fnName);\n        if (operations.length === 0) {\n          var a, b;\n          if (fnName === 'beforeSetClass') {\n            a = groupEventedAnimations(element, 'removeClass', options, animations, 'beforeRemoveClass');\n            b = groupEventedAnimations(element, 'addClass', options, animations, 'beforeAddClass');\n          } else if (fnName === 'setClass') {\n            a = groupEventedAnimations(element, 'removeClass', options, animations, 'removeClass');\n            b = groupEventedAnimations(element, 'addClass', options, animations, 'addClass');\n          }\n\n          if (a) {\n            operations = operations.concat(a);\n          }\n          if (b) {\n            operations = operations.concat(b);\n          }\n        }\n\n        if (operations.length === 0) return;\n\n        // TODO(matsko): add documentation\n        return function startAnimation(callback) {\n          var runners = [];\n          if (operations.length) {\n            forEach(operations, function(animateFn) {\n              runners.push(animateFn());\n            });\n          }\n\n          if (runners.length) {\n            $$AnimateRunner.all(runners, callback);\n          }  else {\n            callback();\n          }\n\n          return function endFn(reject) {\n            forEach(runners, function(runner) {\n              if (reject) {\n                runner.cancel();\n              } else {\n                runner.end();\n              }\n            });\n          };\n        };\n      }\n    };\n\n    function lookupAnimations(classes) {\n      classes = isArray(classes) ? classes : classes.split(' ');\n      var matches = [], flagMap = {};\n      for (var i = 0; i < classes.length; i++) {\n        var klass = classes[i],\n            animationFactory = $animateProvider.$$registeredAnimations[klass];\n        if (animationFactory && !flagMap[klass]) {\n          matches.push($injector.get(animationFactory));\n          flagMap[klass] = true;\n        }\n      }\n      return matches;\n    }\n  }];\n}];\n\nvar $$AnimateJsDriverProvider = ['$$animationProvider', /** @this */ function($$animationProvider) {\n  $$animationProvider.drivers.push('$$animateJsDriver');\n  this.$get = ['$$animateJs', '$$AnimateRunner', function($$animateJs, $$AnimateRunner) {\n    return function initDriverFn(animationDetails) {\n      if (animationDetails.from && animationDetails.to) {\n        var fromAnimation = prepareAnimation(animationDetails.from);\n        var toAnimation = prepareAnimation(animationDetails.to);\n        if (!fromAnimation && !toAnimation) return;\n\n        return {\n          start: function() {\n            var animationRunners = [];\n\n            if (fromAnimation) {\n              animationRunners.push(fromAnimation.start());\n            }\n\n            if (toAnimation) {\n              animationRunners.push(toAnimation.start());\n            }\n\n            $$AnimateRunner.all(animationRunners, done);\n\n            var runner = new $$AnimateRunner({\n              end: endFnFactory(),\n              cancel: endFnFactory()\n            });\n\n            return runner;\n\n            function endFnFactory() {\n              return function() {\n                forEach(animationRunners, function(runner) {\n                  // at this point we cannot cancel animations for groups just yet. 1.5+\n                  runner.end();\n                });\n              };\n            }\n\n            function done(status) {\n              runner.complete(status);\n            }\n          }\n        };\n      } else {\n        return prepareAnimation(animationDetails);\n      }\n    };\n\n    function prepareAnimation(animationDetails) {\n      // TODO(matsko): make sure to check for grouped animations and delegate down to normal animations\n      var element = animationDetails.element;\n      var event = animationDetails.event;\n      var options = animationDetails.options;\n      var classes = animationDetails.classes;\n      return $$animateJs(element, event, classes, options);\n    }\n  }];\n}];\n\nvar NG_ANIMATE_ATTR_NAME = 'data-ng-animate';\nvar NG_ANIMATE_PIN_DATA = '$ngAnimatePin';\nvar $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animateProvider) {\n  var PRE_DIGEST_STATE = 1;\n  var RUNNING_STATE = 2;\n  var ONE_SPACE = ' ';\n\n  var rules = this.rules = {\n    skip: [],\n    cancel: [],\n    join: []\n  };\n\n  function getEventData(options) {\n    return {\n      addClass: options.addClass,\n      removeClass: options.removeClass,\n      from: options.from,\n      to: options.to\n    };\n  }\n\n  function makeTruthyCssClassMap(classString) {\n    if (!classString) {\n      return null;\n    }\n\n    var keys = classString.split(ONE_SPACE);\n    var map = Object.create(null);\n\n    forEach(keys, function(key) {\n      map[key] = true;\n    });\n    return map;\n  }\n\n  function hasMatchingClasses(newClassString, currentClassString) {\n    if (newClassString && currentClassString) {\n      var currentClassMap = makeTruthyCssClassMap(currentClassString);\n      return newClassString.split(ONE_SPACE).some(function(className) {\n        return currentClassMap[className];\n      });\n    }\n  }\n\n  function isAllowed(ruleType, currentAnimation, previousAnimation) {\n    return rules[ruleType].some(function(fn) {\n      return fn(currentAnimation, previousAnimation);\n    });\n  }\n\n  function hasAnimationClasses(animation, and) {\n    var a = (animation.addClass || '').length > 0;\n    var b = (animation.removeClass || '').length > 0;\n    return and ? a && b : a || b;\n  }\n\n  rules.join.push(function(newAnimation, currentAnimation) {\n    // if the new animation is class-based then we can just tack that on\n    return !newAnimation.structural && hasAnimationClasses(newAnimation);\n  });\n\n  rules.skip.push(function(newAnimation, currentAnimation) {\n    // there is no need to animate anything if no classes are being added and\n    // there is no structural animation that will be triggered\n    return !newAnimation.structural && !hasAnimationClasses(newAnimation);\n  });\n\n  rules.skip.push(function(newAnimation, currentAnimation) {\n    // why should we trigger a new structural animation if the element will\n    // be removed from the DOM anyway?\n    return currentAnimation.event === 'leave' && newAnimation.structural;\n  });\n\n  rules.skip.push(function(newAnimation, currentAnimation) {\n    // if there is an ongoing current animation then don't even bother running the class-based animation\n    return currentAnimation.structural && currentAnimation.state === RUNNING_STATE && !newAnimation.structural;\n  });\n\n  rules.cancel.push(function(newAnimation, currentAnimation) {\n    // there can never be two structural animations running at the same time\n    return currentAnimation.structural && newAnimation.structural;\n  });\n\n  rules.cancel.push(function(newAnimation, currentAnimation) {\n    // if the previous animation is already running, but the new animation will\n    // be triggered, but the new animation is structural\n    return currentAnimation.state === RUNNING_STATE && newAnimation.structural;\n  });\n\n  rules.cancel.push(function(newAnimation, currentAnimation) {\n    // cancel the animation if classes added / removed in both animation cancel each other out,\n    // but only if the current animation isn't structural\n\n    if (currentAnimation.structural) return false;\n\n    var nA = newAnimation.addClass;\n    var nR = newAnimation.removeClass;\n    var cA = currentAnimation.addClass;\n    var cR = currentAnimation.removeClass;\n\n    // early detection to save the global CPU shortage :)\n    if ((isUndefined(nA) && isUndefined(nR)) || (isUndefined(cA) && isUndefined(cR))) {\n      return false;\n    }\n\n    return hasMatchingClasses(nA, cR) || hasMatchingClasses(nR, cA);\n  });\n\n  this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$Map',\n               '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow',\n               '$$isDocumentHidden',\n       function($$rAF,   $rootScope,   $rootElement,   $document,   $$Map,\n                $$animation,   $$AnimateRunner,   $templateRequest,   $$jqLite,   $$forceReflow,\n                $$isDocumentHidden) {\n\n    var activeAnimationsLookup = new $$Map();\n    var disabledElementsLookup = new $$Map();\n    var animationsEnabled = null;\n\n    function removeFromDisabledElementsLookup(evt) {\n      disabledElementsLookup.delete(evt.target);\n    }\n\n    function postDigestTaskFactory() {\n      var postDigestCalled = false;\n      return function(fn) {\n        // we only issue a call to postDigest before\n        // it has first passed. This prevents any callbacks\n        // from not firing once the animation has completed\n        // since it will be out of the digest cycle.\n        if (postDigestCalled) {\n          fn();\n        } else {\n          $rootScope.$$postDigest(function() {\n            postDigestCalled = true;\n            fn();\n          });\n        }\n      };\n    }\n\n    // Wait until all directive and route-related templates are downloaded and\n    // compiled. The $templateRequest.totalPendingRequests variable keeps track of\n    // all of the remote templates being currently downloaded. If there are no\n    // templates currently downloading then the watcher will still fire anyway.\n    var deregisterWatch = $rootScope.$watch(\n      function() { return $templateRequest.totalPendingRequests === 0; },\n      function(isEmpty) {\n        if (!isEmpty) return;\n        deregisterWatch();\n\n        // Now that all templates have been downloaded, $animate will wait until\n        // the post digest queue is empty before enabling animations. By having two\n        // calls to $postDigest calls we can ensure that the flag is enabled at the\n        // very end of the post digest queue. Since all of the animations in $animate\n        // use $postDigest, it's important that the code below executes at the end.\n        // This basically means that the page is fully downloaded and compiled before\n        // any animations are triggered.\n        $rootScope.$$postDigest(function() {\n          $rootScope.$$postDigest(function() {\n            // we check for null directly in the event that the application already called\n            // .enabled() with whatever arguments that it provided it with\n            if (animationsEnabled === null) {\n              animationsEnabled = true;\n            }\n          });\n        });\n      }\n    );\n\n    var callbackRegistry = Object.create(null);\n\n    // remember that the `customFilter`/`classNameFilter` are set during the\n    // provider/config stage therefore we can optimize here and setup helper functions\n    var customFilter = $animateProvider.customFilter();\n    var classNameFilter = $animateProvider.classNameFilter();\n    var returnTrue = function() { return true; };\n\n    var isAnimatableByFilter = customFilter || returnTrue;\n    var isAnimatableClassName = !classNameFilter ? returnTrue : function(node, options) {\n      var className = [node.getAttribute('class'), options.addClass, options.removeClass].join(' ');\n      return classNameFilter.test(className);\n    };\n\n    var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\n\n    function normalizeAnimationDetails(element, animation) {\n      return mergeAnimationDetails(element, animation, {});\n    }\n\n    // IE9-11 has no method \"contains\" in SVG element and in Node.prototype. Bug #10259.\n    var contains = window.Node.prototype.contains || /** @this */ function(arg) {\n      // eslint-disable-next-line no-bitwise\n      return this === arg || !!(this.compareDocumentPosition(arg) & 16);\n    };\n\n    function findCallbacks(targetParentNode, targetNode, event) {\n      var matches = [];\n      var entries = callbackRegistry[event];\n      if (entries) {\n        forEach(entries, function(entry) {\n          if (contains.call(entry.node, targetNode)) {\n            matches.push(entry.callback);\n          } else if (event === 'leave' && contains.call(entry.node, targetParentNode)) {\n            matches.push(entry.callback);\n          }\n        });\n      }\n\n      return matches;\n    }\n\n    function filterFromRegistry(list, matchContainer, matchCallback) {\n      var containerNode = extractElementNode(matchContainer);\n      return list.filter(function(entry) {\n        var isMatch = entry.node === containerNode &&\n                        (!matchCallback || entry.callback === matchCallback);\n        return !isMatch;\n      });\n    }\n\n    function cleanupEventListeners(phase, node) {\n      if (phase === 'close' && !node.parentNode) {\n        // If the element is not attached to a parentNode, it has been removed by\n        // the domOperation, and we can safely remove the event callbacks\n        $animate.off(node);\n      }\n    }\n\n    var $animate = {\n      on: function(event, container, callback) {\n        var node = extractElementNode(container);\n        callbackRegistry[event] = callbackRegistry[event] || [];\n        callbackRegistry[event].push({\n          node: node,\n          callback: callback\n        });\n\n        // Remove the callback when the element is removed from the DOM\n        jqLite(container).on('$destroy', function() {\n          var animationDetails = activeAnimationsLookup.get(node);\n\n          if (!animationDetails) {\n            // If there's an animation ongoing, the callback calling code will remove\n            // the event listeners. If we'd remove here, the callbacks would be removed\n            // before the animation ends\n            $animate.off(event, container, callback);\n          }\n        });\n      },\n\n      off: function(event, container, callback) {\n        if (arguments.length === 1 && !isString(arguments[0])) {\n          container = arguments[0];\n          for (var eventType in callbackRegistry) {\n            callbackRegistry[eventType] = filterFromRegistry(callbackRegistry[eventType], container);\n          }\n\n          return;\n        }\n\n        var entries = callbackRegistry[event];\n        if (!entries) return;\n\n        callbackRegistry[event] = arguments.length === 1\n            ? null\n            : filterFromRegistry(entries, container, callback);\n      },\n\n      pin: function(element, parentElement) {\n        assertArg(isElement(element), 'element', 'not an element');\n        assertArg(isElement(parentElement), 'parentElement', 'not an element');\n        element.data(NG_ANIMATE_PIN_DATA, parentElement);\n      },\n\n      push: function(element, event, options, domOperation) {\n        options = options || {};\n        options.domOperation = domOperation;\n        return queueAnimation(element, event, options);\n      },\n\n      // this method has four signatures:\n      //  () - global getter\n      //  (bool) - global setter\n      //  (element) - element getter\n      //  (element, bool) - element setter<F37>\n      enabled: function(element, bool) {\n        var argCount = arguments.length;\n\n        if (argCount === 0) {\n          // () - Global getter\n          bool = !!animationsEnabled;\n        } else {\n          var hasElement = isElement(element);\n\n          if (!hasElement) {\n            // (bool) - Global setter\n            bool = animationsEnabled = !!element;\n          } else {\n            var node = getDomNode(element);\n\n            if (argCount === 1) {\n              // (element) - Element getter\n              bool = !disabledElementsLookup.get(node);\n            } else {\n              // (element, bool) - Element setter\n              if (!disabledElementsLookup.has(node)) {\n                // The element is added to the map for the first time.\n                // Create a listener to remove it on `$destroy` (to avoid memory leak).\n                jqLite(element).on('$destroy', removeFromDisabledElementsLookup);\n              }\n              disabledElementsLookup.set(node, !bool);\n            }\n          }\n        }\n\n        return bool;\n      }\n    };\n\n    return $animate;\n\n    function queueAnimation(originalElement, event, initialOptions) {\n      // we always make a copy of the options since\n      // there should never be any side effects on\n      // the input data when running `$animateCss`.\n      var options = copy(initialOptions);\n\n      var element = stripCommentsFromElement(originalElement);\n      var node = getDomNode(element);\n      var parentNode = node && node.parentNode;\n\n      options = prepareAnimationOptions(options);\n\n      // we create a fake runner with a working promise.\n      // These methods will become available after the digest has passed\n      var runner = new $$AnimateRunner();\n\n      // this is used to trigger callbacks in postDigest mode\n      var runInNextPostDigestOrNow = postDigestTaskFactory();\n\n      if (isArray(options.addClass)) {\n        options.addClass = options.addClass.join(' ');\n      }\n\n      if (options.addClass && !isString(options.addClass)) {\n        options.addClass = null;\n      }\n\n      if (isArray(options.removeClass)) {\n        options.removeClass = options.removeClass.join(' ');\n      }\n\n      if (options.removeClass && !isString(options.removeClass)) {\n        options.removeClass = null;\n      }\n\n      if (options.from && !isObject(options.from)) {\n        options.from = null;\n      }\n\n      if (options.to && !isObject(options.to)) {\n        options.to = null;\n      }\n\n      // If animations are hard-disabled for the whole application there is no need to continue.\n      // There are also situations where a directive issues an animation for a jqLite wrapper that\n      // contains only comment nodes. In this case, there is no way we can perform an animation.\n      if (!animationsEnabled ||\n          !node ||\n          !isAnimatableByFilter(node, event, initialOptions) ||\n          !isAnimatableClassName(node, options)) {\n        close();\n        return runner;\n      }\n\n      var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;\n\n      var documentHidden = $$isDocumentHidden();\n\n      // This is a hard disable of all animations the element itself, therefore  there is no need to\n      // continue further past this point if not enabled\n      // Animations are also disabled if the document is currently hidden (page is not visible\n      // to the user), because browsers slow down or do not flush calls to requestAnimationFrame\n      var skipAnimations = documentHidden || disabledElementsLookup.get(node);\n      var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};\n      var hasExistingAnimation = !!existingAnimation.state;\n\n      // there is no point in traversing the same collection of parent ancestors if a followup\n      // animation will be run on the same element that already did all that checking work\n      if (!skipAnimations && (!hasExistingAnimation || existingAnimation.state !== PRE_DIGEST_STATE)) {\n        skipAnimations = !areAnimationsAllowed(node, parentNode, event);\n      }\n\n      if (skipAnimations) {\n        // Callbacks should fire even if the document is hidden (regression fix for issue #14120)\n        if (documentHidden) notifyProgress(runner, event, 'start', getEventData(options));\n        close();\n        if (documentHidden) notifyProgress(runner, event, 'close', getEventData(options));\n        return runner;\n      }\n\n      if (isStructural) {\n        closeChildAnimations(node);\n      }\n\n      var newAnimation = {\n        structural: isStructural,\n        element: element,\n        event: event,\n        addClass: options.addClass,\n        removeClass: options.removeClass,\n        close: close,\n        options: options,\n        runner: runner\n      };\n\n      if (hasExistingAnimation) {\n        var skipAnimationFlag = isAllowed('skip', newAnimation, existingAnimation);\n        if (skipAnimationFlag) {\n          if (existingAnimation.state === RUNNING_STATE) {\n            close();\n            return runner;\n          } else {\n            mergeAnimationDetails(element, existingAnimation, newAnimation);\n            return existingAnimation.runner;\n          }\n        }\n        var cancelAnimationFlag = isAllowed('cancel', newAnimation, existingAnimation);\n        if (cancelAnimationFlag) {\n          if (existingAnimation.state === RUNNING_STATE) {\n            // this will end the animation right away and it is safe\n            // to do so since the animation is already running and the\n            // runner callback code will run in async\n            existingAnimation.runner.end();\n          } else if (existingAnimation.structural) {\n            // this means that the animation is queued into a digest, but\n            // hasn't started yet. Therefore it is safe to run the close\n            // method which will call the runner methods in async.\n            existingAnimation.close();\n          } else {\n            // this will merge the new animation options into existing animation options\n            mergeAnimationDetails(element, existingAnimation, newAnimation);\n\n            return existingAnimation.runner;\n          }\n        } else {\n          // a joined animation means that this animation will take over the existing one\n          // so an example would involve a leave animation taking over an enter. Then when\n          // the postDigest kicks in the enter will be ignored.\n          var joinAnimationFlag = isAllowed('join', newAnimation, existingAnimation);\n          if (joinAnimationFlag) {\n            if (existingAnimation.state === RUNNING_STATE) {\n              normalizeAnimationDetails(element, newAnimation);\n            } else {\n              applyGeneratedPreparationClasses($$jqLite, element, isStructural ? event : null, options);\n\n              event = newAnimation.event = existingAnimation.event;\n              options = mergeAnimationDetails(element, existingAnimation, newAnimation);\n\n              //we return the same runner since only the option values of this animation will\n              //be fed into the `existingAnimation`.\n              return existingAnimation.runner;\n            }\n          }\n        }\n      } else {\n        // normalization in this case means that it removes redundant CSS classes that\n        // already exist (addClass) or do not exist (removeClass) on the element\n        normalizeAnimationDetails(element, newAnimation);\n      }\n\n      // when the options are merged and cleaned up we may end up not having to do\n      // an animation at all, therefore we should check this before issuing a post\n      // digest callback. Structural animations will always run no matter what.\n      var isValidAnimation = newAnimation.structural;\n      if (!isValidAnimation) {\n        // animate (from/to) can be quickly checked first, otherwise we check if any classes are present\n        isValidAnimation = (newAnimation.event === 'animate' && Object.keys(newAnimation.options.to || {}).length > 0)\n                            || hasAnimationClasses(newAnimation);\n      }\n\n      if (!isValidAnimation) {\n        close();\n        clearElementAnimationState(node);\n        return runner;\n      }\n\n      // the counter keeps track of cancelled animations\n      var counter = (existingAnimation.counter || 0) + 1;\n      newAnimation.counter = counter;\n\n      markElementAnimationState(node, PRE_DIGEST_STATE, newAnimation);\n\n      $rootScope.$$postDigest(function() {\n        // It is possible that the DOM nodes inside `originalElement` have been replaced. This can\n        // happen if the animated element is a transcluded clone and also has a `templateUrl`\n        // directive on it. Therefore, we must recreate `element` in order to interact with the\n        // actual DOM nodes.\n        // Note: We still need to use the old `node` for certain things, such as looking up in\n        //       HashMaps where it was used as the key.\n\n        element = stripCommentsFromElement(originalElement);\n\n        var animationDetails = activeAnimationsLookup.get(node);\n        var animationCancelled = !animationDetails;\n        animationDetails = animationDetails || {};\n\n        // if addClass/removeClass is called before something like enter then the\n        // registered parent element may not be present. The code below will ensure\n        // that a final value for parent element is obtained\n        var parentElement = element.parent() || [];\n\n        // animate/structural/class-based animations all have requirements. Otherwise there\n        // is no point in performing an animation. The parent node must also be set.\n        var isValidAnimation = parentElement.length > 0\n                                && (animationDetails.event === 'animate'\n                                    || animationDetails.structural\n                                    || hasAnimationClasses(animationDetails));\n\n        // this means that the previous animation was cancelled\n        // even if the follow-up animation is the same event\n        if (animationCancelled || animationDetails.counter !== counter || !isValidAnimation) {\n          // if another animation did not take over then we need\n          // to make sure that the domOperation and options are\n          // handled accordingly\n          if (animationCancelled) {\n            applyAnimationClasses(element, options);\n            applyAnimationStyles(element, options);\n          }\n\n          // if the event changed from something like enter to leave then we do\n          // it, otherwise if it's the same then the end result will be the same too\n          if (animationCancelled || (isStructural && animationDetails.event !== event)) {\n            options.domOperation();\n            runner.end();\n          }\n\n          // in the event that the element animation was not cancelled or a follow-up animation\n          // isn't allowed to animate from here then we need to clear the state of the element\n          // so that any future animations won't read the expired animation data.\n          if (!isValidAnimation) {\n            clearElementAnimationState(node);\n          }\n\n          return;\n        }\n\n        // this combined multiple class to addClass / removeClass into a setClass event\n        // so long as a structural event did not take over the animation\n        event = !animationDetails.structural && hasAnimationClasses(animationDetails, true)\n            ? 'setClass'\n            : animationDetails.event;\n\n        markElementAnimationState(node, RUNNING_STATE);\n        var realRunner = $$animation(element, event, animationDetails.options);\n\n        // this will update the runner's flow-control events based on\n        // the `realRunner` object.\n        runner.setHost(realRunner);\n        notifyProgress(runner, event, 'start', getEventData(options));\n\n        realRunner.done(function(status) {\n          close(!status);\n          var animationDetails = activeAnimationsLookup.get(node);\n          if (animationDetails && animationDetails.counter === counter) {\n            clearElementAnimationState(node);\n          }\n          notifyProgress(runner, event, 'close', getEventData(options));\n        });\n      });\n\n      return runner;\n\n      function notifyProgress(runner, event, phase, data) {\n        runInNextPostDigestOrNow(function() {\n          var callbacks = findCallbacks(parentNode, node, event);\n          if (callbacks.length) {\n            // do not optimize this call here to RAF because\n            // we don't know how heavy the callback code here will\n            // be and if this code is buffered then this can\n            // lead to a performance regression.\n            $$rAF(function() {\n              forEach(callbacks, function(callback) {\n                callback(element, phase, data);\n              });\n              cleanupEventListeners(phase, node);\n            });\n          } else {\n            cleanupEventListeners(phase, node);\n          }\n        });\n        runner.progress(event, phase, data);\n      }\n\n      function close(reject) {\n        clearGeneratedClasses(element, options);\n        applyAnimationClasses(element, options);\n        applyAnimationStyles(element, options);\n        options.domOperation();\n        runner.complete(!reject);\n      }\n    }\n\n    function closeChildAnimations(node) {\n      var children = node.querySelectorAll('[' + NG_ANIMATE_ATTR_NAME + ']');\n      forEach(children, function(child) {\n        var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME), 10);\n        var animationDetails = activeAnimationsLookup.get(child);\n        if (animationDetails) {\n          switch (state) {\n            case RUNNING_STATE:\n              animationDetails.runner.end();\n              /* falls through */\n            case PRE_DIGEST_STATE:\n              activeAnimationsLookup.delete(child);\n              break;\n          }\n        }\n      });\n    }\n\n    function clearElementAnimationState(node) {\n      node.removeAttribute(NG_ANIMATE_ATTR_NAME);\n      activeAnimationsLookup.delete(node);\n    }\n\n    /**\n     * This fn returns false if any of the following is true:\n     * a) animations on any parent element are disabled, and animations on the element aren't explicitly allowed\n     * b) a parent element has an ongoing structural animation, and animateChildren is false\n     * c) the element is not a child of the body\n     * d) the element is not a child of the $rootElement\n     */\n    function areAnimationsAllowed(node, parentNode, event) {\n      var bodyNode = $document[0].body;\n      var rootNode = getDomNode($rootElement);\n\n      var bodyNodeDetected = (node === bodyNode) || node.nodeName === 'HTML';\n      var rootNodeDetected = (node === rootNode);\n      var parentAnimationDetected = false;\n      var elementDisabled = disabledElementsLookup.get(node);\n      var animateChildren;\n\n      var parentHost = jqLite.data(node, NG_ANIMATE_PIN_DATA);\n      if (parentHost) {\n        parentNode = getDomNode(parentHost);\n      }\n\n      while (parentNode) {\n        if (!rootNodeDetected) {\n          // AngularJS doesn't want to attempt to animate elements outside of the application\n          // therefore we need to ensure that the rootElement is an ancestor of the current element\n          rootNodeDetected = (parentNode === rootNode);\n        }\n\n        if (parentNode.nodeType !== ELEMENT_NODE) {\n          // no point in inspecting the #document element\n          break;\n        }\n\n        var details = activeAnimationsLookup.get(parentNode) || {};\n        // either an enter, leave or move animation will commence\n        // therefore we can't allow any animations to take place\n        // but if a parent animation is class-based then that's ok\n        if (!parentAnimationDetected) {\n          var parentNodeDisabled = disabledElementsLookup.get(parentNode);\n\n          if (parentNodeDisabled === true && elementDisabled !== false) {\n            // disable animations if the user hasn't explicitly enabled animations on the\n            // current element\n            elementDisabled = true;\n            // element is disabled via parent element, no need to check anything else\n            break;\n          } else if (parentNodeDisabled === false) {\n            elementDisabled = false;\n          }\n          parentAnimationDetected = details.structural;\n        }\n\n        if (isUndefined(animateChildren) || animateChildren === true) {\n          var value = jqLite.data(parentNode, NG_ANIMATE_CHILDREN_DATA);\n          if (isDefined(value)) {\n            animateChildren = value;\n          }\n        }\n\n        // there is no need to continue traversing at this point\n        if (parentAnimationDetected && animateChildren === false) break;\n\n        if (!bodyNodeDetected) {\n          // we also need to ensure that the element is or will be a part of the body element\n          // otherwise it is pointless to even issue an animation to be rendered\n          bodyNodeDetected = (parentNode === bodyNode);\n        }\n\n        if (bodyNodeDetected && rootNodeDetected) {\n          // If both body and root have been found, any other checks are pointless,\n          // as no animation data should live outside the application\n          break;\n        }\n\n        if (!rootNodeDetected) {\n          // If `rootNode` is not detected, check if `parentNode` is pinned to another element\n          parentHost = jqLite.data(parentNode, NG_ANIMATE_PIN_DATA);\n          if (parentHost) {\n            // The pin target element becomes the next parent element\n            parentNode = getDomNode(parentHost);\n            continue;\n          }\n        }\n\n        parentNode = parentNode.parentNode;\n      }\n\n      var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true;\n      return allowAnimation && rootNodeDetected && bodyNodeDetected;\n    }\n\n    function markElementAnimationState(node, state, details) {\n      details = details || {};\n      details.state = state;\n\n      node.setAttribute(NG_ANIMATE_ATTR_NAME, state);\n\n      var oldValue = activeAnimationsLookup.get(node);\n      var newValue = oldValue\n          ? extend(oldValue, details)\n          : details;\n      activeAnimationsLookup.set(node, newValue);\n    }\n  }];\n}];\n\n/** @this */\nvar $$AnimateCacheProvider = function() {\n\n  var KEY = '$$ngAnimateParentKey';\n  var parentCounter = 0;\n  var cache = Object.create(null);\n\n  this.$get = [function() {\n    return {\n      cacheKey: function(node, method, addClass, removeClass) {\n        var parentNode = node.parentNode;\n        var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);\n        var parts = [parentID, method, node.getAttribute('class')];\n        if (addClass) {\n          parts.push(addClass);\n        }\n        if (removeClass) {\n          parts.push(removeClass);\n        }\n        return parts.join(' ');\n      },\n\n      containsCachedAnimationWithoutDuration: function(key) {\n        var entry = cache[key];\n\n        // nothing cached, so go ahead and animate\n        // otherwise it should be a valid animation\n        return (entry && !entry.isValid) || false;\n      },\n\n      flush: function() {\n        cache = Object.create(null);\n      },\n\n      count: function(key) {\n        var entry = cache[key];\n        return entry ? entry.total : 0;\n      },\n\n      get: function(key) {\n        var entry = cache[key];\n        return entry && entry.value;\n      },\n\n      put: function(key, value, isValid) {\n        if (!cache[key]) {\n          cache[key] = { total: 1, value: value, isValid: isValid };\n        } else {\n          cache[key].total++;\n          cache[key].value = value;\n        }\n      }\n    };\n  }];\n};\n\n/* exported $$AnimationProvider */\n\nvar $$AnimationProvider = ['$animateProvider', /** @this */ function($animateProvider) {\n  var NG_ANIMATE_REF_ATTR = 'ng-animate-ref';\n\n  var drivers = this.drivers = [];\n\n  var RUNNER_STORAGE_KEY = '$$animationRunner';\n  var PREPARE_CLASSES_KEY = '$$animatePrepareClasses';\n\n  function setRunner(element, runner) {\n    element.data(RUNNER_STORAGE_KEY, runner);\n  }\n\n  function removeRunner(element) {\n    element.removeData(RUNNER_STORAGE_KEY);\n  }\n\n  function getRunner(element) {\n    return element.data(RUNNER_STORAGE_KEY);\n  }\n\n  this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$Map', '$$rAFScheduler', '$$animateCache',\n       function($$jqLite,   $rootScope,   $injector,   $$AnimateRunner,   $$Map,   $$rAFScheduler, $$animateCache) {\n\n    var animationQueue = [];\n    var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\n\n    function sortAnimations(animations) {\n      var tree = { children: [] };\n      var i, lookup = new $$Map();\n\n      // this is done first beforehand so that the map\n      // is filled with a list of the elements that will be animated\n      for (i = 0; i < animations.length; i++) {\n        var animation = animations[i];\n        lookup.set(animation.domNode, animations[i] = {\n          domNode: animation.domNode,\n          element: animation.element,\n          fn: animation.fn,\n          children: []\n        });\n      }\n\n      for (i = 0; i < animations.length; i++) {\n        processNode(animations[i]);\n      }\n\n      return flatten(tree);\n\n      function processNode(entry) {\n        if (entry.processed) return entry;\n        entry.processed = true;\n\n        var elementNode = entry.domNode;\n        var parentNode = elementNode.parentNode;\n        lookup.set(elementNode, entry);\n\n        var parentEntry;\n        while (parentNode) {\n          parentEntry = lookup.get(parentNode);\n          if (parentEntry) {\n            if (!parentEntry.processed) {\n              parentEntry = processNode(parentEntry);\n            }\n            break;\n          }\n          parentNode = parentNode.parentNode;\n        }\n\n        (parentEntry || tree).children.push(entry);\n        return entry;\n      }\n\n      function flatten(tree) {\n        var result = [];\n        var queue = [];\n        var i;\n\n        for (i = 0; i < tree.children.length; i++) {\n          queue.push(tree.children[i]);\n        }\n\n        var remainingLevelEntries = queue.length;\n        var nextLevelEntries = 0;\n        var row = [];\n\n        for (i = 0; i < queue.length; i++) {\n          var entry = queue[i];\n          if (remainingLevelEntries <= 0) {\n            remainingLevelEntries = nextLevelEntries;\n            nextLevelEntries = 0;\n            result.push(row);\n            row = [];\n          }\n          row.push(entry);\n          entry.children.forEach(function(childEntry) {\n            nextLevelEntries++;\n            queue.push(childEntry);\n          });\n          remainingLevelEntries--;\n        }\n\n        if (row.length) {\n          result.push(row);\n        }\n\n        return result;\n      }\n    }\n\n    // TODO(matsko): document the signature in a better way\n    return function(element, event, options) {\n      options = prepareAnimationOptions(options);\n      var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;\n\n      // there is no animation at the current moment, however\n      // these runner methods will get later updated with the\n      // methods leading into the driver's end/cancel methods\n      // for now they just stop the animation from starting\n      var runner = new $$AnimateRunner({\n        end: function() { close(); },\n        cancel: function() { close(true); }\n      });\n\n      if (!drivers.length) {\n        close();\n        return runner;\n      }\n\n      var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass));\n      var tempClasses = options.tempClasses;\n      if (tempClasses) {\n        classes += ' ' + tempClasses;\n        options.tempClasses = null;\n      }\n\n      if (isStructural) {\n        element.data(PREPARE_CLASSES_KEY, 'ng-' + event + PREPARE_CLASS_SUFFIX);\n      }\n\n      setRunner(element, runner);\n\n      animationQueue.push({\n        // this data is used by the postDigest code and passed into\n        // the driver step function\n        element: element,\n        classes: classes,\n        event: event,\n        structural: isStructural,\n        options: options,\n        beforeStart: beforeStart,\n        close: close\n      });\n\n      element.on('$destroy', handleDestroyedElement);\n\n      // we only want there to be one function called within the post digest\n      // block. This way we can group animations for all the animations that\n      // were apart of the same postDigest flush call.\n      if (animationQueue.length > 1) return runner;\n\n      $rootScope.$$postDigest(function() {\n        var animations = [];\n        forEach(animationQueue, function(entry) {\n          // the element was destroyed early on which removed the runner\n          // form its storage. This means we can't animate this element\n          // at all and it already has been closed due to destruction.\n          if (getRunner(entry.element)) {\n            animations.push(entry);\n          } else {\n            entry.close();\n          }\n        });\n\n        // now any future animations will be in another postDigest\n        animationQueue.length = 0;\n\n        var groupedAnimations = groupAnimations(animations);\n        var toBeSortedAnimations = [];\n\n        forEach(groupedAnimations, function(animationEntry) {\n          var element = animationEntry.from ? animationEntry.from.element : animationEntry.element;\n          var extraClasses = options.addClass;\n\n          extraClasses = (extraClasses ? (extraClasses + ' ') : '') + NG_ANIMATE_CLASSNAME;\n          var cacheKey = $$animateCache.cacheKey(element[0], animationEntry.event, extraClasses, options.removeClass);\n\n          toBeSortedAnimations.push({\n            element: element,\n            domNode: getDomNode(element),\n            fn: function triggerAnimationStart() {\n              var startAnimationFn, closeFn = animationEntry.close;\n\n              // in the event that we've cached the animation status for this element\n              // and it's in fact an invalid animation (something that has duration = 0)\n              // then we should skip all the heavy work from here on\n              if ($$animateCache.containsCachedAnimationWithoutDuration(cacheKey)) {\n                closeFn();\n                return;\n              }\n\n              // it's important that we apply the `ng-animate` CSS class and the\n              // temporary classes before we do any driver invoking since these\n              // CSS classes may be required for proper CSS detection.\n              animationEntry.beforeStart();\n\n              // in the event that the element was removed before the digest runs or\n              // during the RAF sequencing then we should not trigger the animation.\n              var targetElement = animationEntry.anchors\n                  ? (animationEntry.from.element || animationEntry.to.element)\n                  : animationEntry.element;\n\n              if (getRunner(targetElement)) {\n                var operation = invokeFirstDriver(animationEntry);\n                if (operation) {\n                  startAnimationFn = operation.start;\n                }\n              }\n\n              if (!startAnimationFn) {\n                closeFn();\n              } else {\n                var animationRunner = startAnimationFn();\n                animationRunner.done(function(status) {\n                  closeFn(!status);\n                });\n                updateAnimationRunners(animationEntry, animationRunner);\n              }\n            }\n          });\n        });\n\n        // we need to sort each of the animations in order of parent to child\n        // relationships. This ensures that the child classes are applied at the\n        // right time.\n        var finalAnimations = sortAnimations(toBeSortedAnimations);\n        for (var i = 0; i < finalAnimations.length; i++) {\n          var innerArray = finalAnimations[i];\n          for (var j = 0; j < innerArray.length; j++) {\n            var entry = innerArray[j];\n            var element = entry.element;\n\n            // the RAFScheduler code only uses functions\n            finalAnimations[i][j] = entry.fn;\n\n            // the first row of elements shouldn't have a prepare-class added to them\n            // since the elements are at the top of the animation hierarchy and they\n            // will be applied without a RAF having to pass...\n            if (i === 0) {\n              element.removeData(PREPARE_CLASSES_KEY);\n              continue;\n            }\n\n            var prepareClassName = element.data(PREPARE_CLASSES_KEY);\n            if (prepareClassName) {\n              $$jqLite.addClass(element, prepareClassName);\n            }\n          }\n        }\n\n        $$rAFScheduler(finalAnimations);\n      });\n\n      return runner;\n\n      // TODO(matsko): change to reference nodes\n      function getAnchorNodes(node) {\n        var SELECTOR = '[' + NG_ANIMATE_REF_ATTR + ']';\n        var items = node.hasAttribute(NG_ANIMATE_REF_ATTR)\n              ? [node]\n              : node.querySelectorAll(SELECTOR);\n        var anchors = [];\n        forEach(items, function(node) {\n          var attr = node.getAttribute(NG_ANIMATE_REF_ATTR);\n          if (attr && attr.length) {\n            anchors.push(node);\n          }\n        });\n        return anchors;\n      }\n\n      function groupAnimations(animations) {\n        var preparedAnimations = [];\n        var refLookup = {};\n        forEach(animations, function(animation, index) {\n          var element = animation.element;\n          var node = getDomNode(element);\n          var event = animation.event;\n          var enterOrMove = ['enter', 'move'].indexOf(event) >= 0;\n          var anchorNodes = animation.structural ? getAnchorNodes(node) : [];\n\n          if (anchorNodes.length) {\n            var direction = enterOrMove ? 'to' : 'from';\n\n            forEach(anchorNodes, function(anchor) {\n              var key = anchor.getAttribute(NG_ANIMATE_REF_ATTR);\n              refLookup[key] = refLookup[key] || {};\n              refLookup[key][direction] = {\n                animationID: index,\n                element: jqLite(anchor)\n              };\n            });\n          } else {\n            preparedAnimations.push(animation);\n          }\n        });\n\n        var usedIndicesLookup = {};\n        var anchorGroups = {};\n        forEach(refLookup, function(operations, key) {\n          var from = operations.from;\n          var to = operations.to;\n\n          if (!from || !to) {\n            // only one of these is set therefore we can't have an\n            // anchor animation since all three pieces are required\n            var index = from ? from.animationID : to.animationID;\n            var indexKey = index.toString();\n            if (!usedIndicesLookup[indexKey]) {\n              usedIndicesLookup[indexKey] = true;\n              preparedAnimations.push(animations[index]);\n            }\n            return;\n          }\n\n          var fromAnimation = animations[from.animationID];\n          var toAnimation = animations[to.animationID];\n          var lookupKey = from.animationID.toString();\n          if (!anchorGroups[lookupKey]) {\n            var group = anchorGroups[lookupKey] = {\n              structural: true,\n              beforeStart: function() {\n                fromAnimation.beforeStart();\n                toAnimation.beforeStart();\n              },\n              close: function() {\n                fromAnimation.close();\n                toAnimation.close();\n              },\n              classes: cssClassesIntersection(fromAnimation.classes, toAnimation.classes),\n              from: fromAnimation,\n              to: toAnimation,\n              anchors: [] // TODO(matsko): change to reference nodes\n            };\n\n            // the anchor animations require that the from and to elements both have at least\n            // one shared CSS class which effectively marries the two elements together to use\n            // the same animation driver and to properly sequence the anchor animation.\n            if (group.classes.length) {\n              preparedAnimations.push(group);\n            } else {\n              preparedAnimations.push(fromAnimation);\n              preparedAnimations.push(toAnimation);\n            }\n          }\n\n          anchorGroups[lookupKey].anchors.push({\n            'out': from.element, 'in': to.element\n          });\n        });\n\n        return preparedAnimations;\n      }\n\n      function cssClassesIntersection(a,b) {\n        a = a.split(' ');\n        b = b.split(' ');\n        var matches = [];\n\n        for (var i = 0; i < a.length; i++) {\n          var aa = a[i];\n          if (aa.substring(0,3) === 'ng-') continue;\n\n          for (var j = 0; j < b.length; j++) {\n            if (aa === b[j]) {\n              matches.push(aa);\n              break;\n            }\n          }\n        }\n\n        return matches.join(' ');\n      }\n\n      function invokeFirstDriver(animationDetails) {\n        // we loop in reverse order since the more general drivers (like CSS and JS)\n        // may attempt more elements, but custom drivers are more particular\n        for (var i = drivers.length - 1; i >= 0; i--) {\n          var driverName = drivers[i];\n          var factory = $injector.get(driverName);\n          var driver = factory(animationDetails);\n          if (driver) {\n            return driver;\n          }\n        }\n      }\n\n      function beforeStart() {\n        tempClasses = (tempClasses ? (tempClasses + ' ') : '') + NG_ANIMATE_CLASSNAME;\n        $$jqLite.addClass(element, tempClasses);\n\n        var prepareClassName = element.data(PREPARE_CLASSES_KEY);\n        if (prepareClassName) {\n          $$jqLite.removeClass(element, prepareClassName);\n          prepareClassName = null;\n        }\n      }\n\n      function updateAnimationRunners(animation, newRunner) {\n        if (animation.from && animation.to) {\n          update(animation.from.element);\n          update(animation.to.element);\n        } else {\n          update(animation.element);\n        }\n\n        function update(element) {\n          var runner = getRunner(element);\n          if (runner) runner.setHost(newRunner);\n        }\n      }\n\n      function handleDestroyedElement() {\n        var runner = getRunner(element);\n        if (runner && (event !== 'leave' || !options.$$domOperationFired)) {\n          runner.end();\n        }\n      }\n\n      function close(rejected) {\n        element.off('$destroy', handleDestroyedElement);\n        removeRunner(element);\n\n        applyAnimationClasses(element, options);\n        applyAnimationStyles(element, options);\n        options.domOperation();\n\n        if (tempClasses) {\n          $$jqLite.removeClass(element, tempClasses);\n        }\n\n        runner.complete(!rejected);\n      }\n    };\n  }];\n}];\n\n/**\n * @ngdoc directive\n * @name ngAnimateSwap\n * @restrict A\n * @scope\n *\n * @description\n *\n * ngAnimateSwap is a animation-oriented directive that allows for the container to\n * be removed and entered in whenever the associated expression changes. A\n * common usecase for this directive is a rotating banner or slider component which\n * contains one image being present at a time. When the active image changes\n * then the old image will perform a `leave` animation and the new element\n * will be inserted via an `enter` animation.\n *\n * @animations\n * | Animation                        | Occurs                               |\n * |----------------------------------|--------------------------------------|\n * | {@link ng.$animate#enter enter}  | when the new element is inserted to the DOM  |\n * | {@link ng.$animate#leave leave}  | when the old element is removed from the DOM |\n *\n * @example\n * <example name=\"ngAnimateSwap-directive\" module=\"ngAnimateSwapExample\"\n *          deps=\"angular-animate.js\"\n *          animations=\"true\" fixBase=\"true\">\n *   <file name=\"index.html\">\n *     <div class=\"container\" ng-controller=\"AppCtrl\">\n *       <div ng-animate-swap=\"number\" class=\"cell swap-animation\" ng-class=\"colorClass(number)\">\n *         {{ number }}\n *       </div>\n *     </div>\n *   </file>\n *   <file name=\"script.js\">\n *     angular.module('ngAnimateSwapExample', ['ngAnimate'])\n *       .controller('AppCtrl', ['$scope', '$interval', function($scope, $interval) {\n *         $scope.number = 0;\n *         $interval(function() {\n *           $scope.number++;\n *         }, 1000);\n *\n *         var colors = ['red','blue','green','yellow','orange'];\n *         $scope.colorClass = function(number) {\n *           return colors[number % colors.length];\n *         };\n *       }]);\n *   </file>\n *  <file name=\"animations.css\">\n *  .container {\n *    height:250px;\n *    width:250px;\n *    position:relative;\n *    overflow:hidden;\n *    border:2px solid black;\n *  }\n *  .container .cell {\n *    font-size:150px;\n *    text-align:center;\n *    line-height:250px;\n *    position:absolute;\n *    top:0;\n *    left:0;\n *    right:0;\n *    border-bottom:2px solid black;\n *  }\n *  .swap-animation.ng-enter, .swap-animation.ng-leave {\n *    transition:0.5s linear all;\n *  }\n *  .swap-animation.ng-enter {\n *    top:-250px;\n *  }\n *  .swap-animation.ng-enter-active {\n *    top:0px;\n *  }\n *  .swap-animation.ng-leave {\n *    top:0px;\n *  }\n *  .swap-animation.ng-leave-active {\n *    top:250px;\n *  }\n *  .red { background:red; }\n *  .green { background:green; }\n *  .blue { background:blue; }\n *  .yellow { background:yellow; }\n *  .orange { background:orange; }\n *  </file>\n * </example>\n */\nvar ngAnimateSwapDirective = ['$animate', function($animate) {\n  return {\n    restrict: 'A',\n    transclude: 'element',\n    terminal: true,\n    priority: 550, // We use 550 here to ensure that the directive is caught before others,\n                   // but after `ngIf` (at priority 600).\n    link: function(scope, $element, attrs, ctrl, $transclude) {\n      var previousElement, previousScope;\n      scope.$watchCollection(attrs.ngAnimateSwap || attrs['for'], function(value) {\n        if (previousElement) {\n          $animate.leave(previousElement);\n        }\n        if (previousScope) {\n          previousScope.$destroy();\n          previousScope = null;\n        }\n        if (value || value === 0) {\n          $transclude(function(clone, childScope) {\n            previousElement = clone;\n            previousScope = childScope;\n            $animate.enter(clone, null, $element);\n          });\n        }\n      });\n    }\n  };\n}];\n\n/**\n * @ngdoc module\n * @name ngAnimate\n * @description\n *\n * The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via\n * callback hooks. Animations are not enabled by default, however, by including `ngAnimate` the animation hooks are enabled for an AngularJS app.\n *\n * ## Usage\n * Simply put, there are two ways to make use of animations when ngAnimate is used: by using **CSS** and **JavaScript**. The former works purely based\n * using CSS (by using matching CSS selectors/styles) and the latter triggers animations that are registered via `module.animation()`. For\n * both CSS and JS animations the sole requirement is to have a matching `CSS class` that exists both in the registered animation and within\n * the HTML element that the animation will be triggered on.\n *\n * ## Directive Support\n * The following directives are \"animation aware\":\n *\n * | Directive                                                                     | Supported Animations                                                      |\n * |-------------------------------------------------------------------------------|---------------------------------------------------------------------------|\n * | {@link ng.directive:form#animations form / ngForm}                            | add and remove ({@link ng.directive:form#css-classes various classes})    |\n * | {@link ngAnimate.directive:ngAnimateSwap#animations ngAnimateSwap}            | enter and leave                                                           |\n * | {@link ng.directive:ngClass#animations ngClass / {{class&#125;&#8203;&#125;}  | add and remove                                                            |\n * | {@link ng.directive:ngClassEven#animations ngClassEven}                       | add and remove                                                            |\n * | {@link ng.directive:ngClassOdd#animations ngClassOdd}                         | add and remove                                                            |\n * | {@link ng.directive:ngHide#animations ngHide}                                 | add and remove (the `ng-hide` class)                                      |\n * | {@link ng.directive:ngIf#animations ngIf}                                     | enter and leave                                                           |\n * | {@link ng.directive:ngInclude#animations ngInclude}                           | enter and leave                                                           |\n * | {@link module:ngMessages#animations ngMessage / ngMessageExp}                 | enter and leave                                                           |\n * | {@link module:ngMessages#animations ngMessages}                               | add and remove (the `ng-active`/`ng-inactive` classes)                    |\n * | {@link ng.directive:ngModel#animations ngModel}                               | add and remove ({@link ng.directive:ngModel#css-classes various classes}) |\n * | {@link ng.directive:ngRepeat#animations ngRepeat}                             | enter, leave, and move                                                    |\n * | {@link ng.directive:ngShow#animations ngShow}                                 | add and remove (the `ng-hide` class)                                      |\n * | {@link ng.directive:ngSwitch#animations ngSwitch}                             | enter and leave                                                           |\n * | {@link ngRoute.directive:ngView#animations ngView}                            | enter and leave                                                           |\n *\n * (More information can be found by visiting the documentation associated with each directive.)\n *\n * For a full breakdown of the steps involved during each animation event, refer to the\n * {@link ng.$animate `$animate` API docs}.\n *\n * ## CSS-based Animations\n *\n * CSS-based animations with ngAnimate are unique since they require no JavaScript code at all. By using a CSS class that we reference between our HTML\n * and CSS code we can create an animation that will be picked up by AngularJS when an underlying directive performs an operation.\n *\n * The example below shows how an `enter` animation can be made possible on an element using `ng-if`:\n *\n * ```html\n * <div ng-if=\"bool\" class=\"fade\">\n *    Fade me in out\n * </div>\n * <button ng-click=\"bool=true\">Fade In!</button>\n * <button ng-click=\"bool=false\">Fade Out!</button>\n * ```\n *\n * Notice the CSS class **fade**? We can now create the CSS transition code that references this class:\n *\n * ```css\n * /&#42; The starting CSS styles for the enter animation &#42;/\n * .fade.ng-enter {\n *   transition:0.5s linear all;\n *   opacity:0;\n * }\n *\n * /&#42; The finishing CSS styles for the enter animation &#42;/\n * .fade.ng-enter.ng-enter-active {\n *   opacity:1;\n * }\n * ```\n *\n * The key thing to remember here is that, depending on the animation event (which each of the directives above trigger depending on what's going on) two\n * generated CSS classes will be applied to the element; in the example above we have `.ng-enter` and `.ng-enter-active`. For CSS transitions, the transition\n * code **must** be defined within the starting CSS class (in this case `.ng-enter`). The destination class is what the transition will animate towards.\n *\n * If for example we wanted to create animations for `leave` and `move` (ngRepeat triggers move) then we can do so using the same CSS naming conventions:\n *\n * ```css\n * /&#42; now the element will fade out before it is removed from the DOM &#42;/\n * .fade.ng-leave {\n *   transition:0.5s linear all;\n *   opacity:1;\n * }\n * .fade.ng-leave.ng-leave-active {\n *   opacity:0;\n * }\n * ```\n *\n * We can also make use of **CSS Keyframes** by referencing the keyframe animation within the starting CSS class:\n *\n * ```css\n * /&#42; there is no need to define anything inside of the destination\n * CSS class since the keyframe will take charge of the animation &#42;/\n * .fade.ng-leave {\n *   animation: my_fade_animation 0.5s linear;\n *   -webkit-animation: my_fade_animation 0.5s linear;\n * }\n *\n * @keyframes my_fade_animation {\n *   from { opacity:1; }\n *   to { opacity:0; }\n * }\n *\n * @-webkit-keyframes my_fade_animation {\n *   from { opacity:1; }\n *   to { opacity:0; }\n * }\n * ```\n *\n * Feel free also mix transitions and keyframes together as well as any other CSS classes on the same element.\n *\n * ### CSS Class-based Animations\n *\n * Class-based animations (animations that are triggered via `ngClass`, `ngShow`, `ngHide` and some other directives) have a slightly different\n * naming convention. Class-based animations are basic enough that a standard transition or keyframe can be referenced on the class being added\n * and removed.\n *\n * For example if we wanted to do a CSS animation for `ngHide` then we place an animation on the `.ng-hide` CSS class:\n *\n * ```html\n * <div ng-show=\"bool\" class=\"fade\">\n *   Show and hide me\n * </div>\n * <button ng-click=\"bool=!bool\">Toggle</button>\n *\n * <style>\n * .fade.ng-hide {\n *   transition:0.5s linear all;\n *   opacity:0;\n * }\n * </style>\n * ```\n *\n * All that is going on here with ngShow/ngHide behind the scenes is the `.ng-hide` class is added/removed (when the hidden state is valid). Since\n * ngShow and ngHide are animation aware then we can match up a transition and ngAnimate handles the rest.\n *\n * In addition the addition and removal of the CSS class, ngAnimate also provides two helper methods that we can use to further decorate the animation\n * with CSS styles.\n *\n * ```html\n * <div ng-class=\"{on:onOff}\" class=\"highlight\">\n *   Highlight this box\n * </div>\n * <button ng-click=\"onOff=!onOff\">Toggle</button>\n *\n * <style>\n * .highlight {\n *   transition:0.5s linear all;\n * }\n * .highlight.on-add {\n *   background:white;\n * }\n * .highlight.on {\n *   background:yellow;\n * }\n * .highlight.on-remove {\n *   background:black;\n * }\n * </style>\n * ```\n *\n * We can also make use of CSS keyframes by placing them within the CSS classes.\n *\n *\n * ### CSS Staggering Animations\n * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a\n * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be\n * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for\n * the animation. The style property expected within the stagger class can either be a **transition-delay** or an\n * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).\n *\n * ```css\n * .my-animation.ng-enter {\n *   /&#42; standard transition code &#42;/\n *   transition: 1s linear all;\n *   opacity:0;\n * }\n * .my-animation.ng-enter-stagger {\n *   /&#42; this will have a 100ms delay between each successive leave animation &#42;/\n *   transition-delay: 0.1s;\n *\n *   /&#42; As of 1.4.4, this must always be set: it signals ngAnimate\n *     to not accidentally inherit a delay property from another CSS class &#42;/\n *   transition-duration: 0s;\n *\n *   /&#42; if you are using animations instead of transitions you should configure as follows:\n *     animation-delay: 0.1s;\n *     animation-duration: 0s; &#42;/\n * }\n * .my-animation.ng-enter.ng-enter-active {\n *   /&#42; standard transition styles &#42;/\n *   opacity:1;\n * }\n * ```\n *\n * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations\n * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this\n * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation\n * will also be reset if one or more animation frames have passed since the multiple calls to `$animate` were fired.\n *\n * The following code will issue the **ng-leave-stagger** event on the element provided:\n *\n * ```js\n * var kids = parent.children();\n *\n * $animate.leave(kids[0]); //stagger index=0\n * $animate.leave(kids[1]); //stagger index=1\n * $animate.leave(kids[2]); //stagger index=2\n * $animate.leave(kids[3]); //stagger index=3\n * $animate.leave(kids[4]); //stagger index=4\n *\n * window.requestAnimationFrame(function() {\n *   //stagger has reset itself\n *   $animate.leave(kids[5]); //stagger index=0\n *   $animate.leave(kids[6]); //stagger index=1\n *\n *   $scope.$digest();\n * });\n * ```\n *\n * Stagger animations are currently only supported within CSS-defined animations.\n *\n * ### The `ng-animate` CSS class\n *\n * When ngAnimate is animating an element it will apply the `ng-animate` CSS class to the element for the duration of the animation.\n * This is a temporary CSS class and it will be removed once the animation is over (for both JavaScript and CSS-based animations).\n *\n * Therefore, animations can be applied to an element using this temporary class directly via CSS.\n *\n * ```css\n * .zipper.ng-animate {\n *   transition:0.5s linear all;\n * }\n * .zipper.ng-enter {\n *   opacity:0;\n * }\n * .zipper.ng-enter.ng-enter-active {\n *   opacity:1;\n * }\n * .zipper.ng-leave {\n *   opacity:1;\n * }\n * .zipper.ng-leave.ng-leave-active {\n *   opacity:0;\n * }\n * ```\n *\n * (Note that the `ng-animate` CSS class is reserved and it cannot be applied on an element directly since ngAnimate will always remove\n * the CSS class once an animation has completed.)\n *\n *\n * ### The `ng-[event]-prepare` class\n *\n * This is a special class that can be used to prevent unwanted flickering / flash of content before\n * the actual animation starts. The class is added as soon as an animation is initialized, but removed\n * before the actual animation starts (after waiting for a $digest).\n * It is also only added for *structural* animations (`enter`, `move`, and `leave`).\n *\n * In practice, flickering can appear when nesting elements with structural animations such as `ngIf`\n * into elements that have class-based animations such as `ngClass`.\n *\n * ```html\n * <div ng-class=\"{red: myProp}\">\n *   <div ng-class=\"{blue: myProp}\">\n *     <div class=\"message\" ng-if=\"myProp\"></div>\n *   </div>\n * </div>\n * ```\n *\n * It is possible that during the `enter` animation, the `.message` div will be briefly visible before it starts animating.\n * In that case, you can add styles to the CSS that make sure the element stays hidden before the animation starts:\n *\n * ```css\n * .message.ng-enter-prepare {\n *   opacity: 0;\n * }\n * ```\n *\n * ### Animating between value changes\n *\n * Sometimes you need to animate between different expression states, whose values\n * don't necessary need to be known or referenced in CSS styles.\n * Unless possible with another {@link ngAnimate#directive-support \"animation aware\" directive},\n * that specific use case can always be covered with {@link ngAnimate.directive:ngAnimateSwap} as\n * can be seen in {@link ngAnimate.directive:ngAnimateSwap#examples this example}.\n *\n * Note that {@link ngAnimate.directive:ngAnimateSwap} is a *structural directive*, which means it\n * creates a new instance of the element (including any other/child directives it may have) and\n * links it to a new scope every time *swap* happens. In some cases this might not be desirable\n * (e.g. for performance reasons, or when you wish to retain internal state on the original\n * element instance).\n *\n * ## JavaScript-based Animations\n *\n * ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared\n * CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the\n * `module.animation()` module function we can register the animation.\n *\n * Let's see an example of a enter/leave animation using `ngRepeat`:\n *\n * ```html\n * <div ng-repeat=\"item in items\" class=\"slide\">\n *   {{ item }}\n * </div>\n * ```\n *\n * See the **slide** CSS class? Let's use that class to define an animation that we'll structure in our module code by using `module.animation`:\n *\n * ```js\n * myModule.animation('.slide', [function() {\n *   return {\n *     // make note that other events (like addClass/removeClass)\n *     // have different function input parameters\n *     enter: function(element, doneFn) {\n *       jQuery(element).fadeIn(1000, doneFn);\n *\n *       // remember to call doneFn so that AngularJS\n *       // knows that the animation has concluded\n *     },\n *\n *     move: function(element, doneFn) {\n *       jQuery(element).fadeIn(1000, doneFn);\n *     },\n *\n *     leave: function(element, doneFn) {\n *       jQuery(element).fadeOut(1000, doneFn);\n *     }\n *   }\n * }]);\n * ```\n *\n * The nice thing about JS-based animations is that we can inject other services and make use of advanced animation libraries such as\n * greensock.js and velocity.js.\n *\n * If our animation code class-based (meaning that something like `ngClass`, `ngHide` and `ngShow` triggers it) then we can still define\n * our animations inside of the same registered animation, however, the function input arguments are a bit different:\n *\n * ```html\n * <div ng-class=\"color\" class=\"colorful\">\n *   this box is moody\n * </div>\n * <button ng-click=\"color='red'\">Change to red</button>\n * <button ng-click=\"color='blue'\">Change to blue</button>\n * <button ng-click=\"color='green'\">Change to green</button>\n * ```\n *\n * ```js\n * myModule.animation('.colorful', [function() {\n *   return {\n *     addClass: function(element, className, doneFn) {\n *       // do some cool animation and call the doneFn\n *     },\n *     removeClass: function(element, className, doneFn) {\n *       // do some cool animation and call the doneFn\n *     },\n *     setClass: function(element, addedClass, removedClass, doneFn) {\n *       // do some cool animation and call the doneFn\n *     }\n *   }\n * }]);\n * ```\n *\n * ## CSS + JS Animations Together\n *\n * AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of AngularJS,\n * defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking\n * charge of the animation**:\n *\n * ```html\n * <div ng-if=\"bool\" class=\"slide\">\n *   Slide in and out\n * </div>\n * ```\n *\n * ```js\n * myModule.animation('.slide', [function() {\n *   return {\n *     enter: function(element, doneFn) {\n *       jQuery(element).slideIn(1000, doneFn);\n *     }\n *   }\n * }]);\n * ```\n *\n * ```css\n * .slide.ng-enter {\n *   transition:0.5s linear all;\n *   transform:translateY(-100px);\n * }\n * .slide.ng-enter.ng-enter-active {\n *   transform:translateY(0);\n * }\n * ```\n *\n * Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the\n * lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from\n * our own JS-based animation code:\n *\n * ```js\n * myModule.animation('.slide', ['$animateCss', function($animateCss) {\n *   return {\n *     enter: function(element) {\n*        // this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`.\n *       return $animateCss(element, {\n *         event: 'enter',\n *         structural: true\n *       });\n *     }\n *   }\n * }]);\n * ```\n *\n * The nice thing here is that we can save bandwidth by sticking to our CSS-based animation code and we don't need to rely on a 3rd-party animation framework.\n *\n * The `$animateCss` service is very powerful since we can feed in all kinds of extra properties that will be evaluated and fed into a CSS transition or\n * keyframe animation. For example if we wanted to animate the height of an element while adding and removing classes then we can do so by providing that\n * data into `$animateCss` directly:\n *\n * ```js\n * myModule.animation('.slide', ['$animateCss', function($animateCss) {\n *   return {\n *     enter: function(element) {\n *       return $animateCss(element, {\n *         event: 'enter',\n *         structural: true,\n *         addClass: 'maroon-setting',\n *         from: { height:0 },\n *         to: { height: 200 }\n *       });\n *     }\n *   }\n * }]);\n * ```\n *\n * Now we can fill in the rest via our transition CSS code:\n *\n * ```css\n * /&#42; the transition tells ngAnimate to make the animation happen &#42;/\n * .slide.ng-enter { transition:0.5s linear all; }\n *\n * /&#42; this extra CSS class will be absorbed into the transition\n * since the $animateCss code is adding the class &#42;/\n * .maroon-setting { background:red; }\n * ```\n *\n * And `$animateCss` will figure out the rest. Just make sure to have the `done()` callback fire the `doneFn` function to signal when the animation is over.\n *\n * To learn more about what's possible be sure to visit the {@link ngAnimate.$animateCss $animateCss service}.\n *\n * ## Animation Anchoring (via `ng-animate-ref`)\n *\n * ngAnimate in AngularJS 1.4 comes packed with the ability to cross-animate elements between\n * structural areas of an application (like views) by pairing up elements using an attribute\n * called `ng-animate-ref`.\n *\n * Let's say for example we have two views that are managed by `ng-view` and we want to show\n * that there is a relationship between two components situated in within these views. By using the\n * `ng-animate-ref` attribute we can identify that the two components are paired together and we\n * can then attach an animation, which is triggered when the view changes.\n *\n * Say for example we have the following template code:\n *\n * ```html\n * <!-- index.html -->\n * <div ng-view class=\"view-animation\">\n * </div>\n *\n * <!-- home.html -->\n * <a href=\"#/banner-page\">\n *   <img src=\"./banner.jpg\" class=\"banner\" ng-animate-ref=\"banner\">\n * </a>\n *\n * <!-- banner-page.html -->\n * <img src=\"./banner.jpg\" class=\"banner\" ng-animate-ref=\"banner\">\n * ```\n *\n * Now, when the view changes (once the link is clicked), ngAnimate will examine the\n * HTML contents to see if there is a match reference between any components in the view\n * that is leaving and the view that is entering. It will scan both the view which is being\n * removed (leave) and inserted (enter) to see if there are any paired DOM elements that\n * contain a matching ref value.\n *\n * The two images match since they share the same ref value. ngAnimate will now create a\n * transport element (which is a clone of the first image element) and it will then attempt\n * to animate to the position of the second image element in the next view. For the animation to\n * work a special CSS class called `ng-anchor` will be added to the transported element.\n *\n * We can now attach a transition onto the `.banner.ng-anchor` CSS class and then\n * ngAnimate will handle the entire transition for us as well as the addition and removal of\n * any changes of CSS classes between the elements:\n *\n * ```css\n * .banner.ng-anchor {\n *   /&#42; this animation will last for 1 second since there are\n *          two phases to the animation (an `in` and an `out` phase) &#42;/\n *   transition:0.5s linear all;\n * }\n * ```\n *\n * We also **must** include animations for the views that are being entered and removed\n * (otherwise anchoring wouldn't be possible since the new view would be inserted right away).\n *\n * ```css\n * .view-animation.ng-enter, .view-animation.ng-leave {\n *   transition:0.5s linear all;\n *   position:fixed;\n *   left:0;\n *   top:0;\n *   width:100%;\n * }\n * .view-animation.ng-enter {\n *   transform:translateX(100%);\n * }\n * .view-animation.ng-leave,\n * .view-animation.ng-enter.ng-enter-active {\n *   transform:translateX(0%);\n * }\n * .view-animation.ng-leave.ng-leave-active {\n *   transform:translateX(-100%);\n * }\n * ```\n *\n * Now we can jump back to the anchor animation. When the animation happens, there are two stages that occur:\n * an `out` and an `in` stage. The `out` stage happens first and that is when the element is animated away\n * from its origin. Once that animation is over then the `in` stage occurs which animates the\n * element to its destination. The reason why there are two animations is to give enough time\n * for the enter animation on the new element to be ready.\n *\n * The example above sets up a transition for both the in and out phases, but we can also target the out or\n * in phases directly via `ng-anchor-out` and `ng-anchor-in`.\n *\n * ```css\n * .banner.ng-anchor-out {\n *   transition: 0.5s linear all;\n *\n *   /&#42; the scale will be applied during the out animation,\n *          but will be animated away when the in animation runs &#42;/\n *   transform: scale(1.2);\n * }\n *\n * .banner.ng-anchor-in {\n *   transition: 1s linear all;\n * }\n * ```\n *\n *\n *\n *\n * ### Anchoring Demo\n *\n  <example module=\"anchoringExample\"\n           name=\"anchoringExample\"\n           id=\"anchoringExample\"\n           deps=\"angular-animate.js;angular-route.js\"\n           animations=\"true\">\n    <file name=\"index.html\">\n      <a href=\"#!/\">Home</a>\n      <hr />\n      <div class=\"view-container\">\n        <div ng-view class=\"view\"></div>\n      </div>\n    </file>\n    <file name=\"script.js\">\n      angular.module('anchoringExample', ['ngAnimate', 'ngRoute'])\n        .config(['$routeProvider', function($routeProvider) {\n          $routeProvider.when('/', {\n            templateUrl: 'home.html',\n            controller: 'HomeController as home'\n          });\n          $routeProvider.when('/profile/:id', {\n            templateUrl: 'profile.html',\n            controller: 'ProfileController as profile'\n          });\n        }])\n        .run(['$rootScope', function($rootScope) {\n          $rootScope.records = [\n            { id: 1, title: 'Miss Beulah Roob' },\n            { id: 2, title: 'Trent Morissette' },\n            { id: 3, title: 'Miss Ava Pouros' },\n            { id: 4, title: 'Rod Pouros' },\n            { id: 5, title: 'Abdul Rice' },\n            { id: 6, title: 'Laurie Rutherford Sr.' },\n            { id: 7, title: 'Nakia McLaughlin' },\n            { id: 8, title: 'Jordon Blanda DVM' },\n            { id: 9, title: 'Rhoda Hand' },\n            { id: 10, title: 'Alexandrea Sauer' }\n          ];\n        }])\n        .controller('HomeController', [function() {\n          //empty\n        }])\n        .controller('ProfileController', ['$rootScope', '$routeParams',\n            function ProfileController($rootScope, $routeParams) {\n          var index = parseInt($routeParams.id, 10);\n          var record = $rootScope.records[index - 1];\n\n          this.title = record.title;\n          this.id = record.id;\n        }]);\n    </file>\n    <file name=\"home.html\">\n      <h2>Welcome to the home page</h1>\n      <p>Please click on an element</p>\n      <a class=\"record\"\n         ng-href=\"#!/profile/{{ record.id }}\"\n         ng-animate-ref=\"{{ record.id }}\"\n         ng-repeat=\"record in records\">\n        {{ record.title }}\n      </a>\n    </file>\n    <file name=\"profile.html\">\n      <div class=\"profile record\" ng-animate-ref=\"{{ profile.id }}\">\n        {{ profile.title }}\n      </div>\n    </file>\n    <file name=\"animations.css\">\n      .record {\n        display:block;\n        font-size:20px;\n      }\n      .profile {\n        background:black;\n        color:white;\n        font-size:100px;\n      }\n      .view-container {\n        position:relative;\n      }\n      .view-container > .view.ng-animate {\n        position:absolute;\n        top:0;\n        left:0;\n        width:100%;\n        min-height:500px;\n      }\n      .view.ng-enter, .view.ng-leave,\n      .record.ng-anchor {\n        transition:0.5s linear all;\n      }\n      .view.ng-enter {\n        transform:translateX(100%);\n      }\n      .view.ng-enter.ng-enter-active, .view.ng-leave {\n        transform:translateX(0%);\n      }\n      .view.ng-leave.ng-leave-active {\n        transform:translateX(-100%);\n      }\n      .record.ng-anchor-out {\n        background:red;\n      }\n    </file>\n  </example>\n *\n * ### How is the element transported?\n *\n * When an anchor animation occurs, ngAnimate will clone the starting element and position it exactly where the starting\n * element is located on screen via absolute positioning. The cloned element will be placed inside of the root element\n * of the application (where ng-app was defined) and all of the CSS classes of the starting element will be applied. The\n * element will then animate into the `out` and `in` animations and will eventually reach the coordinates and match\n * the dimensions of the destination element. During the entire animation a CSS class of `.ng-animate-shim` will be applied\n * to both the starting and destination elements in order to hide them from being visible (the CSS styling for the class\n * is: `visibility:hidden`). Once the anchor reaches its destination then it will be removed and the destination element\n * will become visible since the shim class will be removed.\n *\n * ### How is the morphing handled?\n *\n * CSS Anchoring relies on transitions and keyframes and the internal code is intelligent enough to figure out\n * what CSS classes differ between the starting element and the destination element. These different CSS classes\n * will be added/removed on the anchor element and a transition will be applied (the transition that is provided\n * in the anchor class). Long story short, ngAnimate will figure out what classes to add and remove which will\n * make the transition of the element as smooth and automatic as possible. Be sure to use simple CSS classes that\n * do not rely on DOM nesting structure so that the anchor element appears the same as the starting element (since\n * the cloned element is placed inside of root element which is likely close to the body element).\n *\n * Note that if the root element is on the `<html>` element then the cloned node will be placed inside of body.\n *\n *\n * ## Using $animate in your directive code\n *\n * So far we've explored how to feed in animations into an AngularJS application, but how do we trigger animations within our own directives in our application?\n * By injecting the `$animate` service into our directive code, we can trigger structural and class-based hooks which can then be consumed by animations. Let's\n * imagine we have a greeting box that shows and hides itself when the data changes\n *\n * ```html\n * <greeting-box active=\"onOrOff\">Hi there</greeting-box>\n * ```\n *\n * ```js\n * ngModule.directive('greetingBox', ['$animate', function($animate) {\n *   return function(scope, element, attrs) {\n *     attrs.$observe('active', function(value) {\n *       value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on');\n *     });\n *   });\n * }]);\n * ```\n *\n * Now the `on` CSS class is added and removed on the greeting box component. Now if we add a CSS class on top of the greeting box element\n * in our HTML code then we can trigger a CSS or JS animation to happen.\n *\n * ```css\n * /&#42; normally we would create a CSS class to reference on the element &#42;/\n * greeting-box.on { transition:0.5s linear all; background:green; color:white; }\n * ```\n *\n * The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's\n * possible be sure to visit the {@link ng.$animate $animate service API page}.\n *\n *\n * ## Callbacks and Promises\n *\n * When `$animate` is called it returns a promise that can be used to capture when the animation has ended. Therefore if we were to trigger\n * an animation (within our directive code) then we can continue performing directive and scope related activities after the animation has\n * ended by chaining onto the returned promise that animation method returns.\n *\n * ```js\n * // somewhere within the depths of the directive\n * $animate.enter(element, parent).then(function() {\n *   //the animation has completed\n * });\n * ```\n *\n * (Note that earlier versions of AngularJS prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case\n * anymore.)\n *\n * In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering\n * an event listener using the `$animate` service. Let's say for example that an animation was triggered on our view\n * routing controller to hook into that:\n *\n * ```js\n * ngModule.controller('HomePageController', ['$animate', function($animate) {\n *   $animate.on('enter', ngViewElement, function(element) {\n *     // the animation for this route has completed\n *   }]);\n * }])\n * ```\n *\n * (Note that you will need to trigger a digest within the callback to get AngularJS to notice any scope-related changes.)\n */\n\nvar copy;\nvar extend;\nvar forEach;\nvar isArray;\nvar isDefined;\nvar isElement;\nvar isFunction;\nvar isObject;\nvar isString;\nvar isUndefined;\nvar jqLite;\nvar noop;\n\n/**\n * @ngdoc service\n * @name $animate\n * @kind object\n *\n * @description\n * The ngAnimate `$animate` service documentation is the same for the core `$animate` service.\n *\n * Click here {@link ng.$animate to learn more about animations with `$animate`}.\n */\nangular.module('ngAnimate', [], function initAngularHelpers() {\n  // Access helpers from AngularJS core.\n  // Do it inside a `config` block to ensure `window.angular` is available.\n  noop        = angular.noop;\n  copy        = angular.copy;\n  extend      = angular.extend;\n  jqLite      = angular.element;\n  forEach     = angular.forEach;\n  isArray     = angular.isArray;\n  isString    = angular.isString;\n  isObject    = angular.isObject;\n  isUndefined = angular.isUndefined;\n  isDefined   = angular.isDefined;\n  isFunction  = angular.isFunction;\n  isElement   = angular.isElement;\n})\n  .info({ angularVersion: '1.8.2' })\n  .directive('ngAnimateSwap', ngAnimateSwapDirective)\n\n  .directive('ngAnimateChildren', $$AnimateChildrenDirective)\n  .factory('$$rAFScheduler', $$rAFSchedulerFactory)\n\n  .provider('$$animateQueue', $$AnimateQueueProvider)\n  .provider('$$animateCache', $$AnimateCacheProvider)\n  .provider('$$animation', $$AnimationProvider)\n\n  .provider('$animateCss', $AnimateCssProvider)\n  .provider('$$animateCssDriver', $$AnimateCssDriverProvider)\n\n  .provider('$$animateJs', $$AnimateJsProvider)\n  .provider('$$animateJsDriver', $$AnimateJsDriverProvider);\n\n\n})(window, window.angular);\n"],"sourceRoot":""}