Project import generated by Copybara.

GitOrigin-RevId: 63746295f1a5ab5a619056791995793d65529e62
diff --git a/node_modules/mdl-ext/src/sticky-header/_sticky-header.scss b/node_modules/mdl-ext/src/sticky-header/_sticky-header.scss
new file mode 100644
index 0000000..69a36f7
--- /dev/null
+++ b/node_modules/mdl-ext/src/sticky-header/_sticky-header.scss
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2016 Leif Olsen. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Use of this module requires the user to include variables from material-design-lite
+//@import "../../node_modules/material-design-lite/src/variables";
+//@import "../../node_modules/material-design-lite/src/mixins";
+@import "../variables";
+
+.mdlext-layout__sticky-header {
+  position: absolute;
+  overflow: visible;
+  background: $mdlext-sticky-header-background;
+  transition: 0.1s ease-in-out;
+
+  &.mdlext-is-scroll {
+    background: $mdlext-sticky-header-background-scroll;
+  }
+}
+
+*:not(.is-small-screen) .mdlext-layout__sticky-header {
+  .mdl-layout__drawer-button {
+    visibility: hidden;
+  }
+  .mdl-layout__header-row {
+    padding-left: $padding;
+  }
+}
+
+*:not(.mdl-layout--fixed-drawer).has-drawer .mdlext-layout__sticky-header,
+.is-small-screen.has-drawer .mdlext-layout__sticky-header {
+  display: flex;
+
+  .mdl-layout__drawer-button {
+    visibility: visible;
+  }
+  .mdl-layout__header-row {
+    padding-left: $padding + $layout-drawer-button-desktop-size;
+  }
+}
diff --git a/node_modules/mdl-ext/src/sticky-header/readme.md b/node_modules/mdl-ext/src/sticky-header/readme.md
new file mode 100644
index 0000000..e9b3107
--- /dev/null
+++ b/node_modules/mdl-ext/src/sticky-header/readme.md
@@ -0,0 +1,172 @@
+# Sticky Header
+
+![Sticky Header](../../etc/sticky-header.png)
+
+A sticky header can be used as a replacement for the Material Design Lite 
+[Fixed Header](https://github.com/google/material-design-lite/tree/master/src/layout#examples).
+
+## Introduction
+A sticky header makes site navigation easily accessible anywhere on the page and saves content space at the same.
+
+The header should auto-hide, i.e. hiding the header automatically when a user starts scrolling down the page and 
+bringing the header back when a user might need it: they reach the bottom of the page or start scrolling up.
+
+>**Note:** The Sticky Header does not collapse on smaller screens.
+
+### To include a MDLEXT **sticky-header** component:
+
+&nbsp;1. Code a `<div>` element. This is the "outer" div that holds the entire layout.
+```html
+<div>
+</div>
+```
+
+&nbsp;2. Add MDL classes as indicated, separated by spaces, to the `div` using the class attribute.
+```html
+<div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header">
+</div>
+```
+
+&nbsp;3. Inside the div, code a `<header>` element, as described in the Material Design Lite 
+[Component Guide](https://getmdl.io/components/index.html#layout-section/layout). Add MDL classes as indicated.
+```html
+<div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header">
+  <header class="mdl-layout__header mdlext-layout__sticky-header mdlext-js-sticky-header">
+    <div class="mdl-layout__header-row">
+  
+      <!-- Title -->
+      <span id="header-title" class="mdl-layout-title">Title goes here</span>
+  
+      <!-- Add spacer, to align navigation to the right -->
+      <div class="mdl-layout-spacer"></div>
+  
+      <label id="go-home" class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored">
+        <a href="#">
+          <i class="material-icons">home</i>
+        </a>
+      </label>
+    </div>
+  </header>
+</div>
+```
+
+&nbsp;4. Code a drawer, and include the MDL class as indicated
+```html
+<div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header">
+  <header class="mdl-layout__header mdlext-layout__sticky-header mdlext-js-sticky-header">
+    <div class="mdl-layout__header-row">
+  
+      <!-- Title -->
+      <span id="header-title" class="mdl-layout-title">Title goes here</span>
+  
+      <!-- Add spacer, to align navigation to the right -->
+      <div class="mdl-layout-spacer"></div>
+  
+      <label id="go-home" class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored">
+        <a href="#">
+          <i class="material-icons">home</i>
+        </a>
+      </label>
+    </div>
+  </header>
+
+  <aside class="mdl-layout__drawer">
+    <span class="mdl-layout-title">Drawer title</span>
+    <nav class="mdl-navigation">
+      <a class="mdl-navigation__link" href="#">A manu item</a>
+    </nav>
+  </aside>
+</div>
+```
+
+&nbsp;4. Add a `<main>` element to hold the layout's primary content, and include the MDL class as indicated
+```html
+<div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer mdl-layout--fixed-header">
+  <header class="mdl-layout__header mdlext-layout__sticky-header mdlext-js-sticky-header">
+    <div class="mdl-layout__header-row">
+  
+      <!-- Title -->
+      <span id="header-title" class="mdl-layout-title">Title goes here</span>
+  
+      <!-- Add spacer, to align navigation to the right -->
+      <div class="mdl-layout-spacer"></div>
+  
+      <label id="go-home" class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored">
+        <a href="#">
+          <i class="material-icons">home</i>
+        </a>
+      </label>
+    </div>
+  </header>
+
+  <aside class="mdl-layout__drawer">
+    <span class="mdl-layout-title">Drawer title</span>
+    <nav class="mdl-navigation">
+      <a class="mdl-navigation__link" href="#">A manu item</a>
+    </nav>
+  </aside>
+  
+  <main class="mdl-layout__content">
+    <p>Content</p>
+    <p>Goes</p>
+    <p>Here</p>
+  </main>  
+</div>
+```
+
+### Examples
+
+* [Sticky header, Fixed drawer](http://leifoolsen.github.io/mdl-ext/demo/sticky-header.html)
+* [Sticky header, Drawer](http://leifoolsen.github.io/mdl-ext/demo/sticky-header-ii.html)
+* [Sticky header, No Drawer](http://leifoolsen.github.io/mdl-ext/demo/sticky-header-iii.html)
+* [Sticky header, Waterfall, Fiexed Drawer](http://leifoolsen.github.io/mdl-ext/demo/sticky-header-iv.html)
+* [Sticky header, Waterfall, Drawer](http://leifoolsen.github.io/mdl-ext/demo/sticky-header-v.html)
+* [Sticky header, Waterfall, No Drawer](http://leifoolsen.github.io/mdl-ext/demo/sticky-header-vi.html)
+
+
+## Component configuration
+The component can be configured using a `data-config` attribute. The attribute value is a JSON string with the following properties.
+
+| Property             |    |    |
+|----------------------|----|----|
+| `visibleAtScrollEnd` | if `true`, the header vil show when page is scrolled to the bottom | default: `false` |
+
+
+The `data-config` attribute must be a valid JSON string. You can use single or double quotes for the JSON properties. 
+
+Example 1, single quotes in JSON config string:
+```html
+<header class="mdl-layout__header mdlext-layout__sticky-header mdlext-js-sticky-header" 
+  data-config="{ 'visibleAtScrollEnd': true }">
+  
+  <div class="mdl-layout__header-row">
+    <span id="header-title" class="mdl-layout-title">Title goes here</span>
+  </div>
+</header>
+```
+
+Example 2, double quotes in JSON config string:
+```html
+<header class="mdl-layout__header mdlext-layout__sticky-header mdlext-js-sticky-header" 
+  data-config='{ "visibleAtScrollEnd": true }'>
+  
+  <div class="mdl-layout__header-row">
+    <span id="header-title" class="mdl-layout-title">Title goes here</span>
+  </div>
+</header>
+```
+
+## Configuration options
+
+The MDLEXT CSS classes apply various predefined visual and behavioral enhancements to the lightbox.
+The table below lists the available classes and their effects.
+
+| MDLEXT class | Effect | Remarks |
+|--------------|--------|---------|
+| `mdlext-layout__sticky-header` | Defines a header as an MDLEXT header component | Required on `<header>` element |
+| `mdlext-js-sticky-header` | Assigns basic MDL behavior to header | Required on `<header>` element |
+
+
+## How to use the component programmatically
+The [tests](../../test/sticky-header/sticky-header.spec.js) provides example code on how to use the component programmatically.
+
diff --git a/node_modules/mdl-ext/src/sticky-header/sticky-header.js b/node_modules/mdl-ext/src/sticky-header/sticky-header.js
new file mode 100644
index 0000000..9ed2e13
--- /dev/null
+++ b/node_modules/mdl-ext/src/sticky-header/sticky-header.js
@@ -0,0 +1,251 @@
+/**
+ * @license
+ * Copyright 2016 Leif Olsen. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This code is built with Google Material Design Lite,
+ * which is Licensed under the Apache License, Version 2.0
+ */
+
+/**
+ * A sticky header makes site navigation easily accessible anywhere on the page and saves content space at the same.
+ * The header should auto-hide, i.e. hiding the header automatically when a user starts scrolling down the page and
+ * bringing the header back when a user might need it: they reach the bottom of the page or start scrolling up.
+ */
+
+import fullThrottle from '../utils/full-throttle';
+import { jsonStringToObject } from '../utils/json-utils';
+import {
+  IS_UPGRADED
+} from '../utils/constants';
+
+
+(function() {
+  'use strict';
+  const MDL_LAYOUT_CONTENT  = 'mdl-layout__content';
+  const IS_SCROLL_CLASS  = 'mdlext-is-scroll';
+
+
+  /**
+   * @constructor
+   * @param {Element} element The element that will be upgraded.
+   */
+  const MaterialExtStickyHeader = function MaterialExtStickyHeader(element) {
+    // Stores the element.
+    this.header_ = element;
+
+    // Heder listens to scroll events from content
+    this.content_ = null;
+    this.lastScrollTop_ = 0;
+
+    // Default config
+    this.config_ = {
+      visibleAtScrollEnd: false
+    };
+
+    this.mutationObserver_ = null;
+
+    this.drawing_ = false;
+
+    // Initialize instance.
+    this.init();
+  };
+
+  window['MaterialExtStickyHeader'] = MaterialExtStickyHeader;
+
+
+  /**
+   * Update header width
+   * @private
+   */
+  MaterialExtStickyHeader.prototype.recalcWidth_ = function() {
+    this.header_.style.width = `${this.content_.clientWidth}px`;
+  };
+
+  const throttleResize = fullThrottle(self => self.recalcWidth_() );
+
+  /**
+   * Adjust header width when window resizes or oreientation changes
+   * @param event
+   * @private
+   */
+  MaterialExtStickyHeader.prototype.resizeHandler_ = function( /* event */ ) {
+    throttleResize(this);
+  };
+
+
+  /**
+   * Update header position
+   * @private
+   */
+  MaterialExtStickyHeader.prototype.reposition_ = function() {
+
+    const currentContentScrollTop = this.content_.scrollTop;
+    const scrollDiff = this.lastScrollTop_ - currentContentScrollTop;
+
+    if(currentContentScrollTop <= 0) {
+      // Scrolled to the top. Header sticks to the top
+      this.header_.style.top = '0';
+      this.header_.classList.remove(IS_SCROLL_CLASS);
+    }
+    else if(scrollDiff > 0) {
+
+      if(scrollDiff >= this.header_.offsetHeight) {
+
+        // Scrolled up. Header slides in
+        const headerTop = (parseInt( window.getComputedStyle( this.header_ ).getPropertyValue( 'top' ) ) || 0);
+        if(headerTop != 0) {
+          this.header_.style.top = '0';
+          this.header_.classList.add(IS_SCROLL_CLASS);
+        }
+        this.lastScrollTop_ = currentContentScrollTop;
+      }
+      return;
+    }
+    else if(scrollDiff < 0) {
+      // Scrolled down
+      this.header_.classList.add(IS_SCROLL_CLASS);
+      let headerTop = (parseInt( window.getComputedStyle( this.header_ ).getPropertyValue( 'top' ) ) || 0);
+
+      if (this.content_.scrollHeight - this.content_.scrollTop <= this.content_.offsetHeight) {
+        // Bottom of content
+        if(headerTop != 0) {
+          this.header_.style.top = this.config_.visibleAtScrollEnd ? '0' : `-${this.header_.offsetHeight}px`;
+        }
+      }
+      else {
+        headerTop += scrollDiff;
+        const offsetHeight = this.header_.offsetHeight;
+        this.header_.style.top = `${( Math.abs( headerTop ) > offsetHeight ? -offsetHeight : headerTop )}px`;
+      }
+    }
+
+    this.lastScrollTop_ = currentContentScrollTop;
+  };
+
+
+  const throttleScroll = fullThrottle((self) => self.reposition_());
+
+  /**
+   * Scroll header when content scrolls
+   * @param event
+   * @private
+   */
+  MaterialExtStickyHeader.prototype.scrollHandler_ = function( /* event */ ) {
+    throttleScroll(this);
+  };
+
+  /**
+   * Init header position
+   * @private
+   */
+  MaterialExtStickyHeader.prototype.updatePosition_ = function( /* event */ ) {
+    this.recalcWidth_();
+    this.reposition_();
+  };
+
+  /**
+   * Add mutation observer
+   * @private
+   */
+  MaterialExtStickyHeader.prototype.addMutationObserver_ = function() {
+
+    // jsdom does not support MutationObserver - so this is not testable
+    /* istanbul ignore next */
+    this.mutationObserver_ = new MutationObserver( ( /*mutations*/ ) => {
+      // Adjust header width if content changes (e.g. in a SPA)
+      this.updatePosition_();
+    });
+
+    this.mutationObserver_.observe( this.content_, {
+      attributes: false,
+      childList: true,
+      characterData: false,
+      subtree: true
+    });
+  };
+
+    /**
+   * Removes event listeners
+   * @private
+   */
+  MaterialExtStickyHeader.prototype.removeListeners_ = function() {
+
+    window.removeEventListener('resize', this.resizeHandler_);
+    window.removeEventListener('orientationchange', this.resizeHandler_);
+
+    if(this.content_) {
+      this.content_.removeEventListener('scroll', this.scrollHandler_);
+    }
+
+    if(this.mutationObserver_) {
+      this.mutationObserver_.disconnect();
+      this.mutationObserver_ = null;
+    }
+  };
+
+  /**
+   * Initialize component
+   */
+  MaterialExtStickyHeader.prototype.init = function() {
+
+    if (this.header_) {
+
+      this.removeListeners_();
+
+      if(this.header_.hasAttribute('data-config')) {
+        this.config_ = jsonStringToObject(this.header_.getAttribute('data-config'));
+      }
+
+      this.content_ = this.header_.parentNode.querySelector(`.${MDL_LAYOUT_CONTENT}`) || null;
+
+      if(this.content_) {
+        this.content_.style.paddingTop = `${this.header_.offsetHeight}px`;  // Make room for sticky header
+        this.lastScrollTop_ = this.content_.scrollTop;
+
+        this.content_.addEventListener('scroll', this.scrollHandler_.bind(this));
+        window.addEventListener('resize', this.resizeHandler_.bind(this));
+        window.addEventListener('orientationchange', this.resizeHandler_.bind(this));
+
+        this.addMutationObserver_();
+        this.updatePosition_();
+
+        // Set upgraded flag
+        this.header_.classList.add(IS_UPGRADED);
+      }
+    }
+  };
+
+  /*
+   * Downgrade component
+   * E.g remove listeners and clean up resources
+   *
+   * Nothing to clean
+   *
+   MaterialExtStickyHeader.prototype.mdlDowngrade_ = function() {
+     'use strict';
+     console.log('***** MaterialExtStickyHeader.prototype.mdlDowngrade_');
+   };
+   */
+
+
+  // The component registers itself. It can assume componentHandler is available
+  // in the global scope.
+  /* eslint no-undef: 0 */
+  componentHandler.register({
+    constructor: MaterialExtStickyHeader,
+    classAsString: 'MaterialExtStickyHeader',
+    cssClass: 'mdlext-js-sticky-header'
+  });
+})();