Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: appengine/swarming/elements/build/elements.html

Issue 2182693002: Add new botlist for swarming (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@app-wrapper
Patch Set: Add documentation Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 <!DOCTYPE html><html><head><!-- 1 <!DOCTYPE html><html><head><!--
2 @license 2 @license
3 Copyright (c) 2016 The Polymer Project Authors. All rights reserved. 3 Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt 4 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt
7 Code distributed by Google as part of the polymer project is also 7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt
9 --><!-- 9 --><!--
10 @license 10 @license
(...skipping 14629 matching lines...) Expand 10 before | Expand all | Expand 10 after
14640 type: String, 14640 type: String,
14641 } 14641 }
14642 }, 14642 },
14643 14643
14644 signIn: function(){ 14644 signIn: function(){
14645 this.$.request.generateRequest(); 14645 this.$.request.generateRequest();
14646 }, 14646 },
14647 14647
14648 }); 14648 });
14649 </script> 14649 </script>
14650 </dom-module>
14651
14652 <script>
14653
14654 (function() {
14655
14656 // monostate data
14657 var metaDatas = {};
14658 var metaArrays = {};
14659 var singleton = null;
14660
14661 Polymer.IronMeta = Polymer({
14662
14663 is: 'iron-meta',
14664
14665 properties: {
14666
14667 /**
14668 * The type of meta-data. All meta-data of the same type is stored
14669 * together.
14670 */
14671 type: {
14672 type: String,
14673 value: 'default',
14674 observer: '_typeChanged'
14675 },
14676
14677 /**
14678 * The key used to store `value` under the `type` namespace.
14679 */
14680 key: {
14681 type: String,
14682 observer: '_keyChanged'
14683 },
14684
14685 /**
14686 * The meta-data to store or retrieve.
14687 */
14688 value: {
14689 type: Object,
14690 notify: true,
14691 observer: '_valueChanged'
14692 },
14693
14694 /**
14695 * If true, `value` is set to the iron-meta instance itself.
14696 */
14697 self: {
14698 type: Boolean,
14699 observer: '_selfChanged'
14700 },
14701
14702 /**
14703 * Array of all meta-data values for the given type.
14704 */
14705 list: {
14706 type: Array,
14707 notify: true
14708 }
14709
14710 },
14711
14712 hostAttributes: {
14713 hidden: true
14714 },
14715
14716 /**
14717 * Only runs if someone invokes the factory/constructor directly
14718 * e.g. `new Polymer.IronMeta()`
14719 *
14720 * @param {{type: (string|undefined), key: (string|undefined), value}=} co nfig
14721 */
14722 factoryImpl: function(config) {
14723 if (config) {
14724 for (var n in config) {
14725 switch(n) {
14726 case 'type':
14727 case 'key':
14728 case 'value':
14729 this[n] = config[n];
14730 break;
14731 }
14732 }
14733 }
14734 },
14735
14736 created: function() {
14737 // TODO(sjmiles): good for debugging?
14738 this._metaDatas = metaDatas;
14739 this._metaArrays = metaArrays;
14740 },
14741
14742 _keyChanged: function(key, old) {
14743 this._resetRegistration(old);
14744 },
14745
14746 _valueChanged: function(value) {
14747 this._resetRegistration(this.key);
14748 },
14749
14750 _selfChanged: function(self) {
14751 if (self) {
14752 this.value = this;
14753 }
14754 },
14755
14756 _typeChanged: function(type) {
14757 this._unregisterKey(this.key);
14758 if (!metaDatas[type]) {
14759 metaDatas[type] = {};
14760 }
14761 this._metaData = metaDatas[type];
14762 if (!metaArrays[type]) {
14763 metaArrays[type] = [];
14764 }
14765 this.list = metaArrays[type];
14766 this._registerKeyValue(this.key, this.value);
14767 },
14768
14769 /**
14770 * Retrieves meta data value by key.
14771 *
14772 * @method byKey
14773 * @param {string} key The key of the meta-data to be returned.
14774 * @return {*}
14775 */
14776 byKey: function(key) {
14777 return this._metaData && this._metaData[key];
14778 },
14779
14780 _resetRegistration: function(oldKey) {
14781 this._unregisterKey(oldKey);
14782 this._registerKeyValue(this.key, this.value);
14783 },
14784
14785 _unregisterKey: function(key) {
14786 this._unregister(key, this._metaData, this.list);
14787 },
14788
14789 _registerKeyValue: function(key, value) {
14790 this._register(key, value, this._metaData, this.list);
14791 },
14792
14793 _register: function(key, value, data, list) {
14794 if (key && data && value !== undefined) {
14795 data[key] = value;
14796 list.push(value);
14797 }
14798 },
14799
14800 _unregister: function(key, data, list) {
14801 if (key && data) {
14802 if (key in data) {
14803 var value = data[key];
14804 delete data[key];
14805 this.arrayDelete(list, value);
14806 }
14807 }
14808 }
14809
14810 });
14811
14812 Polymer.IronMeta.getIronMeta = function getIronMeta() {
14813 if (singleton === null) {
14814 singleton = new Polymer.IronMeta();
14815 }
14816 return singleton;
14817 };
14818
14819 /**
14820 `iron-meta-query` can be used to access infomation stored in `iron-meta`.
14821
14822 Examples:
14823
14824 If I create an instance like this:
14825
14826 <iron-meta key="info" value="foo/bar"></iron-meta>
14827
14828 Note that value="foo/bar" is the metadata I've defined. I could define more
14829 attributes or use child nodes to define additional metadata.
14830
14831 Now I can access that element (and it's metadata) from any `iron-meta-query` instance:
14832
14833 var value = new Polymer.IronMetaQuery({key: 'info'}).value;
14834
14835 @group Polymer Iron Elements
14836 @element iron-meta-query
14837 */
14838 Polymer.IronMetaQuery = Polymer({
14839
14840 is: 'iron-meta-query',
14841
14842 properties: {
14843
14844 /**
14845 * The type of meta-data. All meta-data of the same type is stored
14846 * together.
14847 */
14848 type: {
14849 type: String,
14850 value: 'default',
14851 observer: '_typeChanged'
14852 },
14853
14854 /**
14855 * Specifies a key to use for retrieving `value` from the `type`
14856 * namespace.
14857 */
14858 key: {
14859 type: String,
14860 observer: '_keyChanged'
14861 },
14862
14863 /**
14864 * The meta-data to store or retrieve.
14865 */
14866 value: {
14867 type: Object,
14868 notify: true,
14869 readOnly: true
14870 },
14871
14872 /**
14873 * Array of all meta-data values for the given type.
14874 */
14875 list: {
14876 type: Array,
14877 notify: true
14878 }
14879
14880 },
14881
14882 /**
14883 * Actually a factory method, not a true constructor. Only runs if
14884 * someone invokes it directly (via `new Polymer.IronMeta()`);
14885 *
14886 * @param {{type: (string|undefined), key: (string|undefined)}=} config
14887 */
14888 factoryImpl: function(config) {
14889 if (config) {
14890 for (var n in config) {
14891 switch(n) {
14892 case 'type':
14893 case 'key':
14894 this[n] = config[n];
14895 break;
14896 }
14897 }
14898 }
14899 },
14900
14901 created: function() {
14902 // TODO(sjmiles): good for debugging?
14903 this._metaDatas = metaDatas;
14904 this._metaArrays = metaArrays;
14905 },
14906
14907 _keyChanged: function(key) {
14908 this._setValue(this._metaData && this._metaData[key]);
14909 },
14910
14911 _typeChanged: function(type) {
14912 this._metaData = metaDatas[type];
14913 this.list = metaArrays[type];
14914 if (this.key) {
14915 this._keyChanged(this.key);
14916 }
14917 },
14918
14919 /**
14920 * Retrieves meta data value by key.
14921 * @param {string} key The key of the meta-data to be returned.
14922 * @return {*}
14923 */
14924 byKey: function(key) {
14925 return this._metaData && this._metaData[key];
14926 }
14927
14928 });
14929
14930 })();
14931 </script>
14932
14933
14934 <dom-module id="iron-icon" assetpath="/res/imp/bower_components/iron-icon/">
14935 <template>
14936 <style>
14937 :host {
14938 @apply(--layout-inline);
14939 @apply(--layout-center-center);
14940 position: relative;
14941
14942 vertical-align: middle;
14943
14944 fill: var(--iron-icon-fill-color, currentcolor);
14945 stroke: var(--iron-icon-stroke-color, none);
14946
14947 width: var(--iron-icon-width, 24px);
14948 height: var(--iron-icon-height, 24px);
14949 }
14950 </style>
14951 </template>
14952
14953 <script>
14954
14955 Polymer({
14956
14957 is: 'iron-icon',
14958
14959 properties: {
14960
14961 /**
14962 * The name of the icon to use. The name should be of the form:
14963 * `iconset_name:icon_name`.
14964 */
14965 icon: {
14966 type: String,
14967 observer: '_iconChanged'
14968 },
14969
14970 /**
14971 * The name of the theme to used, if one is specified by the
14972 * iconset.
14973 */
14974 theme: {
14975 type: String,
14976 observer: '_updateIcon'
14977 },
14978
14979 /**
14980 * If using iron-icon without an iconset, you can set the src to be
14981 * the URL of an individual icon image file. Note that this will take
14982 * precedence over a given icon attribute.
14983 */
14984 src: {
14985 type: String,
14986 observer: '_srcChanged'
14987 },
14988
14989 /**
14990 * @type {!Polymer.IronMeta}
14991 */
14992 _meta: {
14993 value: Polymer.Base.create('iron-meta', {type: 'iconset'}),
14994 observer: '_updateIcon'
14995 }
14996
14997 },
14998
14999 _DEFAULT_ICONSET: 'icons',
15000
15001 _iconChanged: function(icon) {
15002 var parts = (icon || '').split(':');
15003 this._iconName = parts.pop();
15004 this._iconsetName = parts.pop() || this._DEFAULT_ICONSET;
15005 this._updateIcon();
15006 },
15007
15008 _srcChanged: function(src) {
15009 this._updateIcon();
15010 },
15011
15012 _usesIconset: function() {
15013 return this.icon || !this.src;
15014 },
15015
15016 /** @suppress {visibility} */
15017 _updateIcon: function() {
15018 if (this._usesIconset()) {
15019 if (this._img && this._img.parentNode) {
15020 Polymer.dom(this.root).removeChild(this._img);
15021 }
15022 if (this._iconName === "") {
15023 if (this._iconset) {
15024 this._iconset.removeIcon(this);
15025 }
15026 } else if (this._iconsetName && this._meta) {
15027 this._iconset = /** @type {?Polymer.Iconset} */ (
15028 this._meta.byKey(this._iconsetName));
15029 if (this._iconset) {
15030 this._iconset.applyIcon(this, this._iconName, this.theme);
15031 this.unlisten(window, 'iron-iconset-added', '_updateIcon');
15032 } else {
15033 this.listen(window, 'iron-iconset-added', '_updateIcon');
15034 }
15035 }
15036 } else {
15037 if (this._iconset) {
15038 this._iconset.removeIcon(this);
15039 }
15040 if (!this._img) {
15041 this._img = document.createElement('img');
15042 this._img.style.width = '100%';
15043 this._img.style.height = '100%';
15044 this._img.draggable = false;
15045 }
15046 this._img.src = this.src;
15047 Polymer.dom(this.root).appendChild(this._img);
15048 }
15049 }
15050
15051 });
15052
15053 </script>
15054
15055 </dom-module>
15056 <script>
15057 /**
15058 * The `iron-iconset-svg` element allows users to define their own icon sets
15059 * that contain svg icons. The svg icon elements should be children of the
15060 * `iron-iconset-svg` element. Multiple icons should be given distinct id's.
15061 *
15062 * Using svg elements to create icons has a few advantages over traditional
15063 * bitmap graphics like jpg or png. Icons that use svg are vector based so
15064 * they are resolution independent and should look good on any device. They
15065 * are stylable via css. Icons can be themed, colorized, and even animated.
15066 *
15067 * Example:
15068 *
15069 * <iron-iconset-svg name="my-svg-icons" size="24">
15070 * <svg>
15071 * <defs>
15072 * <g id="shape">
15073 * <rect x="12" y="0" width="12" height="24" />
15074 * <circle cx="12" cy="12" r="12" />
15075 * </g>
15076 * </defs>
15077 * </svg>
15078 * </iron-iconset-svg>
15079 *
15080 * This will automatically register the icon set "my-svg-icons" to the iconset
15081 * database. To use these icons from within another element, make a
15082 * `iron-iconset` element and call the `byId` method
15083 * to retrieve a given iconset. To apply a particular icon inside an
15084 * element use the `applyIcon` method. For example:
15085 *
15086 * iconset.applyIcon(iconNode, 'car');
15087 *
15088 * @element iron-iconset-svg
15089 * @demo demo/index.html
15090 * @implements {Polymer.Iconset}
15091 */
15092 Polymer({
15093 is: 'iron-iconset-svg',
15094
15095 properties: {
15096
15097 /**
15098 * The name of the iconset.
15099 */
15100 name: {
15101 type: String,
15102 observer: '_nameChanged'
15103 },
15104
15105 /**
15106 * The size of an individual icon. Note that icons must be square.
15107 */
15108 size: {
15109 type: Number,
15110 value: 24
15111 }
15112
15113 },
15114
15115 attached: function() {
15116 this.style.display = 'none';
15117 },
15118
15119 /**
15120 * Construct an array of all icon names in this iconset.
15121 *
15122 * @return {!Array} Array of icon names.
15123 */
15124 getIconNames: function() {
15125 this._icons = this._createIconMap();
15126 return Object.keys(this._icons).map(function(n) {
15127 return this.name + ':' + n;
15128 }, this);
15129 },
15130
15131 /**
15132 * Applies an icon to the given element.
15133 *
15134 * An svg icon is prepended to the element's shadowRoot if it exists,
15135 * otherwise to the element itself.
15136 *
15137 * @method applyIcon
15138 * @param {Element} element Element to which the icon is applied.
15139 * @param {string} iconName Name of the icon to apply.
15140 * @return {?Element} The svg element which renders the icon.
15141 */
15142 applyIcon: function(element, iconName) {
15143 // insert svg element into shadow root, if it exists
15144 element = element.root || element;
15145 // Remove old svg element
15146 this.removeIcon(element);
15147 // install new svg element
15148 var svg = this._cloneIcon(iconName);
15149 if (svg) {
15150 var pde = Polymer.dom(element);
15151 pde.insertBefore(svg, pde.childNodes[0]);
15152 return element._svgIcon = svg;
15153 }
15154 return null;
15155 },
15156
15157 /**
15158 * Remove an icon from the given element by undoing the changes effected
15159 * by `applyIcon`.
15160 *
15161 * @param {Element} element The element from which the icon is removed.
15162 */
15163 removeIcon: function(element) {
15164 // Remove old svg element
15165 if (element._svgIcon) {
15166 Polymer.dom(element).removeChild(element._svgIcon);
15167 element._svgIcon = null;
15168 }
15169 },
15170
15171 /**
15172 *
15173 * When name is changed, register iconset metadata
15174 *
15175 */
15176 _nameChanged: function() {
15177 new Polymer.IronMeta({type: 'iconset', key: this.name, value: this});
15178 this.async(function() {
15179 this.fire('iron-iconset-added', this, {node: window});
15180 });
15181 },
15182
15183 /**
15184 * Create a map of child SVG elements by id.
15185 *
15186 * @return {!Object} Map of id's to SVG elements.
15187 */
15188 _createIconMap: function() {
15189 // Objects chained to Object.prototype (`{}`) have members. Specifically,
15190 // on FF there is a `watch` method that confuses the icon map, so we
15191 // need to use a null-based object here.
15192 var icons = Object.create(null);
15193 Polymer.dom(this).querySelectorAll('[id]')
15194 .forEach(function(icon) {
15195 icons[icon.id] = icon;
15196 });
15197 return icons;
15198 },
15199
15200 /**
15201 * Produce installable clone of the SVG element matching `id` in this
15202 * iconset, or `undefined` if there is no matching element.
15203 *
15204 * @return {Element} Returns an installable clone of the SVG element
15205 * matching `id`.
15206 */
15207 _cloneIcon: function(id) {
15208 // create the icon map on-demand, since the iconset itself has no discrete
15209 // signal to know when it's children are fully parsed
15210 this._icons = this._icons || this._createIconMap();
15211 return this._prepareSvgClone(this._icons[id], this.size);
15212 },
15213
15214 /**
15215 * @param {Element} sourceSvg
15216 * @param {number} size
15217 * @return {Element}
15218 */
15219 _prepareSvgClone: function(sourceSvg, size) {
15220 if (sourceSvg) {
15221 var content = sourceSvg.cloneNode(true),
15222 svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
15223 viewBox = content.getAttribute('viewBox') || '0 0 ' + size + ' ' + s ize;
15224 svg.setAttribute('viewBox', viewBox);
15225 svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
15226 // TODO(dfreedm): `pointer-events: none` works around https://crbug.com/ 370136
15227 // TODO(sjmiles): inline style may not be ideal, but avoids requiring a shadow-root
15228 svg.style.cssText = 'pointer-events: none; display: block; width: 100%; height: 100%;';
15229 svg.appendChild(content).removeAttribute('id');
15230 return svg;
15231 }
15232 return null;
15233 }
15234
15235 });
15236 </script>
15237 <iron-iconset-svg name="icons" size="24">
15238 <svg><defs>
15239 <g id="3d-rotation"><path d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 1 9.16 5.71 24 12 24l.66-.03-3.81-3.81-1.33 1.32zm.89-6.52c-.19 0-.37-.03-.52-.08- .16-.06-.29-.13-.4-.24-.11-.1-.2-.22-.26-.37-.06-.14-.09-.3-.09-.47h-1.3c0 .36.0 7.68.21.95.14.27.33.5.56.69.24.18.51.32.82.41.3.1.62.15.96.15.37 0 .72-.05 1.03- .15.32-.1.6-.25.83-.44s.42-.43.55-.72c.13-.29.2-.61.2-.97 0-.19-.02-.38-.07-.56- .05-.18-.12-.35-.23-.51-.1-.16-.24-.3-.4-.43-.17-.13-.37-.23-.61-.31.2-.09.37-.2 .52-.33.15-.13.27-.27.37-.42.1-.15.17-.3.22-.46.05-.16.07-.32.07-.48 0-.36-.06-. 68-.18-.96-.12-.28-.29-.51-.51-.69-.2-.19-.47-.33-.77-.43C9.1 8.05 8.76 8 8.39 8 c-.36 0-.69.05-1 .16-.3.11-.57.26-.79.45-.21.19-.38.41-.51.67-.12.26-.18.54-.18. 85h1.3c0-.17.03-.32.09-.45s.14-.25.25-.34c.11-.09.23-.17.38-.22.15-.05.3-.08.48- .08.4 0 .7.1.89.31.19.2.29.49.29.86 0 .18-.03.34-.08.49-.05.15-.14.27-.25.37-.11 .1-.25.18-.41.24-.16.06-.36.09-.58.09H7.5v1.03h.77c.22 0 .42.02.6.07s.33.13.45.2 3c.12.11.22.24.29.4.07.16.1.35.1.57 0 .41-.12.72-.35.93-.23.23-.55.33-.95.33zm8. 55-5.92c-.32-.33-.7-.59-1.14-.77-.43-.18-.92-.27-1.46-.27H12v8h2.3c.55 0 1.06-.0 9 1.51-.27.45-.18.84-.43 1.16-.76.32-.33.57-.73.74-1.19.17-.47.26-.99.26-1.57v-. 4c0-.58-.09-1.1-.26-1.57-.18-.47-.43-.87-.75-1.2zm-.39 3.16c0 .42-.05.79-.14 1.1 3-.1.33-.24.62-.43.85-.19.23-.43.41-.71.53-.29.12-.62.18-.99.18h-.91V9.12h.97c.7 2 0 1.27.23 1.64.69.38.46.57 1.12.57 1.99v.4zM12 0l-.66.03 3.81 3.81 1.33-1.33c3 .27 1.55 5.61 4.72 5.96 8.48h1.5C23.44 4.84 18.29 0 12 0z"></path></g>
15240 <g id="accessibility"><path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2z m9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z"></path></g>
15241 <g id="accessible"><circle cx="12" cy="4" r="2"></circle><path d="M19 13v-2c-1.5 4.02-3.09-.75-4.07-1.83l-1.29-1.43c-.17-.19-.38-.34-.61-.45-.01 0-.01-.01-.02-.0 1H13c-.35-.2-.75-.3-1.19-.26C10.76 7.11 10 8.04 10 9.09V15c0 1.1.9 2 2 2h5v5h2v- 5.5c0-1.1-.9-2-2-2h-3v-3.45c1.29 1.07 3.25 1.94 5 1.95zm-6.17 5c-.41 1.16-1.52 2 -2.83 2-1.66 0-3-1.34-3-3 0-1.31.84-2.41 2-2.83V12.1c-2.28.46-4 2.48-4 4.9 0 2.7 6 2.24 5 5 5 2.42 0 4.44-1.72 4.9-4h-2.07z"></path></g>
15242 <g id="account-balance"><path d="M4 10v7h3v-7H4zm6 0v7h3v-7h-3zM2 22h19v-3H2v3zm 14-12v7h3v-7h-3zm-4.5-9L2 6v2h19V6l-9.5-5z"></path></g>
15243 <g id="account-balance-wallet"><path d="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2 -2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm -9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"></path></g>
15244 <g id="account-box"><path d="M3 5v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9 -2-2-2H5c-1.11 0-2 .9-2 2zm12 4c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3zm-9 8c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6v-1z"></path></g>
15245 <g id="account-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 1 0-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14 .2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1. 94-3.5 3.22-6 3.22z"></path></g>
15246 <g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"></path></g>
15247 <g id="add-alert"><path d="M10.01 21.01c0 1.1.89 1.99 1.99 1.99s1.99-.89 1.99-1. 99h-3.98zm8.87-4.19V11c0-3.25-2.25-5.97-5.29-6.69v-.72C13.59 2.71 12.88 2 12 2s- 1.59.71-1.59 1.59v.72C7.37 5.03 5.12 7.75 5.12 11v5.82L3 18.94V20h18v-1.06l-2.12 -2.12zM16 13.01h-3v3h-2v-3H8V11h3V8h2v3h3v2.01z"></path></g>
15248 <g id="add-box"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-. 9 2-2V5c0-1.1-.9-2-2-2zm-2 10h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"></path></g>
15249 <g id="add-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10 S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"></path></g>
15250 <g id="add-circle-outline"><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8 s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"></path></g>
15251 <g id="add-shopping-cart"><path d="M11 9h2V6h3V4h-3V1h-2v3H8v2h3v3zm-4 9c-1.1 0- 1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zm10 0c-1.1 0-1.99.9-1.99 2s.89 2 1.9 9 2 2-.9 2-2-.9-2-2-2zm-9.83-3.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3 .86-7.01L19.42 4h-.01l-1.1 2-2.76 5H8.53l-.13-.27L6.16 6l-.95-2-.94-2H1v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.13 0-.25-.11-.25 -.25z"></path></g>
15252 <g id="alarm"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L 6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12.5 8H11v6l4.75 2.85.75-1.23-4-2.37V8zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3. 13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"></path></g>
15253 <g id="alarm-add"><path d="M7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM22 5. 72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7- 7 7zm1-11h-2v3H8v2h3v3h2v-3h3v-2h-3V9z"></path></g>
15254 <g id="alarm-off"><path d="M12 6c3.87 0 7 3.13 7 7 0 .84-.16 1.65-.43 2.4l1.52 1 .52c.58-1.19.91-2.51.91-3.92 0-4.97-4.03-9-9-9-1.41 0-2.73.33-3.92.91L9.6 6.43C1 0.35 6.16 11.16 6 12 6zm10-.28l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM2.92 2.29L1 .65 3.57 2.98 4.9l-1.11.93 1.42 1.42 1.11-.94.8.8C3.83 8.69 3 10.75 3 13c0 4.97 4.02 9 9 9 2.25 0 4.31-.83 5.89-2.2l2.2 2.2 1.27-1.27L3.89 3.27l-.97-.98zm13.55 16.1C15.26 19.39 13.7 20 12 20c-3.87 0-7-3.13-7-7 0-1.7.61-3.26 1.61-4.47l9.86 9 .86zM8.02 3.28L6.6 1.86l-.86.71 1.42 1.42.86-.71z"></path></g>
15255 <g id="alarm-on"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3. 39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm-1.46-5.47L8.41 12.4l-1.06 1.06 3.18 3.18 6-6-1.06-1.06-4.93 4.95z"></path>< /g>
15256 <g id="all-out"><path d="M16.21 4.16l4 4v-4zm4 12l-4 4h4zm-12 4l-4-4v4zm-4-12l4- 4h-4zm12.95-.95c-2.73-2.73-7.17-2.73-9.9 0s-2.73 7.17 0 9.9 7.17 2.73 9.9 0 2.73 -7.16 0-9.9zm-1.1 8.8c-2.13 2.13-5.57 2.13-7.7 0s-2.13-5.57 0-7.7 5.57-2.13 7.7 0 2.13 5.57 0 7.7z"></path></g>
15257 <g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v 10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4. 33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7 c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l -1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2- .71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4. 84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"></path></g>
15258 <g id="announcement"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-. 9 2-2V4c0-1.1-.9-2-2-2zm-7 9h-2V5h2v6zm0 4h-2v-2h2v2z"></path></g>
15259 <g id="apps"><path d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4z m6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"></p ath></g>
15260 <g id="archive"><path d="M20.54 5.23l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0 -.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.48-.17-.93-.46-1.27zM12 17.5L6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l.81 -1h12l.94 1H5.12z"></path></g>
15261 <g id="arrow-back"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 1 3H20v-2z"></path></g>
15262 <g id="arrow-downward"><path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59 L4 12l8 8 8-8z"></path></g>
15263 <g id="arrow-drop-down"><path d="M7 10l5 5 5-5z"></path></g>
15264 <g id="arrow-drop-down-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 1 0-4.48 10-10S17.52 2 12 2zm0 12l-4-4h8l-4 4z"></path></g>
15265 <g id="arrow-drop-up"><path d="M7 14l5-5 5 5z"></path></g>
15266 <g id="arrow-forward"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"></path></g>
15267 <g id="arrow-upward"><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l -8-8-8 8z"></path></g>
15268 <g id="aspect-ratio"><path d="M19 12h-2v3h-3v2h5v-5zM7 9h3V7H5v5h2V9zm14-6H3c-1. 1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99 h18v14.02z"></path></g>
15269 <g id="assessment"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2- .9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"></path></ g>
15270 <g id="assignment"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c. 55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm2 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4 H7V7h10v2z"></path></g>
15271 <g id="assignment-ind"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84- 2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm0 4c1.66 0 3 1.34 3 3s-1.34 3 -3 3-3-1.34-3-3 1.34-3 3-3zm6 12H6v-1.4c0-2 4-3.1 6-3.1s6 1.1 6 3.1V19z"></path> </g>
15272 <g id="assignment-late"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84 -2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm- 6 15h-2v-2h2v2zm0-4h-2V8h2v6zm-1-9c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"></path></g>
15273 <g id="assignment-return"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4. 84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z m-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm4 12h-4v3l-5-5 5-5v3h4v4z" ></path></g>
15274 <g id="assignment-returned"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2. 4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2- 2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm0 15l-5-5h3V9h4v4h3l-5 5 z"></path></g>
15275 <g id="assignment-turned-in"><path d="M19 3h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2 .4.84-2.82 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2 -2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm-2 14l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></g>
15276 <g id="attachment"><path d="M2 12.5C2 9.46 4.46 7 7.5 7H18c2.21 0 4 1.79 4 4s-1. 79 4-4 4H9.5C8.12 15 7 13.88 7 12.5S8.12 10 9.5 10H17v2H9.41c-.55 0-.55 1 0 1H18 c1.1 0 2-.9 2-2s-.9-2-2-2H7.5C5.57 9 4 10.57 4 12.5S5.57 16 7.5 16H17v2H7.5C4.46 18 2 15.54 2 12.5z"></path></g>
15277 <g id="autorenew"><path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1 .24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c .44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.4 6-3.03-1.24-4.26z"></path></g>
15278 <g id="backspace"><path d="M22 3H7c-.69 0-1.23.35-1.59.88L0 12l5.41 8.11c.36.53. 9.89 1.59.89h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-3 12.59L17.59 17 14 13.41 10.4 1 17 9 15.59 12.59 12 9 8.41 10.41 7 14 10.59 17.59 7 19 8.41 15.41 12 19 15.59z "></path></g>
15279 <g id="backup"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.3 5 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05 -4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"></path></g>
15280 <g id="block"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.5 2 2 12 2zM4 12c0-4.42 3.58-8 8-8 1.85 0 3.55.63 4.9 1.69L5.69 16.9C4.63 15.55 4 13.85 4 12zm8 8c-1.85 0-3.55-.63-4.9-1.69L18.31 7.1C19.37 8.45 20 10.15 20 12c0 4.42-3.58 8-8 8z"></path></g>
15281 <g id="book"><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2 V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z"></path></g>
15282 <g id="bookmark"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2 -2-2z"></path></g>
15283 <g id="bookmark-border"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1 .1-.9-2-2-2zm0 15l-5-2.18L7 18V5h10v13z"></path></g>
15284 <g id="bug-report"><path d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15. 59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.0 4.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33. 09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v 2z"></path></g>
15285 <g id="build"><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1 .4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"></path></g>
15286 <g id="cached"><path d="M19 8l-4 4h3c0 3.31-2.69 6-6 6-1.01 0-1.97-.25-2.8-.7l-1 .46 1.46C8.97 19.54 10.43 20 12 20c4.42 0 8-3.58 8-8h3l-4-4zM6 12c0-3.31 2.69-6 6-6 1.01 0 1.97.25 2.8.7l1.46-1.46C15.03 4.46 13.57 4 12 4c-4.42 0-8 3.58-8 8H1l 4 4 4-4H6z"></path></g>
15287 <g id="camera-enhance"><path d="M9 3L7.17 5H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h1 6c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2h-3.17L15 3H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5 -5 5 2.24 5 5-2.24 5-5 5zm0-1l1.25-2.75L16 13l-2.75-1.25L12 9l-1.25 2.75L8 13l2. 75 1.25z"></path></g>
15288 <g id="cancel"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17. 53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 1 0.59 15.59 7 17 8.41 13.41 12 17 15.59z"></path></g>
15289 <g id="card-giftcard"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3 -1.05 0-1.96.54-2.5 1.35l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c 0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2 -2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c .55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8.62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z"></path></g>
15290 <g id="card-membership"><path d="M20 2H4c-1.11 0-2 .89-2 2v11c0 1.11.89 2 2 2h4v 5l4-2 4 2v-5h4c1.11 0 2-.89 2-2V4c0-1.11-.89-2-2-2zm0 13H4v-2h16v2zm0-5H4V4h16v6 z"></path></g>
15291 <g id="card-travel"><path d="M20 6h-3V4c0-1.11-.89-2-2-2H9c-1.11 0-2 .89-2 2v2H4 c-1.11 0-2 .89-2 2v11c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zM9 4h6v2H9V4zm11 15H4v-2h16v2zm0-5H4V8h3v2h2V8h6v2h2V8h3v6z"></path></g>
15292 <g id="change-history"><path d="M12 7.77L18.39 18H5.61L12 7.77M12 4L2 20h20L12 4 z"></path></g>
15293 <g id="check"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path ></g>
15294 <g id="check-box"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"> </path></g>
15295 <g id="check-box-outline-blank"><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v1 4c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"></path></g>
15296 <g id="check-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10- 10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"></path></g>
15297 <g id="chevron-left"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></p ath></g>
15298 <g id="chevron-right"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z">< /path></g>
15299 <g id="chrome-reader-mode"><path d="M13 12h7v1.5h-7zm0-2.5h7V11h-7zm0 5h7V16h-7z M21 4H3c-1.1 0-2 .9-2 2v13c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 1 5h-9V6h9v13z"></path></g>
15300 <g id="class"><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2- 2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z"></path></g>
15301 <g id="clear"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g>
15302 <g id="close"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g>
15303 <g id="cloud"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05- 4.78-4.65-4.96z"></path></g>
15304 <g id="cloud-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10- 10S17.52 2 12 2zm4.5 14H8c-1.66 0-3-1.34-3-3s1.34-3 3-3l.14.01C8.58 8.28 10.13 7 12 7c2.21 0 4 1.79 4 4h.5c1.38 0 2.5 1.12 2.5 2.5S17.88 16 16.5 16z"></path></g >
15305 <g id="cloud-done"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64- 2.05-4.78-4.65-4.96zM10 17l-3.5-3.5 1.41-1.41L10 14.17 15.18 9l1.41 1.41L10 17z" ></path></g>
15306 <g id="cloud-download"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2 .64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z"></path></g>
15307 <g id="cloud-off"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4c-1.48 0-2.85.43- 4.01 1.17l1.46 1.46C10.21 6.23 11.08 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3 0 1.13-.64 2.11-1.56 2.62l1.45 1.45C23.16 18.16 24 16.68 24 15c0-2.6 4-2.05-4.78-4.65-4.96zM3 5.27l2.75 2.74C2.56 8.15 0 10.77 0 14c0 3.31 2.69 6 6 6 h11.73l2 2L21 20.73 4.27 4 3 5.27zM7.73 10l8 8H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h1 .73z"></path></g>
15308 <g id="cloud-queue"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.6 4 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64 -2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4s1.79-4 4-4h.71C7.37 7.69 9.48 6 12 6c3.04 0 5.5 2.46 5.5 5.5v.5H19c1.66 0 3 1.34 3 3s-1.34 3-3 3z"></path></g>
15309 <g id="cloud-upload"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5. 64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.6 4-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"></path></g>
15310 <g id="code"><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4 .6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"></path></g>
15311 <g id="compare-arrows"><path d="M9.01 14H2v2h7.01v3L13 15l-3.99-4v3zm5.98-1v-3H2 2V8h-7.01V5L11 9l3.99 4z"></path></g>
15312 <g id="content-copy"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0- 2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z">< /path></g>
15313 <g id="content-cut"><path d="M9.64 7.64c.23-.5.36-1.05.36-1.64 0-2.21-1.79-4-4-4 S2 3.79 2 6s1.79 4 4 4c.59 0 1.14-.13 1.64-.36L10 12l-2.36 2.36C7.14 14.13 6.59 14 6 14c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4c0-.59-.13-1.14-.36-1.64L12 14l7 7h3v-1L9.64 7.64zM6 8c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm0 12c-1.1 0 -2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm6-7.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5.5. 22.5.5-.22.5-.5.5zM19 3l-6 6 2 2 7-7V3z"></path></g>
15314 <g id="content-paste"><path d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.8 2 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c .55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"></path> </g>
15315 <g id="copyright"><path d="M10.08 10.86c.05-.33.16-.62.3-.87s.34-.46.59-.62c.24- .15.54-.22.91-.23.23.01.44.05.63.13.2.09.38.21.52.36s.25.33.34.53.13.42.14.64h1. 79c-.02-.47-.11-.9-.28-1.29s-.4-.73-.7-1.01-.66-.5-1.08-.66-.88-.23-1.39-.23c-.6 5 0-1.22.11-1.7.34s-.88.53-1.2.92-.56.84-.71 1.36S8 11.29 8 11.87v.27c0 .58.08 1 .12.23 1.64s.39.97.71 1.35.72.69 1.2.91 1.05.34 1.7.34c.47 0 .91-.08 1.32-.23s.7 7-.36 1.08-.63.56-.58.74-.94.29-.74.3-1.15h-1.79c-.01.21-.06.4-.15.58s-.21.33-.3 6.46-.32.23-.52.3c-.19.07-.39.09-.6.1-.36-.01-.66-.08-.89-.23-.25-.16-.45-.37-.5 9-.62s-.25-.55-.3-.88-.08-.67-.08-1v-.27c0-.35.03-.68.08-1.01zM12 2C6.48 2 2 6.4 8 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"></path></g>
15316 <g id="create"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7. 04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3. 75 1.83-1.83z"></path></g>
15317 <g id="create-new-folder"><path d="M20 6h-8l-2-2H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-1 8h-3v3h-2v-3h-3v-2h3V9 h2v3h3v2z"></path></g>
15318 <g id="credit-card"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2 h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"></path> </g>
15319 <g id="dashboard"><path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6 h8V3h-8z"></path></g>
15320 <g id="date-range"><path d="M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1 V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c 0-1.1-.9-2-2-2zm0 16H5V9h14v11z"></path></g>
15321 <g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l- 1-1h-5l-1 1H5v2h14V4z"></path></g>
15322 <g id="description"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2 H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"></p ath></g>
15323 <g id="dns"><path d="M20 13H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1 -1v-6c0-.55-.45-1-1-1zM7 19c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zM20 3H4c- .55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zM7 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"></path></g>
15324 <g id="done"><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"></path ></g>
15325 <g id="done-all"><path d="M18 7l-1.41-1.41-6.34 6.34 1.41 1.41L18 7zm4.24-1.41L1 1.66 16.17 7.48 12l-1.41 1.41L11.66 19l12-12-1.42-1.41zM.41 13.41L6 19l1.41-1.41 L1.83 12 .41 13.41z"></path></g>
15326 <g id="donut-large"><path d="M11 5.08V2c-5 .5-9 4.81-9 10s4 9.5 9 10v-3.08c-3-.4 8-6-3.4-6-6.92s3-6.44 6-6.92zM18.97 11H22c-.47-5-4-8.53-9-9v3.08C16 5.51 18.54 8 18.97 11zM13 18.92V22c5-.47 8.53-4 9-9h-3.03c-.43 3-2.97 5.49-5.97 5.92z"></pat h></g>
15327 <g id="donut-small"><path d="M11 9.16V2c-5 .5-9 4.79-9 10s4 9.5 9 10v-7.16c-1-.4 1-2-1.52-2-2.84s1-2.43 2-2.84zM14.86 11H22c-.48-4.75-4-8.53-9-9v7.16c1 .3 1.52.9 8 1.86 1.84zM13 14.84V22c5-.47 8.52-4.25 9-9h-7.14c-.34.86-.86 1.54-1.86 1.84z"> </path></g>
15328 <g id="drafts"><path d="M21.99 8c0-.72-.37-1.35-.94-1.7L12 1 2.95 6.3C2.38 6.65 2 7.28 2 8v10c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2l-.01-10zM12 13L3.74 7.84 12 3l8.26 4.84L12 13z"></path></g>
15329 <g id="eject"><path d="M5 17h14v2H5zm7-12L5.33 15h13.34z"></path></g>
15330 <g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.5 2 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></g>
15331 <g id="error-outline"><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58 -8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g>
15332 <g id="event"><path d="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L 3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z" ></path></g>
15333 <g id="event-seat"><path d="M4 18v3h3v-3h10v3h3v-6H4zm15-8h3v3h-3zM2 10h3v3H2zm1 5 3H7V5c0-1.1.9-2 2-2h6c1.1 0 2 .9 2 2v8z"></path></g>
15334 <g id="exit-to-app"><path d="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2 h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14 c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"></path></g>
15335 <g id="expand-less"><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"></p ath></g>
15336 <g id="expand-more"><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"></pat h></g>
15337 <g id="explore"><path d="M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1. 1-.49 1.1-1.1s-.49-1.1-1.1-1.1zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10 -10S17.52 2 12 2zm2.19 12.19L6 18l3.81-8.19L18 6l-3.81 8.19z"></path></g>
15338 <g id="extension"><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 1 0.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.2 1 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.2 1 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z" ></path></g>
15339 <g id="face"><path d="M9 11.75c-.69 0-1.25.56-1.25 1.25s.56 1.25 1.25 1.25 1.25- .56 1.25-1.25-.56-1.25-1.25-1.25zm6 0c-.69 0-1.25.56-1.25 1.25s.56 1.25 1.25 1.2 5 1.25-.56 1.25-1.25-.56-1.25-1.25-1.25zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 1 0-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8 0-.29.02-.58.05-.86 2.36-1.05 4.23-2.98 5.21-5.37C11.07 8.33 14.05 10 17.42 10c.78 0 1.53-.09 2.25-.26.21.71. 33 1.47.33 2.26 0 4.41-3.59 8-8 8z"></path></g>
15340 <g id="favorite"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4. 42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"></path></g>
15341 <g id="favorite-border"><path d="M16.5 3c-1.74 0-3.41.81-4.5 2.09C10.91 3.81 9.2 4 3 7.5 3 4.42 3 2 5.42 2 8.5c0 3.78 3.4 6.86 8.55 11.54L12 21.35l1.45-1.32C18.6 15.36 22 12.28 22 8.5 22 5.42 19.58 3 16.5 3zm-4.4 15.55l-.1.1-.1-.1C7.14 14.24 4 11.39 4 8.5 4 6.5 5.5 5 7.5 5c1.54 0 3.04.99 3.57 2.36h1.87C13.46 5.99 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05z"></path></g>
15342 <g id="feedback"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2- 2V4c0-1.1-.9-2-2-2zm-7 12h-2v-2h2v2zm0-4h-2V6h2v4z"></path></g>
15343 <g id="file-download"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"></path ></g>
15344 <g id="file-upload"><path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"></path></g>
15345 <g id="filter-list"><path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"></p ath></g>
15346 <g id="find-in-page"><path d="M20 19.59V8l-6-6H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1 .89 2 1.99 2H18c.45 0 .85-.15 1.19-.4l-4.43-4.43c-.8.52-1.74.83-2.76.83-2.76 0-5 -2.24-5-5s2.24-5 5-5 5 2.24 5 5c0 1.02-.31 1.96-.83 2.75L20 19.59zM9 13c0 1.66 1 .34 3 3 3s3-1.34 3-3-1.34-3-3-3-3 1.34-3 3z"></path></g>
15347 <g id="find-replace"><path d="M11 6c1.38 0 2.63.56 3.54 1.46L12 10h6V4l-2.05 2.0 5C14.68 4.78 12.93 4 11 4c-3.53 0-6.43 2.61-6.92 6H6.1c.46-2.28 2.48-4 4.9-4zm5. 64 9.14c.66-.9 1.12-1.97 1.28-3.14H15.9c-.46 2.28-2.48 4-4.9 4-1.38 0-2.63-.56-3 .54-1.46L10 12H4v6l2.05-2.05C7.32 17.22 9.07 18 11 18c1.55 0 2.98-.51 4.14-1.36L 20 21.49 21.49 20l-4.85-4.86z"></path></g>
15348 <g id="fingerprint"><path d="M17.81 4.47c-.08 0-.16-.02-.23-.06C15.66 3.42 14 3 12.01 3c-1.98 0-3.86.47-5.57 1.41-.24.13-.54.04-.68-.2-.13-.24-.04-.55.2-.68C7.8 2 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67-.09.18-.26.28-. 44.28zM3.5 9.72c-.1 0-.2-.03-.29-.09-.23-.16-.28-.47-.12-.7.99-1.4 2.25-2.5 3.75 -3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54-.12.7- .23.16-.54.11-.7-.12-.9-1.26-2.04-2.25-3.39-2.94-2.87-1.47-6.54-1.47-9.4.01-1.36 .7-2.5 1.7-3.4 2.96-.08.14-.23.21-.39.21zm6.25 12.07c-.13 0-.26-.05-.35-.15-.87- .87-1.34-1.43-2.01-2.64-.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s 5.66 2.42 5.66 5.39c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-2.42-2.09-4.39-4.66-4.39-2. 57 0-4.66 1.97-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2 .19.51 0 .71-.11.1-.24.15-.37.15zm7.17-1.85c-1.19 0-2.24-.3-3.1-.89-1.49-1.01-2. 38-2.65-2.38-4.39 0-.28.22-.5.5-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54 .71 2.54.71.24 0 .64-.03 1.04-.1.27-.05.53.13.58.41.05.27-.13.53-.41.58-.57.11-1 .07.12-1.21.12zM14.91 22c-.04 0-.09-.01-.13-.02-1.59-.44-2.63-1.03-3.72-2.1-1.4- 1.39-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08-.87 2.08-1.94c0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.44 1.58-6.61 4.03-.39.81-.59 1.76-.59 2.8 0 .78.07 2.01.67 3.61.1.26-.03.55-.29.64 -.26.1-.55-.04-.64-.29-.49-1.31-.73-2.61-.73-3.96 0-1.2.23-2.29.68-3.24 1.33-2.7 9 4.28-4.6 7.51-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94s-3.08- 1.32-3.08-2.94c0-1.07-.93-1.94-2.08-1.94s-2.08.87-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61-.05.23-.26.38-.47.38z"></path>< /g>
15349 <g id="flag"><path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"></path></g>
15350 <g id="flight-land"><path d="M2.5 19h19v2h-19zm7.18-5.73l4.35 1.16 5.31 1.42c.8. 21 1.62-.26 1.84-1.06.21-.8-.26-1.62-1.06-1.84l-5.31-1.42-2.76-9.02L10.12 2v8.28 L5.15 8.95l-.93-2.32-1.45-.39v5.17l1.6.43 5.31 1.43z"></path></g>
15351 <g id="flight-takeoff"><path d="M2.5 19h19v2h-19zm19.57-9.36c-.21-.8-1.04-1.28-1 .84-1.06L14.92 10l-6.9-6.43-1.93.51 4.14 7.17-4.97 1.33-1.97-1.54-1.45.39 1.82 3 .16.77 1.33 1.6-.43 5.31-1.42 4.35-1.16L21 11.49c.81-.23 1.28-1.05 1.07-1.85z">< /path></g>
15352 <g id="flip-to-back"><path d="M9 7H7v2h2V7zm0 4H7v2h2v-2zm0-8c-1.11 0-2 .9-2 2h2 V3zm4 12h-2v2h2v-2zm6-12v2h2c0-1.1-.9-2-2-2zm-6 0h-2v2h2V3zM9 17v-2H7c0 1.1.89 2 2 2zm10-4h2v-2h-2v2zm0-4h2V7h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zM5 7H3v12c0 1.1.89 2 2 2h12v-2H5V7zm10-2h2V3h-2v2zm0 12h2v-2h-2v2z"></path></g>
15353 <g id="flip-to-front"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm2 4v-2H3c0 1.1.89 2 2 2zM3 9h2V7H3v2zm12 12h2v-2h-2v2zm4-18H9c-1.11 0-2 .9-2 2v10c0 1.1.89 2 2 2h10 c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12H9V5h10v10zm-8 6h2v-2h-2v2zm-4 0h2v-2H7v2z "></path></g>
15354 <g id="folder"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path></g>
15355 <g id="folder-open"><path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z"></path></g>
15356 <g id="folder-shared"><path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-5 3c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2- 2 .9-2 2-2zm4 8h-8v-1c0-1.33 2.67-2 4-2s4 .67 4 2v1z"></path></g>
15357 <g id="font-download"><path d="M9.93 13.5h4.14L12 7.98zM20 2H4c-1.1 0-2 .9-2 2v1 6c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-4.05 16.5l-1.14-3H9.17l-1.1 2 3H5.96l5.11-13h1.86l5.11 13h-2.09z"></path></g>
15358 <g id="forward"><path d="M12 8V4l8 8-8 8v-4H4V8z"></path></g>
15359 <g id="fullscreen"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v- 5h-2v3zM14 5v2h3v3h2V5h-5z"></path></g>
15360 <g id="fullscreen-exit"><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h 3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"></path></g>
15361 <g id="gavel"><path d="M1 21h12v2H1zM5.245 8.07l2.83-2.827 14.14 14.142-2.828 2. 828zM12.317 1l5.657 5.656-2.83 2.83-5.654-5.66zM3.825 9.485l5.657 5.657-2.828 2. 828-5.657-5.657z"></path></g>
15362 <g id="gesture"><path d="M4.59 6.89c.7-.71 1.4-1.35 1.71-1.22.5.2 0 1.03-.3 1.52 -.25.42-2.86 3.89-2.86 6.31 0 1.28.48 2.34 1.34 2.98.75.56 1.74.73 2.64.46 1.07- .31 1.95-1.4 3.06-2.77 1.21-1.49 2.83-3.44 4.08-3.44 1.63 0 1.65 1.01 1.76 1.79- 3.78.64-5.38 3.67-5.38 5.37 0 1.7 1.44 3.09 3.21 3.09 1.63 0 4.29-1.33 4.69-6.1H 21v-2.5h-2.47c-.15-1.65-1.09-4.2-4.03-4.2-2.25 0-4.18 1.91-4.94 2.84-.58.73-2.06 2.48-2.29 2.72-.25.3-.68.84-1.11.84-.45 0-.72-.83-.36-1.92.35-1.09 1.4-2.86 1.8 5-3.52.78-1.14 1.3-1.92 1.3-3.28C8.95 3.69 7.31 3 6.44 3 5.12 3 3.97 4 3.72 4.25 c-.36.36-.66.66-.88.93l1.75 1.71zm9.29 11.66c-.31 0-.74-.26-.74-.72 0-.6.73-2.2 2.87-2.76-.3 2.69-1.43 3.48-2.13 3.48z"></path></g>
15363 <g id="get-app"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"></path></g>
15364 <g id="gif"><path d="M11.5 9H13v6h-1.5zM9 9H6c-.6 0-1 .5-1 1v4c0 .5.4 1 1 1h3c.6 0 1-.5 1-1v-2H8.5v1.5h-2v-3H10V10c0-.5-.4-1-1-1zm10 1.5V9h-4.5v6H16v-2h2v-1.5h- 2v-1z"></path></g>
15365 <g id="grade"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path></g>
15366 <g id="group-work"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10 S17.52 2 12 2zM8 17.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5 -1.12 2.5-2.5 2.5zM9.5 8c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5-1.12 2.5-2.5 2 .5S9.5 9.38 9.5 8zm6.5 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2. 5 2.5-1.12 2.5-2.5 2.5z"></path></g>
15367 <g id="help"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1. 45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2 .21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"></path></g>
15368 <g id="help-outline"><path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8- 3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0- 2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"></path></g>
15369 <g id="highlight-off"><path d="M14.59 8L12 10.59 9.41 8 8 9.41 10.59 12 8 14.59 9.41 16 12 13.41 14.59 16 16 14.59 13.41 12 16 9.41 14.59 8zM12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8- 8 8 3.59 8 8-3.59 8-8 8z"></path></g>
15370 <g id="history"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.8 7 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19 .99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2 .08V8H12z"></path></g>
15371 <g id="home"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"></path></g>
15372 <g id="hourglass-empty"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5. 99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6zm10 14.5V20H8v-3.5l4-4 4 4zm-4-5l-4-4V4 h8v3.5l-4 4z"></path></g>
15373 <g id="hourglass-full"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.9 9h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6z"></path></g>
15374 <g id="http"><path d="M4.5 11h-2V9H1v6h1.5v-2.5h2V15H6V9H4.5v2zm2.5-.5h1.5V15H10 v-4.5h1.5V9H7v1.5zm5.5 0H14V15h1.5v-4.5H17V9h-4.5v1.5zm9-1.5H18v6h1.5v-2h2c.8 0 1.5-.7 1.5-1.5v-1c0-.8-.7-1.5-1.5-1.5zm0 2.5h-2v-1h2v1z"></path></g>
15375 <g id="https"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9 -2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3. 1 3.1v2z"></path></g>
15376 <g id="important-devices"><path d="M23 11.01L18 11c-.55 0-1 .45-1 1v9c0 .55.45 1 1 1h5c.55 0 1-.45 1-1v-9c0-.55-.45-.99-1-.99zM23 20h-5v-7h5v7zM20 2H2C.89 2 0 2 .89 0 4v12c0 1.1.89 2 2 2h7v2H7v2h8v-2h-2v-2h2v-2H2V4h18v5h2V4c0-1.11-.9-2-2-2zm -8.03 7L11 6l-.97 3H7l2.47 1.76-.94 2.91 2.47-1.8 2.47 1.8-.94-2.91L15 9h-3.03z" ></path></g>
15377 <g id="inbox"><path d="M19 3H4.99c-1.11 0-1.98.89-1.98 2L3 19c0 1.1.88 2 1.99 2H 19c1.1 0 2-.9 2-2V5c0-1.11-.9-2-2-2zm0 12h-4c0 1.66-1.35 3-3 3s-3-1.34-3-3H4.99V 5H19v10z"></path></g>
15378 <g id="indeterminate-check-box"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10H7v-2h10v2z"></path></g>
15379 <g id="info"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"></path></g>
15380 <g id="info-outline"><path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8- 3.59 8-8 8zM11 9h2V7h-2v2z"></path></g>
15381 <g id="input"><path d="M21 3.01H3c-1.1 0-2 .9-2 2V9h2V4.99h18v14.03H3V15H1v4.01c 0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98v-14c0-1.11-.9-2-2-2zM11 16l4-4-4-4v3H1 v2h10v3z"></path></g>
15382 <g id="invert-colors"><path d="M17.66 7.93L12 2.27 6.34 7.93c-3.12 3.12-3.12 8.1 9 0 11.31C7.9 20.8 9.95 21.58 12 21.58c2.05 0 4.1-.78 5.66-2.34 3.12-3.12 3.12-8 .19 0-11.31zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59s.62-3 .11 1.76-4.24L12 5.1v14.49z"></path></g>
15383 <g id="label"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"></p ath></g>
15384 <g id="label-outline"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5. 01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6. 16zM16 17H5V7h11l3.55 5L16 17z"></path></g>
15385 <g id="language"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 2 2 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2. 76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32- .14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3. 37-1.9-4.33-3.56zm2.95-8H5.08c.96-1.66 2.49-2.93 4.33-3.56C8.81 5.55 8.35 6.75 8 .03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96z M14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.4 9 2.93-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64 .26 1.31.26 2s-.1 1.36-.26 2h-3.38z"></path></g>
15386 <g id="launch"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1 .1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></pa th></g>
15387 <g id="lightbulb-outline"><path d="M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1 zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2. 3l-.85-.6C7.8 12.16 7 10.63 7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z"></path></g>
15388 <g id="line-style"><path d="M3 16h5v-2H3v2zm6.5 0h5v-2h-5v2zm6.5 0h5v-2h-5v2zM3 20h2v-2H3v2zm4 0h2v-2H7v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zM3 12h8v- 2H3v2zm10 0h8v-2h-8v2zM3 4v4h18V4H3z"></path></g>
15389 <g id="line-weight"><path d="M3 17h18v-2H3v2zm0 3h18v-1H3v1zm0-7h18v-3H3v3zm0-9v 4h18V4H3z"></path></g>
15390 <g id="link"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2 .24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></pat h></g>
15391 <g id="list"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm 0 4h14v-2H7v2zM7 7v2h14V7H7z"></path></g>
15392 <g id="lock"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9- 2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"></path></g>
15393 <g id="lock-open"><path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6- 9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6h1.9c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2 zm0 12H6V10h12v10z"></path></g>
15394 <g id="lock-outline"><path d="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z m6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1 .1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM8.9 6c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1v 2H8.9V6zM18 20H6V10h12v10z"></path></g>
15395 <g id="loyalty"><path d="M21.41 11.58l-9-9C12.05 2.22 11.55 2 11 2H4c-1.1 0-2 .9 -2 2v7c0 .55.22 1.05.59 1.42l9 9c.36.36.86.58 1.41.58.55 0 1.05-.22 1.41-.59l7-7 c.37-.36.59-.86.59-1.41 0-.55-.23-1.06-.59-1.42zM5.5 7C4.67 7 4 6.33 4 5.5S4.67 4 5.5 4 7 4.67 7 5.5 6.33 7 5.5 7zm11.77 8.27L13 19.54l-4.27-4.27C8.28 14.81 8 1 4.19 8 13.5c0-1.38 1.12-2.5 2.5-2.5.69 0 1.32.28 1.77.74l.73.72.73-.73c.45-.45 1 .08-.73 1.77-.73 1.38 0 2.5 1.12 2.5 2.5 0 .69-.28 1.32-.73 1.77z"></path></g>
15396 <g id="mail"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2 -.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"></path></g>
15397 <g id="markunread"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1 .1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"></path></g>
15398 <g id="markunread-mailbox"><path d="M20 6H10v6H8V4h6V0H6v6H4c-1.1 0-2 .9-2 2v12c 0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2z"></path></g>
15399 <g id="menu"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></g>
15400 <g id="more-horiz"><path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-. 9 2-2-.9-2-2-2z"></path></g>
15401 <g id="more-vert"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2 c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2 -2-.9-2-2-2z"></path></g>
15402 <g id="motorcycle"><path d="M19.44 9.03L15.41 5H11v2h3.59l2 2H5c-2.8 0-5 2.2-5 5 s2.2 5 5 5c2.46 0 4.45-1.69 4.9-4h1.65l2.77-2.77c-.21.54-.32 1.14-.32 1.77 0 2.8 2.2 5 5 5s5-2.2 5-5c0-2.65-1.97-4.77-4.56-4.97zM7.82 15C7.4 16.15 6.28 17 5 17c -1.63 0-3-1.37-3-3s1.37-3 3-3c1.28 0 2.4.85 2.82 2H5v2h2.82zM19 17c-1.66 0-3-1.3 4-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3z"></path></g>
15403 <g id="move-to-inbox"><path d="M19 3H4.99c-1.11 0-1.98.9-1.98 2L3 19c0 1.1.88 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12h-4c0 1.66-1.35 3-3 3s-3-1.34-3-3 H4.99V5H19v10zm-3-5h-2V7h-4v3H8l4 4 4-4z"></path></g>
15404 <g id="next-week"><path d="M20 7h-4V5c0-.55-.22-1.05-.59-1.41C15.05 3.22 14.55 3 14 3h-4c-1.1 0-2 .9-2 2v2H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V 9c0-1.1-.9-2-2-2zM10 5h4v2h-4V5zm1 13.5l-1-1 3-3-3-3 1-1 4 4-4 4z"></path></g>
15405 <g id="note-add"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18 c1.1 0 2-.9 2-2V8l-6-6zm2 14h-3v3h-2v-3H8v-2h3v-3h2v3h3v2zm-3-7V3.5L18.5 9H13z"> </path></g>
15406 <g id="offline-pin"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17 .5 2 12 2zm5 16H7v-2h10v2zm-6.7-4L7 10.7l1.4-1.4 1.9 1.9 5.3-5.3L17 7.3 10.3 14z "></path></g>
15407 <g id="opacity"><path d="M17.66 8L12 2.35 6.34 8C4.78 9.56 4 11.64 4 13.64s.78 4 .11 2.34 5.67 3.61 2.35 5.66 2.35 4.1-.79 5.66-2.35S20 15.64 20 13.64 19.22 9.56 17.66 8zM6 14c.01-2 .62-3.27 1.76-4.4L12 5.27l4.24 4.38C17.38 10.77 17.99 12 18 14H6z"></path></g>
15408 <g id="open-in-browser"><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h4v-2 H5V8h14v10h-4v2h4c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm-7 6l-4 4h3v6h2v-6h3l-4-4z"> </path></g>
15409 <g id="open-in-new"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2 h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z" ></path></g>
15410 <g id="open-with"><path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm 14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"></path></g>
15411 <g id="pageview"><path d="M11.5 9C10.12 9 9 10.12 9 11.5s1.12 2.5 2.5 2.5 2.5-1. 12 2.5-2.5S12.88 9 11.5 9zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-3.21 14.21l-2.91-2.91c-.69.44-1.51.7-2.39.7C9.01 16 7 13 .99 7 11.5S9.01 7 11.5 7 16 9.01 16 11.5c0 .88-.26 1.69-.7 2.39l2.91 2.9-1.42 1. 42z"></path></g>
15412 <g id="pan-tool"><path d="M23 5.5V20c0 2.2-1.8 4-4 4h-7.3c-1.08 0-2.1-.43-2.85-1 .19L1 14.83s1.26-1.23 1.3-1.25c.22-.19.49-.29.79-.29.22 0 .42.06.6.16.04.01 4.31 2.46 4.31 2.46V4c0-.83.67-1.5 1.5-1.5S11 3.17 11 4v7h1V1.5c0-.83.67-1.5 1.5-1.5 S15 .67 15 1.5V11h1V2.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V11h1V5.5c0-.83.67-1. 5 1.5-1.5s1.5.67 1.5 1.5z"></path></g>
15413 <g id="payment"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c 1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"></path></g>
15414 <g id="perm-camera-mic"><path d="M20 5h-3.17L15 3H9L7.17 5H4c-1.1 0-2 .9-2 2v12c 0 1.1.9 2 2 2h7v-2.09c-2.83-.48-5-2.94-5-5.91h2c0 2.21 1.79 4 4 4s4-1.79 4-4h2c0 2.97-2.17 5.43-5 5.91V21h7c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-6 8c0 1.1-.9 2-2 2 s-2-.9-2-2V9c0-1.1.9-2 2-2s2 .9 2 2v4z"></path></g>
15415 <g id="perm-contact-calendar"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 3c1.66 0 3 1.34 3 3s- 1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm6 12H6v-1c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1z"></pa th></g>
15416 <g id="perm-data-setting"><path d="M18.99 11.5c.34 0 .67.03 1 .07L20 0 0 20h11.5 6c-.04-.33-.07-.66-.07-1 0-4.14 3.36-7.5 7.5-7.5zm3.71 7.99c.02-.16.04-.32.04-.4 9 0-.17-.01-.33-.04-.49l1.06-.83c.09-.08.12-.21.06-.32l-1-1.73c-.06-.11-.19-.15- .31-.11l-1.24.5c-.26-.2-.54-.37-.85-.49l-.19-1.32c-.01-.12-.12-.21-.24-.21h-2c-. 12 0-.23.09-.25.21l-.19 1.32c-.3.13-.59.29-.85.49l-1.24-.5c-.11-.04-.24 0-.31.11 l-1 1.73c-.06.11-.04.24.06.32l1.06.83c-.02.16-.03.32-.03.49 0 .17.01.33.03.49l-1 .06.83c-.09.08-.12.21-.06.32l1 1.73c.06.11.19.15.31.11l1.24-.5c.26.2.54.37.85.49 l.19 1.32c.02.12.12.21.25.21h2c.12 0 .23-.09.25-.21l.19-1.32c.3-.13.59-.29.84-.4 9l1.25.5c.11.04.24 0 .31-.11l1-1.73c.06-.11.03-.24-.06-.32l-1.07-.83zm-3.71 1.01 c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"></path> </g>
15417 <g id="perm-device-information"><path d="M13 7h-2v2h2V7zm0 4h-2v6h2v-6zm4-9.99L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"></path></g>
15418 <g id="perm-identity"><path d="M12 5.9c1.16 0 2.1.94 2.1 2.1s-.94 2.1-2.1 2.1S9. 9 9.16 9.9 8s.94-2.1 2.1-2.1m0 9c2.97 0 6.1 1.46 6.1 2.1v1.1H5.9V17c0-.64 3.13-2 .1 6.1-2.1M12 4C9.79 4 8 5.79 8 8s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 9c-2.67 0- 8 1.34-8 4v3h16v-3c0-2.66-5.33-4-8-4z"></path></g>
15419 <g id="perm-media"><path d="M2 6H0v5h.01L0 20c0 1.1.9 2 2 2h18v-2H2V6zm20-2h-8l- 2-2H6c-1.1 0-1.99.9-1.99 2L4 16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2 zM7 15l4.5-6 3.5 4.51 2.5-3.01L21 15H7z"></path></g>
15420 <g id="perm-phone-msg"><path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.0 3-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.58l2.2-2.21c.28-.27.36-.66.25-1.0 1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 1 7 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM12 3v10l3-3h6V3h-9z"></path></g>
15421 <g id="perm-scan-wifi"><path d="M12 3C6.95 3 3.15 4.85 0 7.23L12 22 24 7.25C20.8 5 4.87 17.05 3 12 3zm1 13h-2v-6h2v6zm-2-8V6h2v2h-2z"></path></g>
15422 <g id="pets"><circle cx="4.5" cy="9.5" r="2.5"></circle><circle cx="9" cy="5.5" r="2.5"></circle><circle cx="15" cy="5.5" r="2.5"></circle><circle cx="19.5" cy= "9.5" r="2.5"></circle><path d="M17.34 14.86c-.87-1.02-1.6-1.89-2.48-2.91-.46-.5 4-1.05-1.08-1.75-1.32-.11-.04-.22-.07-.33-.09-.25-.04-.52-.04-.78-.04s-.53 0-.79 .05c-.11.02-.22.05-.33.09-.7.24-1.28.78-1.75 1.32-.87 1.02-1.6 1.89-2.48 2.91-1. 31 1.31-2.92 2.76-2.62 4.79.29 1.02 1.02 2.03 2.33 2.32.73.15 3.06-.44 5.54-.44h .18c2.48 0 4.81.58 5.54.44 1.31-.29 2.04-1.31 2.33-2.32.31-2.04-1.3-3.49-2.61-4. 8z"></path></g>
15423 <g id="picture-in-picture"><path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1 .1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98V5c0-1.1-.9-2-2-2zm0 16.01H3V4.98h18v14.03 z"></path></g>
15424 <g id="picture-in-picture-alt"><path d="M19 11h-8v6h8v-6zm4 8V4.98C23 3.88 22.1 3 21 3H3c-1.1 0-2 .88-2 1.98V19c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2zm-2 .02H3V4.97h1 8v14.05z"></path></g>
15425 <g id="play-for-work"><path d="M11 5v5.59H7.5l4.5 4.5 4.5-4.5H13V5h-2zm-5 9c0 3. 31 2.69 6 6 6s6-2.69 6-6h-2c0 2.21-1.79 4-4 4s-4-1.79-4-4H6z"></path></g>
15426 <g id="polymer"><path d="M19 4h-4L7.11 16.63 4.5 12 9 4H5L.5 12 5 20h4l7.89-12.6 3L19.5 12 15 20h4l4.5-8z"></path></g>
15427 <g id="power-settings-new"><path d="M13 3h-2v10h2V3zm4.83 2.17l-1.42 1.42C17.99 7.86 19 9.81 19 12c0 3.87-3.13 7-7 7s-7-3.13-7-7c0-2.19 1.01-4.14 2.58-5.42L6.17 5.17C4.23 6.82 3 9.26 3 12c0 4.97 4.03 9 9 9s9-4.03 9-9c0-2.74-1.23-5.18-3.17-6 .83z"></path></g>
15428 <g id="pregnant-woman"><path d="M9 4c0-1.11.89-2 2-2s2 .89 2 2-.89 2-2 2-2-.89-2 -2zm7 9c-.01-1.34-.83-2.51-2-3 0-1.66-1.34-3-3-3s-3 1.34-3 3v7h2v5h3v-5h3v-4z">< /path></g>
15429 <g id="print"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3 -3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6 v4h12V3z"></path></g>
15430 <g id="query-builder"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g>
15431 <g id="question-answer"><path d="M21 6h-2v9H6v2c0 .55.45 1 1 1h11l4 4V7c0-.55-.4 5-1-1-1zm-4 6V3c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v14l4-4h10c.55 0 1-.45 1-1z">< /path></g>
15432 <g id="radio-button-checked"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2 zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g>
15433 <g id="radio-button-unchecked"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 1 0-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8- 8 8z"></path></g>
15434 <g id="receipt"><path d="M18 17H6v-2h12v2zm0-4H6v-2h12v2zm0-4H6V7h12v2zM3 22l1.5 -1.5L6 22l1.5-1.5L9 22l1.5-1.5L12 22l1.5-1.5L15 22l1.5-1.5L18 22l1.5-1.5L21 22V2 l-1.5 1.5L18 2l-1.5 1.5L15 2l-1.5 1.5L12 2l-1.5 1.5L9 2 7.5 3.5 6 2 4.5 3.5 3 2v 20z"></path></g>
15435 <g id="record-voice-over"><circle cx="9" cy="9" r="4"></circle><path d="M9 15c-2 .67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4zm7.76-9.64l-1.68 1.69c.84 1.18.84 2.7 1 0 3.89l1.68 1.69c2.02-2.02 2.02-5.07 0-7.27zM20.07 2l-1.63 1.63c2.77 3.02 2.77 7.56 0 10.74L20.07 16c3.9-3.89 3.91-9.95 0-14z"></path></g>
15436 <g id="redeem"><path d="M20 6h-2.18c.11-.31.18-.65.18-1 0-1.66-1.34-3-3-3-1.05 0 -1.96.54-2.5 1.35l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.0 7.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0- 1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm11 15H4v-2h16v2zm0-5H4V8h5.08L7 10.83 8 .62 12 11 8.76l1-1.36 1 1.36L15.38 12 17 10.83 14.92 8H20v6z"></path></g>
15437 <g id="redo"><path d="M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.9 6 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z"></path></g>
15438 <g id="refresh"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.9 9 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6 -2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"></path></g>
15439 <g id="remove"><path d="M19 13H5v-2h14v2z"></path></g>
15440 <g id="remove-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10 -10S17.52 2 12 2zm5 11H7v-2h10v2z"></path></g>
15441 <g id="remove-circle-outline"><path d="M7 11v2h10v-2H7zm5-9C6.48 2 2 6.48 2 12s4 .48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3. 59 8 8-3.59 8-8 8z"></path></g>
15442 <g id="reorder"><path d="M3 15h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V9H3v2zm0-6v2h18V 5H3z"></path></g>
15443 <g id="reply"><path d="M10 9V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z" ></path></g>
15444 <g id="reply-all"><path d="M7 8V5l-7 7 7 7v-3l-4-4 4-4zm6 1V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z"></path></g>
15445 <g id="report"><path d="M15.73 3H8.27L3 8.27v7.46L8.27 21h7.46L21 15.73V8.27L15. 73 3zM12 17.3c-.72 0-1.3-.58-1.3-1.3 0-.72.58-1.3 1.3-1.3.72 0 1.3.58 1.3 1.3 0 .72-.58 1.3-1.3 1.3zm1-4.3h-2V7h2v6z"></path></g>
15446 <g id="report-problem"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v 4z"></path></g>
15447 <g id="restore"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.8 7 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19 .99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2 .08V8H12z"></path></g>
15448 <g id="room"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.8 7-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1 .12 2.5-2.5 2.5z"></path></g>
15449 <g id="rounded-corner"><path d="M19 19h2v2h-2v-2zm0-2h2v-2h-2v2zM3 13h2v-2H3v2zm 0 4h2v-2H3v2zm0-8h2V7H3v2zm0-4h2V3H3v2zm4 0h2V3H7v2zm8 16h2v-2h-2v2zm-4 0h2v-2h- 2v2zm4 0h2v-2h-2v2zm-8 0h2v-2H7v2zm-4 0h2v-2H3v2zM21 8c0-2.76-2.24-5-5-5h-5v2h5c 1.65 0 3 1.35 3 3v5h2V8z"></path></g>
15450 <g id="rowing"><path d="M8.5 14.5L4 19l1.5 1.5L9 17h2l-2.5-2.5zM15 1c-1.1 0-2 .9 -2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 20.01L18 24l-2.99-3.01V19.5l-7.1-7.09c-.31.05 -.61.07-.91.07v-2.16c1.66.03 3.61-.87 4.67-2.04l1.4-1.55c.19-.21.43-.38.69-.5.29 -.14.62-.23.96-.23h.03C15.99 6.01 17 7.02 17 8.26v5.75c0 .84-.35 1.61-.92 2.16l- 3.58-3.58v-2.27c-.63.52-1.43 1.02-2.29 1.39L16.5 18H18l3 3.01z"></path></g>
15451 <g id="save"><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2 -2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h1 0v4z"></path></g>
15452 <g id="schedule"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 2 2 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3. 58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g>
15453 <g id="search"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5. 91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.7 9l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9. 5 11.99 14 9.5 14z"></path></g>
15454 <g id="select-all"><path d="M3 5h2V3c-1.1 0-2 .9-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2 zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2c0-1.1-.9-2-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm- 2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v 2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2zM7 17h10V7H7v10zm 2-8h6v6H9V9z"></path></g>
15455 <g id="send"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"></path></g>
15456 <g id="settings"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2. 11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1. 08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2 .65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49 .12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.1 2.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42 .49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.4 9 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3 .5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"></path></g>
15457 <g id="settings-applications"><path d="M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2- .9-2-2-2zm7-7H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.8 9-2-2-2zm-1.75 9c0 .23-.02.46-.05.68l1.48 1.16c.13.11.17.3.08.45l-1.4 2.42c-.09. 15-.27.21-.43.15l-1.74-.7c-.36.28-.76.51-1.18.69l-.26 1.85c-.03.17-.18.3-.35.3h- 2.8c-.17 0-.32-.13-.35-.29l-.26-1.85c-.43-.18-.82-.41-1.18-.69l-1.74.7c-.16.06-. 34 0-.43-.15l-1.4-2.42c-.09-.15-.05-.34.08-.45l1.48-1.16c-.03-.23-.05-.46-.05-.6 9 0-.23.02-.46.05-.68l-1.48-1.16c-.13-.11-.17-.3-.08-.45l1.4-2.42c.09-.15.27-.21 .43-.15l1.74.7c.36-.28.76-.51 1.18-.69l.26-1.85c.03-.17.18-.3.35-.3h2.8c.17 0 .3 2.13.35.29l.26 1.85c.43.18.82.41 1.18.69l1.74-.7c.16-.06.34 0 .43.15l1.4 2.42c.0 9.15.05.34-.08.45l-1.48 1.16c.03.23.05.46.05.69z"></path></g>
15458 <g id="settings-backup-restore"><path d="M14 12c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2zm-2-9c-4.97 0-9 4.03-9 9H0l4 4 4-4H5c0-3.87 3.13-7 7-7s7 3.13 7 7-3.1 3 7-7 7c-1.51 0-2.91-.49-4.06-1.3l-1.42 1.44C8.04 20.3 9.94 21 12 21c4.97 0 9-4. 03 9-9s-4.03-9-9-9z"></path></g>
15459 <g id="settings-bluetooth"><path d="M11 24h2v-2h-2v2zm-4 0h2v-2H7v2zm8 0h2v-2h-2 v2zm2.71-18.29L12 0h-1v7.59L6.41 3 5 4.41 10.59 10 5 15.59 6.41 17 11 12.41V20h1 l5.71-5.71-4.3-4.29 4.3-4.29zM13 3.83l1.88 1.88L13 7.59V3.83zm1.88 10.46L13 16.1 7v-3.76l1.88 1.88z"></path></g>
15460 <g id="settings-brightness"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18 c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02zM8 16h2.5l1.5 1.5 1.5- 1.5H16v-2.5l1.5-1.5-1.5-1.5V8h-2.5L12 6.5 10.5 8H8v2.5L6.5 12 8 13.5V16zm4-7c1.6 6 0 3 1.34 3 3s-1.34 3-3 3V9z"></path></g>
15461 <g id="settings-cell"><path d="M7 24h2v-2H7v2zm4 0h2v-2h-2v2zm4 0h2v-2h-2v2zM16 .01L8 0C6.9 0 6 .9 6 2v16c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V2c0-1.1-.9-1.99-2-1.99z M16 16H8V4h8v12z"></path></g>
15462 <g id="settings-ethernet"><path d="M7.77 6.76L6.23 5.48.82 12l5.41 6.52 1.54-1.2 8L3.42 12l4.35-5.24zM7 13h2v-2H7v2zm10-2h-2v2h2v-2zm-6 2h2v-2h-2v2zm6.77-7.52l-1 .54 1.28L20.58 12l-4.35 5.24 1.54 1.28L23.18 12l-5.41-6.52z"></path></g>
15463 <g id="settings-input-antenna"><path d="M12 5c-3.87 0-7 3.13-7 7h2c0-2.76 2.24-5 5-5s5 2.24 5 5h2c0-3.87-3.13-7-7-7zm1 9.29c.88-.39 1.5-1.26 1.5-2.29 0-1.38-1.1 2-2.5-2.5-2.5S9.5 10.62 9.5 12c0 1.02.62 1.9 1.5 2.29v3.3L7.59 21 9 22.41l3-3 3 3L16.41 21 13 17.59v-3.3zM12 1C5.93 1 1 5.93 1 12h2c0-4.97 4.03-9 9-9s9 4.03 9 9 h2c0-6.07-4.93-11-11-11z"></path></g>
15464 <g id="settings-input-component"><path d="M5 2c0-.55-.45-1-1-1s-1 .45-1 1v4H1v6h 6V6H5V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2H9v2zm-8 0 c0 1.3.84 2.4 2 2.82V23h2v-4.18C6.16 18.4 7 17.3 7 16v-2H1v2zM21 6V2c0-.55-.45-1 -1-1s-1 .45-1 1v4h-2v6h6V6h-2zm-8-4c0-.55-.45-1-1-1s-1 .45-1 1v4H9v6h6V6h-2V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2z"></path></g>
15465 <g id="settings-input-composite"><path d="M5 2c0-.55-.45-1-1-1s-1 .45-1 1v4H1v6h 6V6H5V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2H9v2zm-8 0 c0 1.3.84 2.4 2 2.82V23h2v-4.18C6.16 18.4 7 17.3 7 16v-2H1v2zM21 6V2c0-.55-.45-1 -1-1s-1 .45-1 1v4h-2v6h6V6h-2zm-8-4c0-.55-.45-1-1-1s-1 .45-1 1v4H9v6h6V6h-2V2zm4 14c0 1.3.84 2.4 2 2.82V23h2v-4.18c1.16-.41 2-1.51 2-2.82v-2h-6v2z"></path></g>
15466 <g id="settings-input-hdmi"><path d="M18 7V4c0-1.1-.9-2-2-2H8c-1.1 0-2 .9-2 2v3H 5v6l3 6v3h8v-3l3-6V7h-1zM8 4h8v3h-2V5h-1v2h-2V5h-1v2H8V4z"></path></g>
15467 <g id="settings-input-svideo"><path d="M8 11.5c0-.83-.67-1.5-1.5-1.5S5 10.67 5 1 1.5 5.67 13 6.5 13 8 12.33 8 11.5zm7-5c0-.83-.67-1.5-1.5-1.5h-3C9.67 5 9 5.67 9 6.5S9.67 8 10.5 8h3c.83 0 1.5-.67 1.5-1.5zM8.5 15c-.83 0-1.5.67-1.5 1.5S7.67 18 8.5 18s1.5-.67 1.5-1.5S9.33 15 8.5 15zM12 1C5.93 1 1 5.93 1 12s4.93 11 11 11 11- 4.93 11-11S18.07 1 12 1zm0 20c-4.96 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9zm5.5-11c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5z m-2 5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5z"></ path></g>
15468 <g id="settings-overscan"><path d="M12.01 5.5L10 8h4l-1.99-2.5zM18 10v4l2.5-1.99 L18 10zM6 10l-2.5 2.01L6 14v-4zm8 6h-4l2.01 2.5L14 16zm7-13H3c-1.1 0-2 .9-2 2v14 c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02z"></p ath></g>
15469 <g id="settings-phone"><path d="M13 9h-2v2h2V9zm4 0h-2v2h2V9zm3 6.5c-1.25 0-2.45 -.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.58l2.2 -2.21c.28-.27.36-.66.25-1.01C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 9v2h2V9h-2 z"></path></g>
15470 <g id="settings-power"><path d="M7 24h2v-2H7v2zm4 0h2v-2h-2v2zm2-22h-2v10h2V2zm3 .56 2.44l-1.45 1.45C16.84 6.94 18 8.83 18 11c0 3.31-2.69 6-6 6s-6-2.69-6-6c0-2.1 7 1.16-4.06 2.88-5.12L7.44 4.44C5.36 5.88 4 8.28 4 11c0 4.42 3.58 8 8 8s8-3.58 8 -8c0-2.72-1.36-5.12-3.44-6.56zM15 24h2v-2h-2v2z"></path></g>
15471 <g id="settings-remote"><path d="M15 9H9c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h6c.5 5 0 1-.45 1-1V10c0-.55-.45-1-1-1zm-3 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zM7.05 6.05l1.41 1.41C9.37 6.56 10.62 6 12 6s2.63.56 3.54 1.46l1.41-1.41C15.68 4.78 13.93 4 12 4s-3.68.78-4.95 2.05zM12 0C8.96 0 6.21 1.23 4.22 3.22l1.41 1.41C 7.26 3.01 9.51 2 12 2s4.74 1.01 6.36 2.64l1.41-1.41C17.79 1.23 15.04 0 12 0z"></ path></g>
15472 <g id="settings-voice"><path d="M7 24h2v-2H7v2zm5-11c1.66 0 2.99-1.34 2.99-3L15 4c0-1.66-1.34-3-3-3S9 2.34 9 4v6c0 1.66 1.34 3 3 3zm-1 11h2v-2h-2v2zm4 0h2v-2h-2 v2zm4-14h-1.7c0 3-2.54 5.1-5.3 5.1S6.7 13 6.7 10H5c0 3.41 2.72 6.23 6 6.72V20h2v -3.28c3.28-.49 6-3.31 6-6.72z"></path></g>
15473 <g id="shop"><path d="M16 6V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H2v13c0 1.1 1.89 2 2 2h16c1.11 0 2-.89 2-2V6h-6zm-6-2h4v2h-4V4zM9 18V9l7.5 4L9 18z"></path>< /g>
15474 <g id="shop-two"><path d="M3 9H1v11c0 1.11.89 2 2 2h14c1.11 0 2-.89 2-2H3V9zm15- 4V3c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H5v11c0 1.11.89 2 2 2h14c1.11 0 2-.89 2-2V5h-5zm-6-2h4v2h-4V3zm0 12V8l5.5 3-5.5 4z"></path></g>
15475 <g id="shopping-basket"><path d="M17.21 9l-4.38-6.56c-.19-.28-.51-.42-.83-.42-.3 2 0-.64.14-.83.43L6.79 9H2c-.55 0-1 .45-1 1 0 .09.01.18.04.27l2.54 9.27c.23.84 1 1.46 1.92 1.46h13c.92 0 1.69-.62 1.93-1.46l2.54-9.27L23 10c0-.55-.45-1-1-1h-4.7 9zM9 9l3-4.4L15 9H9zm3 8c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"></path></g >
15476 <g id="shopping-cart"><path d="M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-. 9-2-2-2zM1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7. 42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49 c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2H1zm16 16c-1.1 0-1.99.9-1.99 2 s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z"></path></g>
15477 <g id="sort"><path d="M3 18h6v-2H3v2zM3 6v2h18V6H3zm0 7h12v-2H3v2z"></path></g>
15478 <g id="speaker-notes"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2- .9 2-2V4c0-1.1-.9-2-2-2zM8 14H6v-2h2v2zm0-3H6V9h2v2zm0-3H6V6h2v2zm7 6h-5v-2h5v2z m3-3h-8V9h8v2zm0-3h-8V6h8v2z"></path></g>
15479 <g id="spellcheck"><path d="M12.45 16h2.09L9.43 3H7.57L2.46 16h2.09l1.12-3h5.64l 1.14 3zm-6.02-5L8.5 5.48 10.57 11H6.43zm15.16.59l-8.09 8.09L9.83 16l-1.41 1.41 5 .09 5.09L23 13l-1.41-1.41z"></path></g>
15480 <g id="star"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path></g>
15481 <g id="star-border"><path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L 5.82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4l-3.76 2.27 1-4.28-3.32-2.8 8 4.38-.38L12 6.1l1.71 4.04 4.38.38-3.32 2.88 1 4.28L12 15.4z"></path></g>
15482 <g id="star-half"><path d="M22 9.24l-7.19-.62L12 2 9.19 8.63 2 9.24l5.46 4.73L5. 82 21 12 17.27 18.18 21l-1.63-7.03L22 9.24zM12 15.4V6.1l1.71 4.04 4.38.38-3.32 2 .88 1 4.28L12 15.4z"></path></g>
15483 <g id="stars"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 1 7.52 22 12S17.52 2 11.99 2zm4.24 16L12 15.45 7.77 18l1.12-4.81-3.73-3.23 4.92-.4 2L12 5l1.92 4.53 4.92.42-3.73 3.23L16.23 18z"></path></g>
15484 <g id="store"><path d="M20 4H4v2h16V4zm1 10v-2l-1-5H4l-1 5v2h1v6h10v-6h4v6h2v-6h 1zm-9 4H6v-4h6v4z"></path></g>
15485 <g id="subdirectory-arrow-left"><path d="M11 9l1.42 1.42L8.83 14H18V4h2v12H8.83l 3.59 3.58L11 21l-6-6 6-6z"></path></g>
15486 <g id="subdirectory-arrow-right"><path d="M19 15l-6 6-1.42-1.42L15.17 16H4V4h2v1 0h9.17l-3.59-3.58L13 9l6 6z"></path></g>
15487 <g id="subject"><path d="M14 17H4v2h10v-2zm6-8H4v2h16V9zM4 15h16v-2H4v2zM4 5v2h1 6V5H4z"></path></g>
15488 <g id="supervisor-account"><path d="M16.5 12c1.38 0 2.49-1.12 2.49-2.5S17.88 7 1 6.5 7C15.12 7 14 8.12 14 9.5s1.12 2.5 2.5 2.5zM9 11c1.66 0 2.99-1.34 2.99-3S10.6 6 5 9 5C7.34 5 6 6.34 6 8s1.34 3 3 3zm7.5 3c-1.83 0-5.5.92-5.5 2.75V19h11v-2.25c 0-1.83-3.67-2.75-5.5-2.75zM9 13c-2.33 0-7 1.17-7 3.5V19h7v-2.25c0-.85.33-2.34 2. 37-3.47C10.5 13.1 9.66 13 9 13z"></path></g>
15489 <g id="swap-horiz"><path d="M6.99 11L3 15l3.99 4v-3H14v-2H6.99v-3zM21 9l-3.99-4v 3H10v2h7.01v3L21 9z"></path></g>
15490 <g id="swap-vert"><path d="M16 17.01V10h-2v7.01h-3L15 21l4-3.99h-3zM9 3L5 6.99h3 V14h2V6.99h3L9 3z"></path></g>
15491 <g id="swap-vertical-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10- 4.48 10-10S17.52 2 12 2zM6.5 9L10 5.5 13.5 9H11v4H9V9H6.5zm11 6L14 18.5 10.5 15H 13v-4h2v4h2.5z"></path></g>
15492 <g id="system-update-alt"><path d="M12 16.5l4-4h-3v-9h-2v9H8l4 4zm9-13h-6v1.99h6 v14.03H3V5.49h6V3.5H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-14c0-1 .1-.9-2-2-2z"></path></g>
15493 <g id="tab"><path d="M21 3H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V 5c0-1.1-.9-2-2-2zm0 16H3V5h10v4h8v10z"></path></g>
15494 <g id="tab-unselected"><path d="M1 9h2V7H1v2zm0 4h2v-2H1v2zm0-8h2V3c-1.1 0-2 .9- 2 2zm8 16h2v-2H9v2zm-8-4h2v-2H1v2zm2 4v-2H1c0 1.1.9 2 2 2zM21 3h-8v6h10V5c0-1.1- .9-2-2-2zm0 14h2v-2h-2v2zM9 5h2V3H9v2zM5 21h2v-2H5v2zM5 5h2V3H5v2zm16 16c1.1 0 2 -.9 2-2h-2v2zm0-8h2v-2h-2v2zm-8 8h2v-2h-2v2zm4 0h2v-2h-2v2z"></path></g>
15495 <g id="text-format"><path d="M5 17v2h14v-2H5zm4.5-4.2h5l.9 2.2h2.1L12.75 4h-1.5L 6.5 15h2.1l.9-2.2zM12 5.98L13.87 11h-3.74L12 5.98z"></path></g>
15496 <g id="theaters"><path d="M18 3v2h-2V3H8v2H6V3H4v18h2v-2h2v2h8v-2h2v2h2V3h-2zM8 17H6v-2h2v2zm0-4H6v-2h2v2zm0-4H6V7h2v2zm10 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2V7h 2v2z"></path></g>
15497 <g id="thumb-down"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-. 14.47-.14.73v1.91l.01.01L1 14c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z" ></path></g>
15498 <g id="thumb-up"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03 -.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1.91l-.01-.01L23 10z"></path></g>
15499 <g id="thumbs-up-down"><path d="M12 6c0-.55-.45-1-1-1H5.82l.66-3.18.02-.23c0-.31 -.13-.59-.33-.8L5.38 0 .44 4.94C.17 5.21 0 5.59 0 6v6.5c0 .83.67 1.5 1.5 1.5h6.7 5c.62 0 1.15-.38 1.38-.91l2.26-5.29c.07-.17.11-.36.11-.55V6zm10.5 4h-6.75c-.62 0 -1.15.38-1.38.91l-2.26 5.29c-.07.17-.11.36-.11.55V18c0 .55.45 1 1 1h5.18l-.66 3. 18-.02.24c0 .31.13.59.33.8l.79.78 4.94-4.94c.27-.27.44-.65.44-1.06v-6.5c0-.83-.6 7-1.5-1.5-1.5z"></path></g>
15500 <g id="timeline"><path d="M23 8c0 1.1-.9 2-2 2-.18 0-.35-.02-.51-.07l-3.56 3.55c .05.16.07.34.07.52 0 1.1-.9 2-2 2s-2-.9-2-2c0-.18.02-.36.07-.52l-2.55-2.55c-.16. 05-.34.07-.52.07s-.36-.02-.52-.07l-4.55 4.56c.05.16.07.33.07.51 0 1.1-.9 2-2 2s- 2-.9-2-2 .9-2 2-2c.18 0 .35.02.51.07l4.56-4.55C8.02 9.36 8 9.18 8 9c0-1.1.9-2 2- 2s2 .9 2 2c0 .18-.02.36-.07.52l2.55 2.55c.16-.05.34-.07.52-.07s.36.02.52.07l3.55 -3.56C19.02 8.35 19 8.18 19 8c0-1.1.9-2 2-2s2 .9 2 2z"></path></g>
15501 <g id="toc"><path d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2 zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z"></path></g>
15502 <g id="today"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1. 1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"></pa th></g>
15503 <g id="toll"><path d="M15 4c-4.42 0-8 3.58-8 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8z m0 14c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zM3 12c0-2.61 1.67-4.83 4-5.65V4.26C3.55 5.15 1 8.27 1 12s2.55 6.85 6 7.74v-2.09c-2.33-.82-4-3.04-4-5.6 5z"></path></g>
15504 <g id="touch-app"><path d="M9 11.24V7.5C9 6.12 10.12 5 11.5 5S14 6.12 14 7.5v3.7 4c1.21-.81 2-2.18 2-3.74C16 5.01 13.99 3 11.5 3S7 5.01 7 7.5c0 1.56.79 2.93 2 3. 74zm9.84 4.63l-4.54-2.26c-.17-.07-.35-.11-.54-.11H13v-6c0-.83-.67-1.5-1.5-1.5S10 6.67 10 7.5v10.74l-3.43-.72c-.08-.01-.15-.03-.24-.03-.31 0-.59.13-.79.33l-.79.8 4.94 4.94c.27.27.65.44 1.06.44h6.79c.75 0 1.33-.55 1.44-1.28l.75-5.27c.01-.07.0 2-.14.02-.2 0-.62-.38-1.16-.91-1.38z"></path></g>
15505 <g id="track-changes"><path d="M19.07 4.93l-1.41 1.41C19.1 7.79 20 9.79 20 12c0 4.42-3.58 8-8 8s-8-3.58-8-8c0-4.08 3.05-7.44 7-7.93v2.02C8.16 6.57 6 9.03 6 12c0 3.31 2.69 6 6 6s6-2.69 6-6c0-1.66-.67-3.16-1.76-4.24l-1.41 1.41C15.55 9.9 16 10 .9 16 12c0 2.21-1.79 4-4 4s-4-1.79-4-4c0-1.86 1.28-3.41 3-3.86v2.14c-.6.35-1 .98 -1 1.72 0 1.1.9 2 2 2s2-.9 2-2c0-.74-.4-1.38-1-1.72V2h-1C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10c0-2.76-1.12-5.26-2.93-7.07z"></path></g>
15506 <g id="translate"><path d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3. 71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9 .19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04 zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3. 24z"></path></g>
15507 <g id="trending-down"><path d="M16 18l2.29-2.29-4.88-4.88-4 4L2 7.41 3.41 6l6 6 4-4 6.3 6.29L22 12v6z"></path></g>
15508 <g id="trending-flat"><path d="M22 12l-4-4v3H3v2h15v3z"></path></g>
15509 <g id="trending-up"><path d="M16 6l2.29 2.29-4.88 4.88-4-4L2 16.59 3.41 18l6-6 4 4 6.3-6.29L22 12V6z"></path></g>
15510 <g id="turned-in"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9- 2-2-2z"></path></g>
15511 <g id="turned-in-not"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1 -.9-2-2-2zm0 15l-5-2.18L7 18V5h10v13z"></path></g>
15512 <g id="unarchive"><path d="M20.55 5.22l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.15.55L3.46 5.22C3.17 5.57 3 6.01 3 6.5V19c0 1.1.89 2 2 2h14c1.1 0 2- .9 2-2V6.5c0-.49-.17-.93-.45-1.28zM12 9.5l5.5 5.5H14v2h-4v-2H6.5L12 9.5zM5.12 5l .82-1h12l.93 1H5.12z"></path></g>
15513 <g id="undo"><path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1. 16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12. 5 8z"></path></g>
15514 <g id="unfold-less"><path d="M7.41 18.59L8.83 20 12 16.83 15.17 20l1.41-1.41L12 14l-4.59 4.59zm9.18-13.18L15.17 4 12 7.17 8.83 4 7.41 5.41 12 10l4.59-4.59z"></p ath></g>
15515 <g id="unfold-more"><path d="M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z"></path></g >
15516 <g id="update"><path d="M21 10.12h-6.78l2.74-2.82c-2.73-2.7-7.15-2.8-9.88-.1-2.7 3 2.71-2.73 7.08 0 9.79 2.73 2.71 7.15 2.71 9.88 0C18.32 15.65 19 14.08 19 12.1h 2c0 1.98-.88 4.55-2.64 6.29-3.51 3.48-9.21 3.48-12.72 0-3.5-3.47-3.53-9.11-.02-1 2.58 3.51-3.47 9.14-3.47 12.65 0L21 3v7.12zM12.5 8v4.25l3.5 2.08-.72 1.21L11 13V 8h1.5z"></path></g>
15517 <g id="verified-user"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6. 45 9-12V5l-9-4zm-2 16l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"></path></g>
15518 <g id="view-agenda"><path d="M20 13H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zm0-10H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1z"></path></g>
15519 <g id="view-array"><path d="M4 18h3V5H4v13zM18 5v13h3V5h-3zM8 18h9V5H8v13z"></pa th></g>
15520 <g id="view-carousel"><path d="M7 19h10V4H7v15zm-5-2h4V6H2v11zM18 6v11h4V6h-4z"> </path></g>
15521 <g id="view-column"><path d="M10 18h5V5h-5v13zm-6 0h5V5H4v13zM16 5v13h5V5h-5z">< /path></g>
15522 <g id="view-day"><path d="M2 21h19v-3H2v3zM20 8H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1zM2 3v3h19V3H2z"></path></g>
15523 <g id="view-headline"><path d="M4 15h16v-2H4v2zm0 4h16v-2H4v2zm0-8h16V9H4v2zm0-6 v2h16V5H4z"></path></g>
15524 <g id="view-list"><path d="M4 14h4v-4H4v4zm0 5h4v-4H4v4zM4 9h4V5H4v4zm5 5h12v-4H 9v4zm0 5h12v-4H9v4zM9 5v4h12V5H9z"></path></g>
15525 <g id="view-module"><path d="M4 11h5V5H4v6zm0 7h5v-6H4v6zm6 0h5v-6h-5v6zm6 0h5v- 6h-5v6zm-6-7h5V5h-5v6zm6-6v6h5V5h-5z"></path></g>
15526 <g id="view-quilt"><path d="M10 18h5v-6h-5v6zm-6 0h5V5H4v13zm12 0h5v-6h-5v6zM10 5v6h11V5H10z"></path></g>
15527 <g id="view-stream"><path d="M4 18h17v-6H4v6zM4 5v6h17V5H4z"></path></g>
15528 <g id="view-week"><path d="M6 5H3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-. 45 1-1V6c0-.55-.45-1-1-1zm14 0h-3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-. 45 1-1V6c0-.55-.45-1-1-1zm-7 0h-3c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h3c.55 0 1-. 45 1-1V6c0-.55-.45-1-1-1z"></path></g>
15529 <g id="visibility"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s 9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z">< /path></g>
15530 <g id="visibility-off"><path d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l 2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98 .7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3. 27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .4 4-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53- 2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"></path></g>
15531 <g id="warning"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></p ath></g>
15532 <g id="watch-later"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17 .5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z"></path></g>
15533 <g id="weekend"><path d="M21 10c-1.1 0-2 .9-2 2v3H5v-3c0-1.1-.9-2-2-2s-2 .9-2 2v 5c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2v-5c0-1.1-.9-2-2-2zm-3-5H6c-1.1 0-2 .9-2 2v2.15 c1.16.41 2 1.51 2 2.82V14h12v-2.03c0-1.3.84-2.4 2-2.82V7c0-1.1-.9-2-2-2z"></path ></g>
15534 <g id="work"><path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm- 6 0h-4V4h4v2z"></path></g>
15535 <g id="youtube-searched-for"><path d="M17.01 14h-.8l-.27-.27c.98-1.14 1.57-2.61 1.57-4.23 0-3.59-2.91-6.5-6.5-6.5s-6.5 3-6.5 6.5H2l3.84 4 4.16-4H6.51C6.51 7 8.5 3 5 11.01 5s4.5 2.01 4.5 4.5c0 2.48-2.02 4.5-4.5 4.5-.65 0-1.26-.14-1.82-.38L7.7 1 15.1c.97.57 2.09.9 3.3.9 1.61 0 3.08-.59 4.22-1.57l.27.27v.79l5.01 4.99L22 19l -4.99-5z"></path></g>
15536 <g id="zoom-in"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5 .91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v. 79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9 .5 11.99 14 9.5 14zm2.5-4h-2v2H9v-2H7V9h2V7h1v2h2v1z"></path></g>
15537 <g id="zoom-out"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v .79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zM7 9h5v1H7z"></path></g>
15538 </defs></svg>
15539 </iron-iconset-svg>
15540 <dom-module id="sort-toggle" assetpath="/res/imp/common/">
15541 <template>
15542 <style>
15543 :host {
15544 display: inline-block;
15545 position: relative;
15546 min-width:20px;
15547 min-height:16px;
15548 vertical-align: middle;
15549 }
15550 iron-icon {
15551 position: absolute;
15552 left: 0;
15553 cursor: pointer;
15554 }
15555 .hidden {
15556 visibility: hidden;
15557 }
15558 </style>
15559
15560 <span on-click="toggle">
15561 <iron-icon style="top:0" class$="[[_hidden(sort,'1')]]" icon="icons:arrow- drop-down">
15562 </iron-icon>
15563 <iron-icon style="bottom:0" class$="[[_hidden(sort,'-1')]]" icon="icons:ar row-drop-up">
15564 </iron-icon>
15565 </span>
15566
15567 </template>
15568 <script>
15569 Polymer({
15570 is: "sort-toggle",
15571 properties: {
15572 name: {
15573 type: String,
15574 observer: "_resetSort",
15575 },
15576 sort: {
15577 type: Number,
15578 value: 0,
15579 notify: true,
15580 },
15581 },
15582 toggle: function() {
15583 if (this.sort === -1) {
15584 this.set("sort", 0);
15585 } else if (this.sort === 1) {
15586 this.set("sort", -1);
15587 } else {
15588 this.set("sort", 1);
15589 }
15590 this.fire("sort_change", {sort: this.sort, name: this.name});
15591 },
15592 _hidden: function(num, compare) {
15593 // double equals intentionally used here because compare is a string
15594 // and num is an int.
15595 if (num == compare) {
15596 return "hidden";
15597 }
15598 return "";
15599 },
15600 _resetSort: function(newV, old) {
15601 // Because of how Polymer inserts and moves elements around, we need to
15602 // reset the sort value if the name changes so the ascending sort by
15603 // "os" doesn't become the ascending sort by "gpu" if a column gets
15604 // added.
15605 this.set("sort", 0);
15606 this.fire("sort_change", {sort: 0, name: newV});
15607 },
15608 });
15609 </script>
15610 </dom-module><script>
15611
15612 window.SwarmingBehaviors = window.SwarmingBehaviors || {};
15613 (function(){
15614 var ANDROID_ALIASES = {
15615 "bullhead": "Nexus 5X",
15616 "flo": "Nexus 7",
15617 "hammerhead": "Nexus 5",
15618 "mako": "Nexus 4",
15619 "shamu": "Nexus 6",
15620 };
15621 // Taken from http://developer.android.com/reference/android/os/BatteryManag er.html
15622 var BATTERY_HEALTH_UNKNOWN = 1;
15623 var BATTERY_HEALTH_GOOD = 2;
15624 var BATTERY_STATUS_CHARGING = 2;
15625
15626 var UNAUTHENTICATED = "unauthenticated";
15627 var AVAILABLE = "available";
15628
15629 var GPU_ALIASES = {
15630 "1002": "AMD",
15631 "1002:6779": "AMD Radeon HD 6450/7450/8450",
15632 "1002:6821": "AMD Radeon HD 8870M",
15633 "102b": "Matrox",
15634 "102b:0522": "Matrox MGA G200e",
15635 "102b:0532": "Matrox MGA G200eW",
15636 "102b:0534": "Matrox G200eR2",
15637 "10de": "NVIDIA",
15638 "10de:08aa": "NVIDIA GeForce 320M",
15639 "10de:0fe9": "NVIDIA GeForce GT 750M Mac Edition",
15640 "10de:104a": "NVIDIA GeForce GT 610",
15641 "10de:11c0": "NVIDIA GeForce GTX 660",
15642 "10de:1244": "NVIDIA GeForce GTX 550 Ti",
15643 "10de:1401": "NVIDIA GeForce GTX 960",
15644 "8086": "Intel",
15645 "8086:041a": "Intel Xeon Integrated",
15646 "8086:0a2e": "Intel Haswell Integrated",
15647 "8086:0d26": "Intel Crystal Well Integrated",
15648 }
15649
15650 // matches a string like "ALIAS (ORIG)", with ORIG as group 1
15651 var ALIAS_REGEXP = /.+ \((.*)\)/;
15652
15653 // This behavior wraps up all the shared bot-list functionality.
15654 SwarmingBehaviors.BotListBehavior = {
15655
15656 _androidAlias: function(device) {
15657 if (device.notReady) {
15658 return UNAUTHENTICATED.toUpperCase();
15659 }
15660 var t = this._deviceType(device);
15661 var a = ANDROID_ALIASES[t];
15662 if (!a) {
15663 return "UNKNOWN";
15664 }
15665 return a;
15666 },
15667
15668 _applyAlias: function(orig, alias) {
15669 return alias +" ("+orig+")";
15670 },
15671
15672 _cores: function(bot) {
15673 // For whatever reason, sometimes cores are in dimensions and sometimes they are in state, but never both.
15674 var c = (bot && bot.state && bot.state.cores);
15675 if (c && c.length > 0) {
15676 return c;
15677 }
15678 c = this._dimension(bot, "cores") || ["Unknown"];
15679 return c;
15680 },
15681
15682 _devices: function(bot) {
15683 var devices = [];
15684 var d = (bot && bot.state && bot.state.devices) || {};
15685 // state.devices is like {Serial:Object}, so we need to keep the serial
15686 for (key in d) {
15687 var o = d[key];
15688 o.serial = key;
15689 o.okay = (o.state === AVAILABLE);
15690 devices.push(o);
15691 }
15692 return devices;
15693 },
15694
15695 _deviceType: function(device) {
15696 if (!device || !device.build) {
15697 return "unknown";
15698 }
15699 var t = device.build["build.product"] || device.build["product.board"] | |
15700 device.build["product.device"] || "unknown";
15701 return t.toLowerCase();
15702 },
15703
15704 _dimension: function(data, dim) {
15705 if (!data || !data.dimensions || !dim) {
15706 return undefined;
15707 }
15708 for (var i = 0; i<data.dimensions.length; i++) {
15709 if (data.dimensions[i].key === dim) {
15710 return data.dimensions[i].value;
15711 }
15712 }
15713 return undefined;
15714 },
15715
15716 _gpuAlias: function(gpu) {
15717 var a = GPU_ALIASES[gpu];
15718 if (!a) {
15719 return "UNKNOWN";
15720 }
15721 return a;
15722 },
15723
15724 _unalias: function(str) {
15725 var match = ALIAS_REGEXP.exec(str);
15726 if (match) {
15727 return match[1];
15728 }
15729 return str;
15730 },
15731 }
15732 })()
15733 </script>
15734 <dom-module id="bot-list-data" assetpath="/res/imp/botlist/">
15735 <template>
15736 <iron-ajax id="request" url="/_ah/api/swarming/v1/bots/list" headers="[[auth _headers]]" handle-as="json" last-response="{{_data}}" loading="{{busy}}">
15737 </iron-ajax>
15738 </template>
15739 <script>
15740 (function(){
15741 var DIMENSIONS = ["cores", "cpu", "id", "os", "pool"];
15742 // "gpu" and "devices" are added separately because we need to
15743 // deal with aliases.
15744 var BOT_PROPERTIES = ["gpu", "devices", "task", "status"];
15745 Polymer({
15746 is: 'bot-list-data',
15747 properties: {
15748 auth_headers: {
15749 type: Object,
15750 observer: "signIn",
15751 },
15752
15753 bots: {
15754 type: Array,
15755 computed: "_bots(_data)",
15756 notify: true,
15757 },
15758 busy: {
15759 type: Boolean,
15760 notify: true,
15761 },
15762 primary_map: {
15763 type:Object,
15764 computed: "_primaryMap(bots)",
15765 notify: true,
15766 },
15767 primary_arr: {
15768 type:Array,
15769 value: function() {
15770 return DIMENSIONS.concat(BOT_PROPERTIES);
15771 },
15772 notify: true,
15773 },
15774
15775 _data: {
15776 type: Object,
15777 },
15778 },
15779 behaviors: [SwarmingBehaviors.BotListBehavior],
15780
15781 signIn: function(){
15782 this.$.request.generateRequest();
15783 },
15784
15785 _bots: function(){
15786 if (!this._data || !this._data.items) {
15787 return [];
15788 }
15789 this._data.items.forEach(function(o){
15790 o.state = JSON.parse(o.state);
15791 });
15792 return this._data.items;
15793 },
15794
15795 _primaryMap: function(bots){
15796 var map = {};
15797 DIMENSIONS.forEach(function(p){
15798 map[p] = {};
15799 });
15800 map["devices"] = {};
15801 map["gpu"] = {};
15802 bots.forEach(function(b){
15803 DIMENSIONS.forEach(function(d){
15804 var dims = this._dimension(b, d) || [];
15805 dims.forEach(function(e){
15806 map[d][e] = true;
15807 });
15808 }.bind(this));
15809
15810 // Add Android devices and their aliases
15811 this._devices(b).forEach(function(d){
15812 var dt = this._deviceType(d);
15813 var alias = this._androidAlias(d);
15814 if (dt !== "unknown") {
15815 dt = this._applyAlias(dt,alias);
15816 }
15817 map["devices"][dt] = true;
15818 }.bind(this));
15819 map["devices"]["none"] = true;
15820
15821 // Add GPU aliases
15822 var gpus = this._dimension(b, "gpu") || [];
15823 gpus.forEach(function(g){
15824 var alias = this._gpuAlias(g);
15825 if (alias !== "UNKNOWN") {
15826 map["gpu"][this._applyAlias(g, alias)] = true;
15827 } else {
15828 map["gpu"][g] = true;
15829 }
15830
15831 }.bind(this));
15832 }.bind(this));
15833
15834 var pMap = {};
15835 for (key in map){
15836 pMap[key] = Object.keys(map[key]).sort(function(a,b){
15837 // Try numeric, aka "natural" sort first.
15838 var ns = a - b;
15839 if (ns) {
15840 return ns;
15841 }
15842 return a.localeCompare(b);
15843 });
15844 }
15845
15846 // Create custom filter options
15847 pMap["task"] = ["busy", "idle"];
15848 pMap["status"] = ["available", "dead", "quarantined"];
15849 return pMap;
15850 },
15851
15852 });
15853 })();
15854 </script>
15855 </dom-module><script>
15856
15857 /**
15858 * @param {!Function} selectCallback
15859 * @constructor
15860 */
15861 Polymer.IronSelection = function(selectCallback) {
15862 this.selection = [];
15863 this.selectCallback = selectCallback;
15864 };
15865
15866 Polymer.IronSelection.prototype = {
15867
15868 /**
15869 * Retrieves the selected item(s).
15870 *
15871 * @method get
15872 * @returns Returns the selected item(s). If the multi property is true,
15873 * `get` will return an array, otherwise it will return
15874 * the selected item or undefined if there is no selection.
15875 */
15876 get: function() {
15877 return this.multi ? this.selection.slice() : this.selection[0];
15878 },
15879
15880 /**
15881 * Clears all the selection except the ones indicated.
15882 *
15883 * @method clear
15884 * @param {Array} excludes items to be excluded.
15885 */
15886 clear: function(excludes) {
15887 this.selection.slice().forEach(function(item) {
15888 if (!excludes || excludes.indexOf(item) < 0) {
15889 this.setItemSelected(item, false);
15890 }
15891 }, this);
15892 },
15893
15894 /**
15895 * Indicates if a given item is selected.
15896 *
15897 * @method isSelected
15898 * @param {*} item The item whose selection state should be checked.
15899 * @returns Returns true if `item` is selected.
15900 */
15901 isSelected: function(item) {
15902 return this.selection.indexOf(item) >= 0;
15903 },
15904
15905 /**
15906 * Sets the selection state for a given item to either selected or deselecte d.
15907 *
15908 * @method setItemSelected
15909 * @param {*} item The item to select.
15910 * @param {boolean} isSelected True for selected, false for deselected.
15911 */
15912 setItemSelected: function(item, isSelected) {
15913 if (item != null) {
15914 if (isSelected !== this.isSelected(item)) {
15915 // proceed to update selection only if requested state differs from cu rrent
15916 if (isSelected) {
15917 this.selection.push(item);
15918 } else {
15919 var i = this.selection.indexOf(item);
15920 if (i >= 0) {
15921 this.selection.splice(i, 1);
15922 }
15923 }
15924 if (this.selectCallback) {
15925 this.selectCallback(item, isSelected);
15926 }
15927 }
15928 }
15929 },
15930
15931 /**
15932 * Sets the selection state for a given item. If the `multi` property
15933 * is true, then the selected state of `item` will be toggled; otherwise
15934 * the `item` will be selected.
15935 *
15936 * @method select
15937 * @param {*} item The item to select.
15938 */
15939 select: function(item) {
15940 if (this.multi) {
15941 this.toggle(item);
15942 } else if (this.get() !== item) {
15943 this.setItemSelected(this.get(), false);
15944 this.setItemSelected(item, true);
15945 }
15946 },
15947
15948 /**
15949 * Toggles the selection state for `item`.
15950 *
15951 * @method toggle
15952 * @param {*} item The item to toggle.
15953 */
15954 toggle: function(item) {
15955 this.setItemSelected(item, !this.isSelected(item));
15956 }
15957
15958 };
15959
15960 </script>
15961 <script>
15962
15963 /** @polymerBehavior */
15964 Polymer.IronSelectableBehavior = {
15965
15966 /**
15967 * Fired when iron-selector is activated (selected or deselected).
15968 * It is fired before the selected items are changed.
15969 * Cancel the event to abort selection.
15970 *
15971 * @event iron-activate
15972 */
15973
15974 /**
15975 * Fired when an item is selected
15976 *
15977 * @event iron-select
15978 */
15979
15980 /**
15981 * Fired when an item is deselected
15982 *
15983 * @event iron-deselect
15984 */
15985
15986 /**
15987 * Fired when the list of selectable items changes (e.g., items are
15988 * added or removed). The detail of the event is a mutation record that
15989 * describes what changed.
15990 *
15991 * @event iron-items-changed
15992 */
15993
15994 properties: {
15995
15996 /**
15997 * If you want to use an attribute value or property of an element for
15998 * `selected` instead of the index, set this to the name of the attribute
15999 * or property. Hyphenated values are converted to camel case when used to
16000 * look up the property of a selectable element. Camel cased values are
16001 * *not* converted to hyphenated values for attribute lookup. It's
16002 * recommended that you provide the hyphenated form of the name so that
16003 * selection works in both cases. (Use `attr-or-property-name` instead of
16004 * `attrOrPropertyName`.)
16005 */
16006 attrForSelected: {
16007 type: String,
16008 value: null
16009 },
16010
16011 /**
16012 * Gets or sets the selected element. The default is to use the index of t he item.
16013 * @type {string|number}
16014 */
16015 selected: {
16016 type: String,
16017 notify: true
16018 },
16019
16020 /**
16021 * Returns the currently selected item.
16022 *
16023 * @type {?Object}
16024 */
16025 selectedItem: {
16026 type: Object,
16027 readOnly: true,
16028 notify: true
16029 },
16030
16031 /**
16032 * The event that fires from items when they are selected. Selectable
16033 * will listen for this event from items and update the selection state.
16034 * Set to empty string to listen to no events.
16035 */
16036 activateEvent: {
16037 type: String,
16038 value: 'tap',
16039 observer: '_activateEventChanged'
16040 },
16041
16042 /**
16043 * This is a CSS selector string. If this is set, only items that match t he CSS selector
16044 * are selectable.
16045 */
16046 selectable: String,
16047
16048 /**
16049 * The class to set on elements when selected.
16050 */
16051 selectedClass: {
16052 type: String,
16053 value: 'iron-selected'
16054 },
16055
16056 /**
16057 * The attribute to set on elements when selected.
16058 */
16059 selectedAttribute: {
16060 type: String,
16061 value: null
16062 },
16063
16064 /**
16065 * Default fallback if the selection based on selected with `attrForSelect ed`
16066 * is not found.
16067 */
16068 fallbackSelection: {
16069 type: String,
16070 value: null
16071 },
16072
16073 /**
16074 * The list of items from which a selection can be made.
16075 */
16076 items: {
16077 type: Array,
16078 readOnly: true,
16079 notify: true,
16080 value: function() {
16081 return [];
16082 }
16083 },
16084
16085 /**
16086 * The set of excluded elements where the key is the `localName`
16087 * of the element that will be ignored from the item list.
16088 *
16089 * @default {template: 1}
16090 */
16091 _excludedLocalNames: {
16092 type: Object,
16093 value: function() {
16094 return {
16095 'template': 1
16096 };
16097 }
16098 }
16099 },
16100
16101 observers: [
16102 '_updateAttrForSelected(attrForSelected)',
16103 '_updateSelected(selected)',
16104 '_checkFallback(fallbackSelection)'
16105 ],
16106
16107 created: function() {
16108 this._bindFilterItem = this._filterItem.bind(this);
16109 this._selection = new Polymer.IronSelection(this._applySelection.bind(this ));
16110 },
16111
16112 attached: function() {
16113 this._observer = this._observeItems(this);
16114 this._updateItems();
16115 if (!this._shouldUpdateSelection) {
16116 this._updateSelected();
16117 }
16118 this._addListener(this.activateEvent);
16119 },
16120
16121 detached: function() {
16122 if (this._observer) {
16123 Polymer.dom(this).unobserveNodes(this._observer);
16124 }
16125 this._removeListener(this.activateEvent);
16126 },
16127
16128 /**
16129 * Returns the index of the given item.
16130 *
16131 * @method indexOf
16132 * @param {Object} item
16133 * @returns Returns the index of the item
16134 */
16135 indexOf: function(item) {
16136 return this.items.indexOf(item);
16137 },
16138
16139 /**
16140 * Selects the given value.
16141 *
16142 * @method select
16143 * @param {string|number} value the value to select.
16144 */
16145 select: function(value) {
16146 this.selected = value;
16147 },
16148
16149 /**
16150 * Selects the previous item.
16151 *
16152 * @method selectPrevious
16153 */
16154 selectPrevious: function() {
16155 var length = this.items.length;
16156 var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % len gth;
16157 this.selected = this._indexToValue(index);
16158 },
16159
16160 /**
16161 * Selects the next item.
16162 *
16163 * @method selectNext
16164 */
16165 selectNext: function() {
16166 var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.l ength;
16167 this.selected = this._indexToValue(index);
16168 },
16169
16170 /**
16171 * Selects the item at the given index.
16172 *
16173 * @method selectIndex
16174 */
16175 selectIndex: function(index) {
16176 this.select(this._indexToValue(index));
16177 },
16178
16179 /**
16180 * Force a synchronous update of the `items` property.
16181 *
16182 * NOTE: Consider listening for the `iron-items-changed` event to respond to
16183 * updates to the set of selectable items after updates to the DOM list and
16184 * selection state have been made.
16185 *
16186 * WARNING: If you are using this method, you should probably consider an
16187 * alternate approach. Synchronously querying for items is potentially
16188 * slow for many use cases. The `items` property will update asynchronously
16189 * on its own to reflect selectable items in the DOM.
16190 */
16191 forceSynchronousItemUpdate: function() {
16192 this._updateItems();
16193 },
16194
16195 get _shouldUpdateSelection() {
16196 return this.selected != null;
16197 },
16198
16199 _checkFallback: function() {
16200 if (this._shouldUpdateSelection) {
16201 this._updateSelected();
16202 }
16203 },
16204
16205 _addListener: function(eventName) {
16206 this.listen(this, eventName, '_activateHandler');
16207 },
16208
16209 _removeListener: function(eventName) {
16210 this.unlisten(this, eventName, '_activateHandler');
16211 },
16212
16213 _activateEventChanged: function(eventName, old) {
16214 this._removeListener(old);
16215 this._addListener(eventName);
16216 },
16217
16218 _updateItems: function() {
16219 var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
16220 nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
16221 this._setItems(nodes);
16222 },
16223
16224 _updateAttrForSelected: function() {
16225 if (this._shouldUpdateSelection) {
16226 this.selected = this._indexToValue(this.indexOf(this.selectedItem));
16227 }
16228 },
16229
16230 _updateSelected: function() {
16231 this._selectSelected(this.selected);
16232 },
16233
16234 _selectSelected: function(selected) {
16235 this._selection.select(this._valueToItem(this.selected));
16236 // Check for items, since this array is populated only when attached
16237 // Since Number(0) is falsy, explicitly check for undefined
16238 if (this.fallbackSelection && this.items.length && (this._selection.get() === undefined)) {
16239 this.selected = this.fallbackSelection;
16240 }
16241 },
16242
16243 _filterItem: function(node) {
16244 return !this._excludedLocalNames[node.localName];
16245 },
16246
16247 _valueToItem: function(value) {
16248 return (value == null) ? null : this.items[this._valueToIndex(value)];
16249 },
16250
16251 _valueToIndex: function(value) {
16252 if (this.attrForSelected) {
16253 for (var i = 0, item; item = this.items[i]; i++) {
16254 if (this._valueForItem(item) == value) {
16255 return i;
16256 }
16257 }
16258 } else {
16259 return Number(value);
16260 }
16261 },
16262
16263 _indexToValue: function(index) {
16264 if (this.attrForSelected) {
16265 var item = this.items[index];
16266 if (item) {
16267 return this._valueForItem(item);
16268 }
16269 } else {
16270 return index;
16271 }
16272 },
16273
16274 _valueForItem: function(item) {
16275 var propValue = item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected) ];
16276 return propValue != undefined ? propValue : item.getAttribute(this.attrFor Selected);
16277 },
16278
16279 _applySelection: function(item, isSelected) {
16280 if (this.selectedClass) {
16281 this.toggleClass(this.selectedClass, isSelected, item);
16282 }
16283 if (this.selectedAttribute) {
16284 this.toggleAttribute(this.selectedAttribute, isSelected, item);
16285 }
16286 this._selectionChange();
16287 this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {item: item});
16288 },
16289
16290 _selectionChange: function() {
16291 this._setSelectedItem(this._selection.get());
16292 },
16293
16294 // observe items change under the given node.
16295 _observeItems: function(node) {
16296 return Polymer.dom(node).observeNodes(function(mutation) {
16297 this._updateItems();
16298
16299 if (this._shouldUpdateSelection) {
16300 this._updateSelected();
16301 }
16302
16303 // Let other interested parties know about the change so that
16304 // we don't have to recreate mutation observers everywhere.
16305 this.fire('iron-items-changed', mutation, {
16306 bubbles: false,
16307 cancelable: false
16308 });
16309 });
16310 },
16311
16312 _activateHandler: function(e) {
16313 var t = e.target;
16314 var items = this.items;
16315 while (t && t != this) {
16316 var i = items.indexOf(t);
16317 if (i >= 0) {
16318 var value = this._indexToValue(i);
16319 this._itemActivate(value, t);
16320 return;
16321 }
16322 t = t.parentNode;
16323 }
16324 },
16325
16326 _itemActivate: function(value, item) {
16327 if (!this.fire('iron-activate',
16328 {selected: value, item: item}, {cancelable: true}).defaultPrevented) {
16329 this.select(value);
16330 }
16331 }
16332
16333 };
16334
16335 </script>
16336 <script>
16337 /** @polymerBehavior Polymer.IronMultiSelectableBehavior */
16338 Polymer.IronMultiSelectableBehaviorImpl = {
16339 properties: {
16340
16341 /**
16342 * If true, multiple selections are allowed.
16343 */
16344 multi: {
16345 type: Boolean,
16346 value: false,
16347 observer: 'multiChanged'
16348 },
16349
16350 /**
16351 * Gets or sets the selected elements. This is used instead of `selected` when `multi`
16352 * is true.
16353 */
16354 selectedValues: {
16355 type: Array,
16356 notify: true
16357 },
16358
16359 /**
16360 * Returns an array of currently selected items.
16361 */
16362 selectedItems: {
16363 type: Array,
16364 readOnly: true,
16365 notify: true
16366 },
16367
16368 },
16369
16370 observers: [
16371 '_updateSelected(selectedValues.splices)'
16372 ],
16373
16374 /**
16375 * Selects the given value. If the `multi` property is true, then the select ed state of the
16376 * `value` will be toggled; otherwise the `value` will be selected.
16377 *
16378 * @method select
16379 * @param {string|number} value the value to select.
16380 */
16381 select: function(value) {
16382 if (this.multi) {
16383 if (this.selectedValues) {
16384 this._toggleSelected(value);
16385 } else {
16386 this.selectedValues = [value];
16387 }
16388 } else {
16389 this.selected = value;
16390 }
16391 },
16392
16393 multiChanged: function(multi) {
16394 this._selection.multi = multi;
16395 },
16396
16397 get _shouldUpdateSelection() {
16398 return this.selected != null ||
16399 (this.selectedValues != null && this.selectedValues.length);
16400 },
16401
16402 _updateAttrForSelected: function() {
16403 if (!this.multi) {
16404 Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this);
16405 } else if (this._shouldUpdateSelection) {
16406 this.selectedValues = this.selectedItems.map(function(selectedItem) {
16407 return this._indexToValue(this.indexOf(selectedItem));
16408 }, this).filter(function(unfilteredValue) {
16409 return unfilteredValue != null;
16410 }, this);
16411 }
16412 },
16413
16414 _updateSelected: function() {
16415 if (this.multi) {
16416 this._selectMulti(this.selectedValues);
16417 } else {
16418 this._selectSelected(this.selected);
16419 }
16420 },
16421
16422 _selectMulti: function(values) {
16423 if (values) {
16424 var selectedItems = this._valuesToItems(values);
16425 // clear all but the current selected items
16426 this._selection.clear(selectedItems);
16427 // select only those not selected yet
16428 for (var i = 0; i < selectedItems.length; i++) {
16429 this._selection.setItemSelected(selectedItems[i], true);
16430 }
16431 // Check for items, since this array is populated only when attached
16432 if (this.fallbackSelection && this.items.length && !this._selection.get( ).length) {
16433 var fallback = this._valueToItem(this.fallbackSelection);
16434 if (fallback) {
16435 this.selectedValues = [this.fallbackSelection];
16436 }
16437 }
16438 } else {
16439 this._selection.clear();
16440 }
16441 },
16442
16443 _selectionChange: function() {
16444 var s = this._selection.get();
16445 if (this.multi) {
16446 this._setSelectedItems(s);
16447 } else {
16448 this._setSelectedItems([s]);
16449 this._setSelectedItem(s);
16450 }
16451 },
16452
16453 _toggleSelected: function(value) {
16454 var i = this.selectedValues.indexOf(value);
16455 var unselected = i < 0;
16456 if (unselected) {
16457 this.push('selectedValues',value);
16458 } else {
16459 this.splice('selectedValues',i,1);
16460 }
16461 },
16462
16463 _valuesToItems: function(values) {
16464 return (values == null) ? null : values.map(function(value) {
16465 return this._valueToItem(value);
16466 }, this);
16467 }
16468 };
16469
16470 /** @polymerBehavior */
16471 Polymer.IronMultiSelectableBehavior = [
16472 Polymer.IronSelectableBehavior,
16473 Polymer.IronMultiSelectableBehaviorImpl
16474 ];
16475
16476 </script>
16477 <script>
16478 /**
16479 `iron-selector` is an element which can be used to manage a list of elements
16480 that can be selected. Tapping on the item will make the item selected. The ` selected` indicates
16481 which item is being selected. The default is to use the index of the item.
16482
16483 Example:
16484
16485 <iron-selector selected="0">
16486 <div>Item 1</div>
16487 <div>Item 2</div>
16488 <div>Item 3</div>
16489 </iron-selector>
16490
16491 If you want to use the attribute value of an element for `selected` instead of the index,
16492 set `attrForSelected` to the name of the attribute. For example, if you want to select item by
16493 `name`, set `attrForSelected` to `name`.
16494
16495 Example:
16496
16497 <iron-selector attr-for-selected="name" selected="foo">
16498 <div name="foo">Foo</div>
16499 <div name="bar">Bar</div>
16500 <div name="zot">Zot</div>
16501 </iron-selector>
16502
16503 You can specify a default fallback with `fallbackSelection` in case the `selec ted` attribute does
16504 not match the `attrForSelected` attribute of any elements.
16505
16506 Example:
16507
16508 <iron-selector attr-for-selected="name" selected="non-existing"
16509 fallback-selection="default">
16510 <div name="foo">Foo</div>
16511 <div name="bar">Bar</div>
16512 <div name="default">Default</div>
16513 </iron-selector>
16514
16515 Note: When the selector is multi, the selection will set to `fallbackSelection ` iff
16516 the number of matching elements is zero.
16517
16518 `iron-selector` is not styled. Use the `iron-selected` CSS class to style the selected element.
16519
16520 Example:
16521
16522 <style>
16523 .iron-selected {
16524 background: #eee;
16525 }
16526 </style>
16527
16528 ...
16529
16530 <iron-selector selected="0">
16531 <div>Item 1</div>
16532 <div>Item 2</div>
16533 <div>Item 3</div>
16534 </iron-selector>
16535
16536 @demo demo/index.html
16537 */
16538
16539 Polymer({
16540
16541 is: 'iron-selector',
16542
16543 behaviors: [
16544 Polymer.IronMultiSelectableBehavior
16545 ]
16546
16547 });
16548
16549 </script>
16550
16551
16552 <style is="custom-style">
16553
16554 :root {
16555 /*
16556 * You can use these generic variables in your elements for easy theming.
16557 * For example, if all your elements use `--primary-text-color` as its main
16558 * color, then switching from a light to a dark theme is just a matter of
16559 * changing the value of `--primary-text-color` in your application.
16560 */
16561 --primary-text-color: var(--light-theme-text-color);
16562 --primary-background-color: var(--light-theme-background-color);
16563 --secondary-text-color: var(--light-theme-secondary-color);
16564 --disabled-text-color: var(--light-theme-disabled-color);
16565 --divider-color: var(--light-theme-divider-color);
16566 --error-color: var(--paper-deep-orange-a700);
16567
16568 /*
16569 * Primary and accent colors. Also see color.html for more colors.
16570 */
16571 --primary-color: var(--paper-indigo-500);
16572 --light-primary-color: var(--paper-indigo-100);
16573 --dark-primary-color: var(--paper-indigo-700);
16574
16575 --accent-color: var(--paper-pink-a200);
16576 --light-accent-color: var(--paper-pink-a100);
16577 --dark-accent-color: var(--paper-pink-a400);
16578
16579
16580 /*
16581 * Material Design Light background theme
16582 */
16583 --light-theme-background-color: #ffffff;
16584 --light-theme-base-color: #000000;
16585 --light-theme-text-color: var(--paper-grey-900);
16586 --light-theme-secondary-color: #737373; /* for secondary text and icons */
16587 --light-theme-disabled-color: #9b9b9b; /* disabled/hint text */
16588 --light-theme-divider-color: #dbdbdb;
16589
16590 /*
16591 * Material Design Dark background theme
16592 */
16593 --dark-theme-background-color: var(--paper-grey-900);
16594 --dark-theme-base-color: #ffffff;
16595 --dark-theme-text-color: #ffffff;
16596 --dark-theme-secondary-color: #bcbcbc; /* for secondary text and icons */
16597 --dark-theme-disabled-color: #646464; /* disabled/hint text */
16598 --dark-theme-divider-color: #3c3c3c;
16599
16600 /*
16601 * Deprecated values because of their confusing names.
16602 */
16603 --text-primary-color: var(--dark-theme-text-color);
16604 --default-primary-color: var(--primary-color);
16605
16606 }
16607
16608 </style>
16609 <script>
16610 /**
16611 * Singleton IronMeta instance.
16612 */
16613 Polymer.IronValidatableBehaviorMeta = null;
16614
16615 /**
16616 * `Use Polymer.IronValidatableBehavior` to implement an element that validate s user input.
16617 * Use the related `Polymer.IronValidatorBehavior` to add custom validation lo gic to an iron-input.
16618 *
16619 * By default, an `<iron-form>` element validates its fields when the user pre sses the submit button.
16620 * To validate a form imperatively, call the form's `validate()` method, which in turn will
16621 * call `validate()` on all its children. By using `Polymer.IronValidatableBeh avior`, your
16622 * custom element will get a public `validate()`, which
16623 * will return the validity of the element, and a corresponding `invalid` attr ibute,
16624 * which can be used for styling.
16625 *
16626 * To implement the custom validation logic of your element, you must override
16627 * the protected `_getValidity()` method of this behaviour, rather than `valid ate()`.
16628 * See [this](https://github.com/PolymerElements/iron-form/blob/master/demo/si mple-element.html)
16629 * for an example.
16630 *
16631 * ### Accessibility
16632 *
16633 * Changing the `invalid` property, either manually or by calling `validate()` will update the
16634 * `aria-invalid` attribute.
16635 *
16636 * @demo demo/index.html
16637 * @polymerBehavior
16638 */
16639 Polymer.IronValidatableBehavior = {
16640
16641 properties: {
16642
16643 /**
16644 * Name of the validator to use.
16645 */
16646 validator: {
16647 type: String
16648 },
16649
16650 /**
16651 * True if the last call to `validate` is invalid.
16652 */
16653 invalid: {
16654 notify: true,
16655 reflectToAttribute: true,
16656 type: Boolean,
16657 value: false
16658 },
16659
16660 /**
16661 * This property is deprecated and should not be used. Use the global
16662 * validator meta singleton, `Polymer.IronValidatableBehaviorMeta` instead .
16663 */
16664 _validatorMeta: {
16665 type: Object
16666 },
16667
16668 /**
16669 * Namespace for this validator. This property is deprecated and should
16670 * not be used. For all intents and purposes, please consider it a
16671 * read-only, config-time property.
16672 */
16673 validatorType: {
16674 type: String,
16675 value: 'validator'
16676 },
16677
16678 _validator: {
16679 type: Object,
16680 computed: '__computeValidator(validator)'
16681 }
16682 },
16683
16684 observers: [
16685 '_invalidChanged(invalid)'
16686 ],
16687
16688 registered: function() {
16689 Polymer.IronValidatableBehaviorMeta = new Polymer.IronMeta({type: 'validat or'});
16690 },
16691
16692 _invalidChanged: function() {
16693 if (this.invalid) {
16694 this.setAttribute('aria-invalid', 'true');
16695 } else {
16696 this.removeAttribute('aria-invalid');
16697 }
16698 },
16699
16700 /**
16701 * @return {boolean} True if the validator `validator` exists.
16702 */
16703 hasValidator: function() {
16704 return this._validator != null;
16705 },
16706
16707 /**
16708 * Returns true if the `value` is valid, and updates `invalid`. If you want
16709 * your element to have custom validation logic, do not override this method ;
16710 * override `_getValidity(value)` instead.
16711
16712 * @param {Object} value The value to be validated. By default, it is passed
16713 * to the validator's `validate()` function, if a validator is set.
16714 * @return {boolean} True if `value` is valid.
16715 */
16716 validate: function(value) {
16717 this.invalid = !this._getValidity(value);
16718 return !this.invalid;
16719 },
16720
16721 /**
16722 * Returns true if `value` is valid. By default, it is passed
16723 * to the validator's `validate()` function, if a validator is set. You
16724 * should override this method if you want to implement custom validity
16725 * logic for your element.
16726 *
16727 * @param {Object} value The value to be validated.
16728 * @return {boolean} True if `value` is valid.
16729 */
16730
16731 _getValidity: function(value) {
16732 if (this.hasValidator()) {
16733 return this._validator.validate(value);
16734 }
16735 return true;
16736 },
16737
16738 __computeValidator: function() {
16739 return Polymer.IronValidatableBehaviorMeta &&
16740 Polymer.IronValidatableBehaviorMeta.byKey(this.validator);
16741 }
16742 };
16743
16744 </script>
16745 <script>
16746 /**
16747 Polymer.IronFormElementBehavior enables a custom element to be included
16748 in an `iron-form`.
16749
16750 @demo demo/index.html
16751 @polymerBehavior
16752 */
16753 Polymer.IronFormElementBehavior = {
16754
16755 properties: {
16756 /**
16757 * Fired when the element is added to an `iron-form`.
16758 *
16759 * @event iron-form-element-register
16760 */
16761
16762 /**
16763 * Fired when the element is removed from an `iron-form`.
16764 *
16765 * @event iron-form-element-unregister
16766 */
16767
16768 /**
16769 * The name of this element.
16770 */
16771 name: {
16772 type: String
16773 },
16774
16775 /**
16776 * The value for this element.
16777 */
16778 value: {
16779 notify: true,
16780 type: String
16781 },
16782
16783 /**
16784 * Set to true to mark the input as required. If used in a form, a
16785 * custom element that uses this behavior should also use
16786 * Polymer.IronValidatableBehavior and define a custom validation method.
16787 * Otherwise, a `required` element will always be considered valid.
16788 * It's also strongly recommended to provide a visual style for the elemen t
16789 * when its value is invalid.
16790 */
16791 required: {
16792 type: Boolean,
16793 value: false
16794 },
16795
16796 /**
16797 * The form that the element is registered to.
16798 */
16799 _parentForm: {
16800 type: Object
16801 }
16802 },
16803
16804 attached: function() {
16805 // Note: the iron-form that this element belongs to will set this
16806 // element's _parentForm property when handling this event.
16807 this.fire('iron-form-element-register');
16808 },
16809
16810 detached: function() {
16811 if (this._parentForm) {
16812 this._parentForm.fire('iron-form-element-unregister', {target: this});
16813 }
16814 }
16815
16816 };
16817
16818 </script>
16819 <script>
16820
16821 /**
16822 * Use `Polymer.IronCheckedElementBehavior` to implement a custom element
16823 * that has a `checked` property, which can be used for validation if the
16824 * element is also `required`. Element instances implementing this behavior
16825 * will also be registered for use in an `iron-form` element.
16826 *
16827 * @demo demo/index.html
16828 * @polymerBehavior Polymer.IronCheckedElementBehavior
16829 */
16830 Polymer.IronCheckedElementBehaviorImpl = {
16831
16832 properties: {
16833 /**
16834 * Fired when the checked state changes.
16835 *
16836 * @event iron-change
16837 */
16838
16839 /**
16840 * Gets or sets the state, `true` is checked and `false` is unchecked.
16841 */
16842 checked: {
16843 type: Boolean,
16844 value: false,
16845 reflectToAttribute: true,
16846 notify: true,
16847 observer: '_checkedChanged'
16848 },
16849
16850 /**
16851 * If true, the button toggles the active state with each tap or press
16852 * of the spacebar.
16853 */
16854 toggles: {
16855 type: Boolean,
16856 value: true,
16857 reflectToAttribute: true
16858 },
16859
16860 /* Overriden from Polymer.IronFormElementBehavior */
16861 value: {
16862 type: String,
16863 value: 'on',
16864 observer: '_valueChanged'
16865 }
16866 },
16867
16868 observers: [
16869 '_requiredChanged(required)'
16870 ],
16871
16872 created: function() {
16873 // Used by `iron-form` to handle the case that an element with this behavi or
16874 // doesn't have a role of 'checkbox' or 'radio', but should still only be
16875 // included when the form is serialized if `this.checked === true`.
16876 this._hasIronCheckedElementBehavior = true;
16877 },
16878
16879 /**
16880 * Returns false if the element is required and not checked, and true otherw ise.
16881 * @param {*=} _value Ignored.
16882 * @return {boolean} true if `required` is false or if `checked` is true.
16883 */
16884 _getValidity: function(_value) {
16885 return this.disabled || !this.required || this.checked;
16886 },
16887
16888 /**
16889 * Update the aria-required label when `required` is changed.
16890 */
16891 _requiredChanged: function() {
16892 if (this.required) {
16893 this.setAttribute('aria-required', 'true');
16894 } else {
16895 this.removeAttribute('aria-required');
16896 }
16897 },
16898
16899 /**
16900 * Fire `iron-changed` when the checked state changes.
16901 */
16902 _checkedChanged: function() {
16903 this.active = this.checked;
16904 this.fire('iron-change');
16905 },
16906
16907 /**
16908 * Reset value to 'on' if it is set to `undefined`.
16909 */
16910 _valueChanged: function() {
16911 if (this.value === undefined || this.value === null) {
16912 this.value = 'on';
16913 }
16914 }
16915 };
16916
16917 /** @polymerBehavior Polymer.IronCheckedElementBehavior */
16918 Polymer.IronCheckedElementBehavior = [
16919 Polymer.IronFormElementBehavior,
16920 Polymer.IronValidatableBehavior,
16921 Polymer.IronCheckedElementBehaviorImpl
16922 ];
16923
16924 </script>
16925 <script>
16926 (function() {
16927 'use strict';
16928
16929 /**
16930 * Chrome uses an older version of DOM Level 3 Keyboard Events
16931 *
16932 * Most keys are labeled as text, but some are Unicode codepoints.
16933 * Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-200712 21/keyset.html#KeySet-Set
16934 */
16935 var KEY_IDENTIFIER = {
16936 'U+0008': 'backspace',
16937 'U+0009': 'tab',
16938 'U+001B': 'esc',
16939 'U+0020': 'space',
16940 'U+007F': 'del'
16941 };
16942
16943 /**
16944 * Special table for KeyboardEvent.keyCode.
16945 * KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even bett er
16946 * than that.
16947 *
16948 * Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEve nt.keyCode#Value_of_keyCode
16949 */
16950 var KEY_CODE = {
16951 8: 'backspace',
16952 9: 'tab',
16953 13: 'enter',
16954 27: 'esc',
16955 33: 'pageup',
16956 34: 'pagedown',
16957 35: 'end',
16958 36: 'home',
16959 32: 'space',
16960 37: 'left',
16961 38: 'up',
16962 39: 'right',
16963 40: 'down',
16964 46: 'del',
16965 106: '*'
16966 };
16967
16968 /**
16969 * MODIFIER_KEYS maps the short name for modifier keys used in a key
16970 * combo string to the property name that references those same keys
16971 * in a KeyboardEvent instance.
16972 */
16973 var MODIFIER_KEYS = {
16974 'shift': 'shiftKey',
16975 'ctrl': 'ctrlKey',
16976 'alt': 'altKey',
16977 'meta': 'metaKey'
16978 };
16979
16980 /**
16981 * KeyboardEvent.key is mostly represented by printable character made by
16982 * the keyboard, with unprintable keys labeled nicely.
16983 *
16984 * However, on OS X, Alt+char can make a Unicode character that follows an
16985 * Apple-specific mapping. In this case, we fall back to .keyCode.
16986 */
16987 var KEY_CHAR = /[a-z0-9*]/;
16988
16989 /**
16990 * Matches a keyIdentifier string.
16991 */
16992 var IDENT_CHAR = /U\+/;
16993
16994 /**
16995 * Matches arrow keys in Gecko 27.0+
16996 */
16997 var ARROW_KEY = /^arrow/;
16998
16999 /**
17000 * Matches space keys everywhere (notably including IE10's exceptional name
17001 * `spacebar`).
17002 */
17003 var SPACE_KEY = /^space(bar)?/;
17004
17005 /**
17006 * Matches ESC key.
17007 *
17008 * Value from: http://w3c.github.io/uievents-key/#key-Escape
17009 */
17010 var ESC_KEY = /^escape$/;
17011
17012 /**
17013 * Transforms the key.
17014 * @param {string} key The KeyBoardEvent.key
17015 * @param {Boolean} [noSpecialChars] Limits the transformation to
17016 * alpha-numeric characters.
17017 */
17018 function transformKey(key, noSpecialChars) {
17019 var validKey = '';
17020 if (key) {
17021 var lKey = key.toLowerCase();
17022 if (lKey === ' ' || SPACE_KEY.test(lKey)) {
17023 validKey = 'space';
17024 } else if (ESC_KEY.test(lKey)) {
17025 validKey = 'esc';
17026 } else if (lKey.length == 1) {
17027 if (!noSpecialChars || KEY_CHAR.test(lKey)) {
17028 validKey = lKey;
17029 }
17030 } else if (ARROW_KEY.test(lKey)) {
17031 validKey = lKey.replace('arrow', '');
17032 } else if (lKey == 'multiply') {
17033 // numpad '*' can map to Multiply on IE/Windows
17034 validKey = '*';
17035 } else {
17036 validKey = lKey;
17037 }
17038 }
17039 return validKey;
17040 }
17041
17042 function transformKeyIdentifier(keyIdent) {
17043 var validKey = '';
17044 if (keyIdent) {
17045 if (keyIdent in KEY_IDENTIFIER) {
17046 validKey = KEY_IDENTIFIER[keyIdent];
17047 } else if (IDENT_CHAR.test(keyIdent)) {
17048 keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16);
17049 validKey = String.fromCharCode(keyIdent).toLowerCase();
17050 } else {
17051 validKey = keyIdent.toLowerCase();
17052 }
17053 }
17054 return validKey;
17055 }
17056
17057 function transformKeyCode(keyCode) {
17058 var validKey = '';
17059 if (Number(keyCode)) {
17060 if (keyCode >= 65 && keyCode <= 90) {
17061 // ascii a-z
17062 // lowercase is 32 offset from uppercase
17063 validKey = String.fromCharCode(32 + keyCode);
17064 } else if (keyCode >= 112 && keyCode <= 123) {
17065 // function keys f1-f12
17066 validKey = 'f' + (keyCode - 112);
17067 } else if (keyCode >= 48 && keyCode <= 57) {
17068 // top 0-9 keys
17069 validKey = String(keyCode - 48);
17070 } else if (keyCode >= 96 && keyCode <= 105) {
17071 // num pad 0-9
17072 validKey = String(keyCode - 96);
17073 } else {
17074 validKey = KEY_CODE[keyCode];
17075 }
17076 }
17077 return validKey;
17078 }
17079
17080 /**
17081 * Calculates the normalized key for a KeyboardEvent.
17082 * @param {KeyboardEvent} keyEvent
17083 * @param {Boolean} [noSpecialChars] Set to true to limit keyEvent.key
17084 * transformation to alpha-numeric chars. This is useful with key
17085 * combinations like shift + 2, which on FF for MacOS produces
17086 * keyEvent.key = @
17087 * To get 2 returned, set noSpecialChars = true
17088 * To get @ returned, set noSpecialChars = false
17089 */
17090 function normalizedKeyForEvent(keyEvent, noSpecialChars) {
17091 // Fall back from .key, to .keyIdentifier, to .keyCode, and then to
17092 // .detail.key to support artificial keyboard events.
17093 return transformKey(keyEvent.key, noSpecialChars) ||
17094 transformKeyIdentifier(keyEvent.keyIdentifier) ||
17095 transformKeyCode(keyEvent.keyCode) ||
17096 transformKey(keyEvent.detail ? keyEvent.detail.key : keyEvent.detail, no SpecialChars) || '';
17097 }
17098
17099 function keyComboMatchesEvent(keyCombo, event) {
17100 // For combos with modifiers we support only alpha-numeric keys
17101 var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers);
17102 return keyEvent === keyCombo.key &&
17103 (!keyCombo.hasModifiers || (
17104 !!event.shiftKey === !!keyCombo.shiftKey &&
17105 !!event.ctrlKey === !!keyCombo.ctrlKey &&
17106 !!event.altKey === !!keyCombo.altKey &&
17107 !!event.metaKey === !!keyCombo.metaKey)
17108 );
17109 }
17110
17111 function parseKeyComboString(keyComboString) {
17112 if (keyComboString.length === 1) {
17113 return {
17114 combo: keyComboString,
17115 key: keyComboString,
17116 event: 'keydown'
17117 };
17118 }
17119 return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboP art) {
17120 var eventParts = keyComboPart.split(':');
17121 var keyName = eventParts[0];
17122 var event = eventParts[1];
17123
17124 if (keyName in MODIFIER_KEYS) {
17125 parsedKeyCombo[MODIFIER_KEYS[keyName]] = true;
17126 parsedKeyCombo.hasModifiers = true;
17127 } else {
17128 parsedKeyCombo.key = keyName;
17129 parsedKeyCombo.event = event || 'keydown';
17130 }
17131
17132 return parsedKeyCombo;
17133 }, {
17134 combo: keyComboString.split(':').shift()
17135 });
17136 }
17137
17138 function parseEventString(eventString) {
17139 return eventString.trim().split(' ').map(function(keyComboString) {
17140 return parseKeyComboString(keyComboString);
17141 });
17142 }
17143
17144 /**
17145 * `Polymer.IronA11yKeysBehavior` provides a normalized interface for proces sing
17146 * keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3 .org/TR/wai-aria-practices/#kbd_general_binding).
17147 * The element takes care of browser differences with respect to Keyboard ev ents
17148 * and uses an expressive syntax to filter key presses.
17149 *
17150 * Use the `keyBindings` prototype property to express what combination of k eys
17151 * will trigger the callback. A key binding has the format
17152 * `"KEY+MODIFIER:EVENT": "callback"` (`"KEY": "callback"` or
17153 * `"KEY:EVENT": "callback"` are valid as well). Some examples:
17154 *
17155 * keyBindings: {
17156 * 'space': '_onKeydown', // same as 'space:keydown'
17157 * 'shift+tab': '_onKeydown',
17158 * 'enter:keypress': '_onKeypress',
17159 * 'esc:keyup': '_onKeyup'
17160 * }
17161 *
17162 * The callback will receive with an event containing the following informat ion in `event.detail`:
17163 *
17164 * _onKeydown: function(event) {
17165 * console.log(event.detail.combo); // KEY+MODIFIER, e.g. "shift+tab"
17166 * console.log(event.detail.key); // KEY only, e.g. "tab"
17167 * console.log(event.detail.event); // EVENT, e.g. "keydown"
17168 * console.log(event.detail.keyboardEvent); // the original KeyboardE vent
17169 * }
17170 *
17171 * Use the `keyEventTarget` attribute to set up event handlers on a specific
17172 * node.
17173 *
17174 * See the [demo source code](https://github.com/PolymerElements/iron-a11y-k eys-behavior/blob/master/demo/x-key-aware.html)
17175 * for an example.
17176 *
17177 * @demo demo/index.html
17178 * @polymerBehavior
17179 */
17180 Polymer.IronA11yKeysBehavior = {
17181 properties: {
17182 /**
17183 * The EventTarget that will be firing relevant KeyboardEvents. Set it t o
17184 * `null` to disable the listeners.
17185 * @type {?EventTarget}
17186 */
17187 keyEventTarget: {
17188 type: Object,
17189 value: function() {
17190 return this;
17191 }
17192 },
17193
17194 /**
17195 * If true, this property will cause the implementing element to
17196 * automatically stop propagation on any handled KeyboardEvents.
17197 */
17198 stopKeyboardEventPropagation: {
17199 type: Boolean,
17200 value: false
17201 },
17202
17203 _boundKeyHandlers: {
17204 type: Array,
17205 value: function() {
17206 return [];
17207 }
17208 },
17209
17210 // We use this due to a limitation in IE10 where instances will have
17211 // own properties of everything on the "prototype".
17212 _imperativeKeyBindings: {
17213 type: Object,
17214 value: function() {
17215 return {};
17216 }
17217 }
17218 },
17219
17220 observers: [
17221 '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)'
17222 ],
17223
17224
17225 /**
17226 * To be used to express what combination of keys will trigger the relati ve
17227 * callback. e.g. `keyBindings: { 'esc': '_onEscPressed'}`
17228 * @type {Object}
17229 */
17230 keyBindings: {},
17231
17232 registered: function() {
17233 this._prepKeyBindings();
17234 },
17235
17236 attached: function() {
17237 this._listenKeyEventListeners();
17238 },
17239
17240 detached: function() {
17241 this._unlistenKeyEventListeners();
17242 },
17243
17244 /**
17245 * Can be used to imperatively add a key binding to the implementing
17246 * element. This is the imperative equivalent of declaring a keybinding
17247 * in the `keyBindings` prototype property.
17248 */
17249 addOwnKeyBinding: function(eventString, handlerName) {
17250 this._imperativeKeyBindings[eventString] = handlerName;
17251 this._prepKeyBindings();
17252 this._resetKeyEventListeners();
17253 },
17254
17255 /**
17256 * When called, will remove all imperatively-added key bindings.
17257 */
17258 removeOwnKeyBindings: function() {
17259 this._imperativeKeyBindings = {};
17260 this._prepKeyBindings();
17261 this._resetKeyEventListeners();
17262 },
17263
17264 /**
17265 * Returns true if a keyboard event matches `eventString`.
17266 *
17267 * @param {KeyboardEvent} event
17268 * @param {string} eventString
17269 * @return {boolean}
17270 */
17271 keyboardEventMatchesKeys: function(event, eventString) {
17272 var keyCombos = parseEventString(eventString);
17273 for (var i = 0; i < keyCombos.length; ++i) {
17274 if (keyComboMatchesEvent(keyCombos[i], event)) {
17275 return true;
17276 }
17277 }
17278 return false;
17279 },
17280
17281 _collectKeyBindings: function() {
17282 var keyBindings = this.behaviors.map(function(behavior) {
17283 return behavior.keyBindings;
17284 });
17285
17286 if (keyBindings.indexOf(this.keyBindings) === -1) {
17287 keyBindings.push(this.keyBindings);
17288 }
17289
17290 return keyBindings;
17291 },
17292
17293 _prepKeyBindings: function() {
17294 this._keyBindings = {};
17295
17296 this._collectKeyBindings().forEach(function(keyBindings) {
17297 for (var eventString in keyBindings) {
17298 this._addKeyBinding(eventString, keyBindings[eventString]);
17299 }
17300 }, this);
17301
17302 for (var eventString in this._imperativeKeyBindings) {
17303 this._addKeyBinding(eventString, this._imperativeKeyBindings[eventStri ng]);
17304 }
17305
17306 // Give precedence to combos with modifiers to be checked first.
17307 for (var eventName in this._keyBindings) {
17308 this._keyBindings[eventName].sort(function (kb1, kb2) {
17309 var b1 = kb1[0].hasModifiers;
17310 var b2 = kb2[0].hasModifiers;
17311 return (b1 === b2) ? 0 : b1 ? -1 : 1;
17312 })
17313 }
17314 },
17315
17316 _addKeyBinding: function(eventString, handlerName) {
17317 parseEventString(eventString).forEach(function(keyCombo) {
17318 this._keyBindings[keyCombo.event] =
17319 this._keyBindings[keyCombo.event] || [];
17320
17321 this._keyBindings[keyCombo.event].push([
17322 keyCombo,
17323 handlerName
17324 ]);
17325 }, this);
17326 },
17327
17328 _resetKeyEventListeners: function() {
17329 this._unlistenKeyEventListeners();
17330
17331 if (this.isAttached) {
17332 this._listenKeyEventListeners();
17333 }
17334 },
17335
17336 _listenKeyEventListeners: function() {
17337 if (!this.keyEventTarget) {
17338 return;
17339 }
17340 Object.keys(this._keyBindings).forEach(function(eventName) {
17341 var keyBindings = this._keyBindings[eventName];
17342 var boundKeyHandler = this._onKeyBindingEvent.bind(this, keyBindings);
17343
17344 this._boundKeyHandlers.push([this.keyEventTarget, eventName, boundKeyH andler]);
17345
17346 this.keyEventTarget.addEventListener(eventName, boundKeyHandler);
17347 }, this);
17348 },
17349
17350 _unlistenKeyEventListeners: function() {
17351 var keyHandlerTuple;
17352 var keyEventTarget;
17353 var eventName;
17354 var boundKeyHandler;
17355
17356 while (this._boundKeyHandlers.length) {
17357 // My kingdom for block-scope binding and destructuring assignment..
17358 keyHandlerTuple = this._boundKeyHandlers.pop();
17359 keyEventTarget = keyHandlerTuple[0];
17360 eventName = keyHandlerTuple[1];
17361 boundKeyHandler = keyHandlerTuple[2];
17362
17363 keyEventTarget.removeEventListener(eventName, boundKeyHandler);
17364 }
17365 },
17366
17367 _onKeyBindingEvent: function(keyBindings, event) {
17368 if (this.stopKeyboardEventPropagation) {
17369 event.stopPropagation();
17370 }
17371
17372 // if event has been already prevented, don't do anything
17373 if (event.defaultPrevented) {
17374 return;
17375 }
17376
17377 for (var i = 0; i < keyBindings.length; i++) {
17378 var keyCombo = keyBindings[i][0];
17379 var handlerName = keyBindings[i][1];
17380 if (keyComboMatchesEvent(keyCombo, event)) {
17381 this._triggerKeyHandler(keyCombo, handlerName, event);
17382 // exit the loop if eventDefault was prevented
17383 if (event.defaultPrevented) {
17384 return;
17385 }
17386 }
17387 }
17388 },
17389
17390 _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) {
17391 var detail = Object.create(keyCombo);
17392 detail.keyboardEvent = keyboardEvent;
17393 var event = new CustomEvent(keyCombo.event, {
17394 detail: detail,
17395 cancelable: true
17396 });
17397 this[handlerName].call(this, event);
17398 if (event.defaultPrevented) {
17399 keyboardEvent.preventDefault();
17400 }
17401 }
17402 };
17403 })();
17404 </script>
17405 <script>
17406
17407 /**
17408 * @demo demo/index.html
17409 * @polymerBehavior
17410 */
17411 Polymer.IronControlState = {
17412
17413 properties: {
17414
17415 /**
17416 * If true, the element currently has focus.
17417 */
17418 focused: {
17419 type: Boolean,
17420 value: false,
17421 notify: true,
17422 readOnly: true,
17423 reflectToAttribute: true
17424 },
17425
17426 /**
17427 * If true, the user cannot interact with this element.
17428 */
17429 disabled: {
17430 type: Boolean,
17431 value: false,
17432 notify: true,
17433 observer: '_disabledChanged',
17434 reflectToAttribute: true
17435 },
17436
17437 _oldTabIndex: {
17438 type: Number
17439 },
17440
17441 _boundFocusBlurHandler: {
17442 type: Function,
17443 value: function() {
17444 return this._focusBlurHandler.bind(this);
17445 }
17446 }
17447
17448 },
17449
17450 observers: [
17451 '_changedControlState(focused, disabled)'
17452 ],
17453
17454 ready: function() {
17455 this.addEventListener('focus', this._boundFocusBlurHandler, true);
17456 this.addEventListener('blur', this._boundFocusBlurHandler, true);
17457 },
17458
17459 _focusBlurHandler: function(event) {
17460 // NOTE(cdata): if we are in ShadowDOM land, `event.target` will
17461 // eventually become `this` due to retargeting; if we are not in
17462 // ShadowDOM land, `event.target` will eventually become `this` due
17463 // to the second conditional which fires a synthetic event (that is also
17464 // handled). In either case, we can disregard `event.path`.
17465
17466 if (event.target === this) {
17467 this._setFocused(event.type === 'focus');
17468 } else if (!this.shadowRoot) {
17469 var target = /** @type {Node} */(Polymer.dom(event).localTarget);
17470 if (!this.isLightDescendant(target)) {
17471 this.fire(event.type, {sourceEvent: event}, {
17472 node: this,
17473 bubbles: event.bubbles,
17474 cancelable: event.cancelable
17475 });
17476 }
17477 }
17478 },
17479
17480 _disabledChanged: function(disabled, old) {
17481 this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
17482 this.style.pointerEvents = disabled ? 'none' : '';
17483 if (disabled) {
17484 this._oldTabIndex = this.tabIndex;
17485 this._setFocused(false);
17486 this.tabIndex = -1;
17487 this.blur();
17488 } else if (this._oldTabIndex !== undefined) {
17489 this.tabIndex = this._oldTabIndex;
17490 }
17491 },
17492
17493 _changedControlState: function() {
17494 // _controlStateChanged is abstract, follow-on behaviors may implement it
17495 if (this._controlStateChanged) {
17496 this._controlStateChanged();
17497 }
17498 }
17499
17500 };
17501
17502 </script>
17503 <script>
17504
17505 /**
17506 * @demo demo/index.html
17507 * @polymerBehavior Polymer.IronButtonState
17508 */
17509 Polymer.IronButtonStateImpl = {
17510
17511 properties: {
17512
17513 /**
17514 * If true, the user is currently holding down the button.
17515 */
17516 pressed: {
17517 type: Boolean,
17518 readOnly: true,
17519 value: false,
17520 reflectToAttribute: true,
17521 observer: '_pressedChanged'
17522 },
17523
17524 /**
17525 * If true, the button toggles the active state with each tap or press
17526 * of the spacebar.
17527 */
17528 toggles: {
17529 type: Boolean,
17530 value: false,
17531 reflectToAttribute: true
17532 },
17533
17534 /**
17535 * If true, the button is a toggle and is currently in the active state.
17536 */
17537 active: {
17538 type: Boolean,
17539 value: false,
17540 notify: true,
17541 reflectToAttribute: true
17542 },
17543
17544 /**
17545 * True if the element is currently being pressed by a "pointer," which
17546 * is loosely defined as mouse or touch input (but specifically excluding
17547 * keyboard input).
17548 */
17549 pointerDown: {
17550 type: Boolean,
17551 readOnly: true,
17552 value: false
17553 },
17554
17555 /**
17556 * True if the input device that caused the element to receive focus
17557 * was a keyboard.
17558 */
17559 receivedFocusFromKeyboard: {
17560 type: Boolean,
17561 readOnly: true
17562 },
17563
17564 /**
17565 * The aria attribute to be set if the button is a toggle and in the
17566 * active state.
17567 */
17568 ariaActiveAttribute: {
17569 type: String,
17570 value: 'aria-pressed',
17571 observer: '_ariaActiveAttributeChanged'
17572 }
17573 },
17574
17575 listeners: {
17576 down: '_downHandler',
17577 up: '_upHandler',
17578 tap: '_tapHandler'
17579 },
17580
17581 observers: [
17582 '_detectKeyboardFocus(focused)',
17583 '_activeChanged(active, ariaActiveAttribute)'
17584 ],
17585
17586 keyBindings: {
17587 'enter:keydown': '_asyncClick',
17588 'space:keydown': '_spaceKeyDownHandler',
17589 'space:keyup': '_spaceKeyUpHandler',
17590 },
17591
17592 _mouseEventRe: /^mouse/,
17593
17594 _tapHandler: function() {
17595 if (this.toggles) {
17596 // a tap is needed to toggle the active state
17597 this._userActivate(!this.active);
17598 } else {
17599 this.active = false;
17600 }
17601 },
17602
17603 _detectKeyboardFocus: function(focused) {
17604 this._setReceivedFocusFromKeyboard(!this.pointerDown && focused);
17605 },
17606
17607 // to emulate native checkbox, (de-)activations from a user interaction fire
17608 // 'change' events
17609 _userActivate: function(active) {
17610 if (this.active !== active) {
17611 this.active = active;
17612 this.fire('change');
17613 }
17614 },
17615
17616 _downHandler: function(event) {
17617 this._setPointerDown(true);
17618 this._setPressed(true);
17619 this._setReceivedFocusFromKeyboard(false);
17620 },
17621
17622 _upHandler: function() {
17623 this._setPointerDown(false);
17624 this._setPressed(false);
17625 },
17626
17627 /**
17628 * @param {!KeyboardEvent} event .
17629 */
17630 _spaceKeyDownHandler: function(event) {
17631 var keyboardEvent = event.detail.keyboardEvent;
17632 var target = Polymer.dom(keyboardEvent).localTarget;
17633
17634 // Ignore the event if this is coming from a focused light child, since th at
17635 // element will deal with it.
17636 if (this.isLightDescendant(/** @type {Node} */(target)))
17637 return;
17638
17639 keyboardEvent.preventDefault();
17640 keyboardEvent.stopImmediatePropagation();
17641 this._setPressed(true);
17642 },
17643
17644 /**
17645 * @param {!KeyboardEvent} event .
17646 */
17647 _spaceKeyUpHandler: function(event) {
17648 var keyboardEvent = event.detail.keyboardEvent;
17649 var target = Polymer.dom(keyboardEvent).localTarget;
17650
17651 // Ignore the event if this is coming from a focused light child, since th at
17652 // element will deal with it.
17653 if (this.isLightDescendant(/** @type {Node} */(target)))
17654 return;
17655
17656 if (this.pressed) {
17657 this._asyncClick();
17658 }
17659 this._setPressed(false);
17660 },
17661
17662 // trigger click asynchronously, the asynchrony is useful to allow one
17663 // event handler to unwind before triggering another event
17664 _asyncClick: function() {
17665 this.async(function() {
17666 this.click();
17667 }, 1);
17668 },
17669
17670 // any of these changes are considered a change to button state
17671
17672 _pressedChanged: function(pressed) {
17673 this._changedButtonState();
17674 },
17675
17676 _ariaActiveAttributeChanged: function(value, oldValue) {
17677 if (oldValue && oldValue != value && this.hasAttribute(oldValue)) {
17678 this.removeAttribute(oldValue);
17679 }
17680 },
17681
17682 _activeChanged: function(active, ariaActiveAttribute) {
17683 if (this.toggles) {
17684 this.setAttribute(this.ariaActiveAttribute,
17685 active ? 'true' : 'false');
17686 } else {
17687 this.removeAttribute(this.ariaActiveAttribute);
17688 }
17689 this._changedButtonState();
17690 },
17691
17692 _controlStateChanged: function() {
17693 if (this.disabled) {
17694 this._setPressed(false);
17695 } else {
17696 this._changedButtonState();
17697 }
17698 },
17699
17700 // provide hook for follow-on behaviors to react to button-state
17701
17702 _changedButtonState: function() {
17703 if (this._buttonStateChanged) {
17704 this._buttonStateChanged(); // abstract
17705 }
17706 }
17707
17708 };
17709
17710 /** @polymerBehavior */
17711 Polymer.IronButtonState = [
17712 Polymer.IronA11yKeysBehavior,
17713 Polymer.IronButtonStateImpl
17714 ];
17715
17716 </script>
17717
17718
17719 <dom-module id="paper-ripple" assetpath="/res/imp/bower_components/paper-ripple/ ">
17720
17721 <template>
17722 <style>
17723 :host {
17724 display: block;
17725 position: absolute;
17726 border-radius: inherit;
17727 overflow: hidden;
17728 top: 0;
17729 left: 0;
17730 right: 0;
17731 bottom: 0;
17732
17733 /* See PolymerElements/paper-behaviors/issues/34. On non-Chrome browsers ,
17734 * creating a node (with a position:absolute) in the middle of an event
17735 * handler "interrupts" that event handler (which happens when the
17736 * ripple is created on demand) */
17737 pointer-events: none;
17738 }
17739
17740 :host([animating]) {
17741 /* This resolves a rendering issue in Chrome (as of 40) where the
17742 ripple is not properly clipped by its parent (which may have
17743 rounded corners). See: http://jsbin.com/temexa/4
17744
17745 Note: We only apply this style conditionally. Otherwise, the browser
17746 will create a new compositing layer for every ripple element on the
17747 page, and that would be bad. */
17748 -webkit-transform: translate(0, 0);
17749 transform: translate3d(0, 0, 0);
17750 }
17751
17752 #background,
17753 #waves,
17754 .wave-container,
17755 .wave {
17756 pointer-events: none;
17757 position: absolute;
17758 top: 0;
17759 left: 0;
17760 width: 100%;
17761 height: 100%;
17762 }
17763
17764 #background,
17765 .wave {
17766 opacity: 0;
17767 }
17768
17769 #waves,
17770 .wave {
17771 overflow: hidden;
17772 }
17773
17774 .wave-container,
17775 .wave {
17776 border-radius: 50%;
17777 }
17778
17779 :host(.circle) #background,
17780 :host(.circle) #waves {
17781 border-radius: 50%;
17782 }
17783
17784 :host(.circle) .wave-container {
17785 overflow: hidden;
17786 }
17787 </style>
17788
17789 <div id="background"></div>
17790 <div id="waves"></div>
17791 </template>
17792 </dom-module>
17793 <script>
17794 (function() {
17795 var Utility = {
17796 distance: function(x1, y1, x2, y2) {
17797 var xDelta = (x1 - x2);
17798 var yDelta = (y1 - y2);
17799
17800 return Math.sqrt(xDelta * xDelta + yDelta * yDelta);
17801 },
17802
17803 now: window.performance && window.performance.now ?
17804 window.performance.now.bind(window.performance) : Date.now
17805 };
17806
17807 /**
17808 * @param {HTMLElement} element
17809 * @constructor
17810 */
17811 function ElementMetrics(element) {
17812 this.element = element;
17813 this.width = this.boundingRect.width;
17814 this.height = this.boundingRect.height;
17815
17816 this.size = Math.max(this.width, this.height);
17817 }
17818
17819 ElementMetrics.prototype = {
17820 get boundingRect () {
17821 return this.element.getBoundingClientRect();
17822 },
17823
17824 furthestCornerDistanceFrom: function(x, y) {
17825 var topLeft = Utility.distance(x, y, 0, 0);
17826 var topRight = Utility.distance(x, y, this.width, 0);
17827 var bottomLeft = Utility.distance(x, y, 0, this.height);
17828 var bottomRight = Utility.distance(x, y, this.width, this.height);
17829
17830 return Math.max(topLeft, topRight, bottomLeft, bottomRight);
17831 }
17832 };
17833
17834 /**
17835 * @param {HTMLElement} element
17836 * @constructor
17837 */
17838 function Ripple(element) {
17839 this.element = element;
17840 this.color = window.getComputedStyle(element).color;
17841
17842 this.wave = document.createElement('div');
17843 this.waveContainer = document.createElement('div');
17844 this.wave.style.backgroundColor = this.color;
17845 this.wave.classList.add('wave');
17846 this.waveContainer.classList.add('wave-container');
17847 Polymer.dom(this.waveContainer).appendChild(this.wave);
17848
17849 this.resetInteractionState();
17850 }
17851
17852 Ripple.MAX_RADIUS = 300;
17853
17854 Ripple.prototype = {
17855 get recenters() {
17856 return this.element.recenters;
17857 },
17858
17859 get center() {
17860 return this.element.center;
17861 },
17862
17863 get mouseDownElapsed() {
17864 var elapsed;
17865
17866 if (!this.mouseDownStart) {
17867 return 0;
17868 }
17869
17870 elapsed = Utility.now() - this.mouseDownStart;
17871
17872 if (this.mouseUpStart) {
17873 elapsed -= this.mouseUpElapsed;
17874 }
17875
17876 return elapsed;
17877 },
17878
17879 get mouseUpElapsed() {
17880 return this.mouseUpStart ?
17881 Utility.now () - this.mouseUpStart : 0;
17882 },
17883
17884 get mouseDownElapsedSeconds() {
17885 return this.mouseDownElapsed / 1000;
17886 },
17887
17888 get mouseUpElapsedSeconds() {
17889 return this.mouseUpElapsed / 1000;
17890 },
17891
17892 get mouseInteractionSeconds() {
17893 return this.mouseDownElapsedSeconds + this.mouseUpElapsedSeconds;
17894 },
17895
17896 get initialOpacity() {
17897 return this.element.initialOpacity;
17898 },
17899
17900 get opacityDecayVelocity() {
17901 return this.element.opacityDecayVelocity;
17902 },
17903
17904 get radius() {
17905 var width2 = this.containerMetrics.width * this.containerMetrics.width;
17906 var height2 = this.containerMetrics.height * this.containerMetrics.heigh t;
17907 var waveRadius = Math.min(
17908 Math.sqrt(width2 + height2),
17909 Ripple.MAX_RADIUS
17910 ) * 1.1 + 5;
17911
17912 var duration = 1.1 - 0.2 * (waveRadius / Ripple.MAX_RADIUS);
17913 var timeNow = this.mouseInteractionSeconds / duration;
17914 var size = waveRadius * (1 - Math.pow(80, -timeNow));
17915
17916 return Math.abs(size);
17917 },
17918
17919 get opacity() {
17920 if (!this.mouseUpStart) {
17921 return this.initialOpacity;
17922 }
17923
17924 return Math.max(
17925 0,
17926 this.initialOpacity - this.mouseUpElapsedSeconds * this.opacityDecayVe locity
17927 );
17928 },
17929
17930 get outerOpacity() {
17931 // Linear increase in background opacity, capped at the opacity
17932 // of the wavefront (waveOpacity).
17933 var outerOpacity = this.mouseUpElapsedSeconds * 0.3;
17934 var waveOpacity = this.opacity;
17935
17936 return Math.max(
17937 0,
17938 Math.min(outerOpacity, waveOpacity)
17939 );
17940 },
17941
17942 get isOpacityFullyDecayed() {
17943 return this.opacity < 0.01 &&
17944 this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
17945 },
17946
17947 get isRestingAtMaxRadius() {
17948 return this.opacity >= this.initialOpacity &&
17949 this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
17950 },
17951
17952 get isAnimationComplete() {
17953 return this.mouseUpStart ?
17954 this.isOpacityFullyDecayed : this.isRestingAtMaxRadius;
17955 },
17956
17957 get translationFraction() {
17958 return Math.min(
17959 1,
17960 this.radius / this.containerMetrics.size * 2 / Math.sqrt(2)
17961 );
17962 },
17963
17964 get xNow() {
17965 if (this.xEnd) {
17966 return this.xStart + this.translationFraction * (this.xEnd - this.xSta rt);
17967 }
17968
17969 return this.xStart;
17970 },
17971
17972 get yNow() {
17973 if (this.yEnd) {
17974 return this.yStart + this.translationFraction * (this.yEnd - this.ySta rt);
17975 }
17976
17977 return this.yStart;
17978 },
17979
17980 get isMouseDown() {
17981 return this.mouseDownStart && !this.mouseUpStart;
17982 },
17983
17984 resetInteractionState: function() {
17985 this.maxRadius = 0;
17986 this.mouseDownStart = 0;
17987 this.mouseUpStart = 0;
17988
17989 this.xStart = 0;
17990 this.yStart = 0;
17991 this.xEnd = 0;
17992 this.yEnd = 0;
17993 this.slideDistance = 0;
17994
17995 this.containerMetrics = new ElementMetrics(this.element);
17996 },
17997
17998 draw: function() {
17999 var scale;
18000 var translateString;
18001 var dx;
18002 var dy;
18003
18004 this.wave.style.opacity = this.opacity;
18005
18006 scale = this.radius / (this.containerMetrics.size / 2);
18007 dx = this.xNow - (this.containerMetrics.width / 2);
18008 dy = this.yNow - (this.containerMetrics.height / 2);
18009
18010
18011 // 2d transform for safari because of border-radius and overflow:hidden clipping bug.
18012 // https://bugs.webkit.org/show_bug.cgi?id=98538
18013 this.waveContainer.style.webkitTransform = 'translate(' + dx + 'px, ' + dy + 'px)';
18014 this.waveContainer.style.transform = 'translate3d(' + dx + 'px, ' + dy + 'px, 0)';
18015 this.wave.style.webkitTransform = 'scale(' + scale + ',' + scale + ')';
18016 this.wave.style.transform = 'scale3d(' + scale + ',' + scale + ',1)';
18017 },
18018
18019 /** @param {Event=} event */
18020 downAction: function(event) {
18021 var xCenter = this.containerMetrics.width / 2;
18022 var yCenter = this.containerMetrics.height / 2;
18023
18024 this.resetInteractionState();
18025 this.mouseDownStart = Utility.now();
18026
18027 if (this.center) {
18028 this.xStart = xCenter;
18029 this.yStart = yCenter;
18030 this.slideDistance = Utility.distance(
18031 this.xStart, this.yStart, this.xEnd, this.yEnd
18032 );
18033 } else {
18034 this.xStart = event ?
18035 event.detail.x - this.containerMetrics.boundingRect.left :
18036 this.containerMetrics.width / 2;
18037 this.yStart = event ?
18038 event.detail.y - this.containerMetrics.boundingRect.top :
18039 this.containerMetrics.height / 2;
18040 }
18041
18042 if (this.recenters) {
18043 this.xEnd = xCenter;
18044 this.yEnd = yCenter;
18045 this.slideDistance = Utility.distance(
18046 this.xStart, this.yStart, this.xEnd, this.yEnd
18047 );
18048 }
18049
18050 this.maxRadius = this.containerMetrics.furthestCornerDistanceFrom(
18051 this.xStart,
18052 this.yStart
18053 );
18054
18055 this.waveContainer.style.top =
18056 (this.containerMetrics.height - this.containerMetrics.size) / 2 + 'px' ;
18057 this.waveContainer.style.left =
18058 (this.containerMetrics.width - this.containerMetrics.size) / 2 + 'px';
18059
18060 this.waveContainer.style.width = this.containerMetrics.size + 'px';
18061 this.waveContainer.style.height = this.containerMetrics.size + 'px';
18062 },
18063
18064 /** @param {Event=} event */
18065 upAction: function(event) {
18066 if (!this.isMouseDown) {
18067 return;
18068 }
18069
18070 this.mouseUpStart = Utility.now();
18071 },
18072
18073 remove: function() {
18074 Polymer.dom(this.waveContainer.parentNode).removeChild(
18075 this.waveContainer
18076 );
18077 }
18078 };
18079
18080 Polymer({
18081 is: 'paper-ripple',
18082
18083 behaviors: [
18084 Polymer.IronA11yKeysBehavior
18085 ],
18086
18087 properties: {
18088 /**
18089 * The initial opacity set on the wave.
18090 *
18091 * @attribute initialOpacity
18092 * @type number
18093 * @default 0.25
18094 */
18095 initialOpacity: {
18096 type: Number,
18097 value: 0.25
18098 },
18099
18100 /**
18101 * How fast (opacity per second) the wave fades out.
18102 *
18103 * @attribute opacityDecayVelocity
18104 * @type number
18105 * @default 0.8
18106 */
18107 opacityDecayVelocity: {
18108 type: Number,
18109 value: 0.8
18110 },
18111
18112 /**
18113 * If true, ripples will exhibit a gravitational pull towards
18114 * the center of their container as they fade away.
18115 *
18116 * @attribute recenters
18117 * @type boolean
18118 * @default false
18119 */
18120 recenters: {
18121 type: Boolean,
18122 value: false
18123 },
18124
18125 /**
18126 * If true, ripples will center inside its container
18127 *
18128 * @attribute recenters
18129 * @type boolean
18130 * @default false
18131 */
18132 center: {
18133 type: Boolean,
18134 value: false
18135 },
18136
18137 /**
18138 * A list of the visual ripples.
18139 *
18140 * @attribute ripples
18141 * @type Array
18142 * @default []
18143 */
18144 ripples: {
18145 type: Array,
18146 value: function() {
18147 return [];
18148 }
18149 },
18150
18151 /**
18152 * True when there are visible ripples animating within the
18153 * element.
18154 */
18155 animating: {
18156 type: Boolean,
18157 readOnly: true,
18158 reflectToAttribute: true,
18159 value: false
18160 },
18161
18162 /**
18163 * If true, the ripple will remain in the "down" state until `holdDown`
18164 * is set to false again.
18165 */
18166 holdDown: {
18167 type: Boolean,
18168 value: false,
18169 observer: '_holdDownChanged'
18170 },
18171
18172 /**
18173 * If true, the ripple will not generate a ripple effect
18174 * via pointer interaction.
18175 * Calling ripple's imperative api like `simulatedRipple` will
18176 * still generate the ripple effect.
18177 */
18178 noink: {
18179 type: Boolean,
18180 value: false
18181 },
18182
18183 _animating: {
18184 type: Boolean
18185 },
18186
18187 _boundAnimate: {
18188 type: Function,
18189 value: function() {
18190 return this.animate.bind(this);
18191 }
18192 }
18193 },
18194
18195 get target () {
18196 return this.keyEventTarget;
18197 },
18198
18199 keyBindings: {
18200 'enter:keydown': '_onEnterKeydown',
18201 'space:keydown': '_onSpaceKeydown',
18202 'space:keyup': '_onSpaceKeyup'
18203 },
18204
18205 attached: function() {
18206 // Set up a11yKeysBehavior to listen to key events on the target,
18207 // so that space and enter activate the ripple even if the target doesn' t
18208 // handle key events. The key handlers deal with `noink` themselves.
18209 if (this.parentNode.nodeType == 11) { // DOCUMENT_FRAGMENT_NODE
18210 this.keyEventTarget = Polymer.dom(this).getOwnerRoot().host;
18211 } else {
18212 this.keyEventTarget = this.parentNode;
18213 }
18214 var keyEventTarget = /** @type {!EventTarget} */ (this.keyEventTarget);
18215 this.listen(keyEventTarget, 'up', 'uiUpAction');
18216 this.listen(keyEventTarget, 'down', 'uiDownAction');
18217 },
18218
18219 detached: function() {
18220 this.unlisten(this.keyEventTarget, 'up', 'uiUpAction');
18221 this.unlisten(this.keyEventTarget, 'down', 'uiDownAction');
18222 this.keyEventTarget = null;
18223 },
18224
18225 get shouldKeepAnimating () {
18226 for (var index = 0; index < this.ripples.length; ++index) {
18227 if (!this.ripples[index].isAnimationComplete) {
18228 return true;
18229 }
18230 }
18231
18232 return false;
18233 },
18234
18235 simulatedRipple: function() {
18236 this.downAction(null);
18237
18238 // Please see polymer/polymer#1305
18239 this.async(function() {
18240 this.upAction();
18241 }, 1);
18242 },
18243
18244 /**
18245 * Provokes a ripple down effect via a UI event,
18246 * respecting the `noink` property.
18247 * @param {Event=} event
18248 */
18249 uiDownAction: function(event) {
18250 if (!this.noink) {
18251 this.downAction(event);
18252 }
18253 },
18254
18255 /**
18256 * Provokes a ripple down effect via a UI event,
18257 * *not* respecting the `noink` property.
18258 * @param {Event=} event
18259 */
18260 downAction: function(event) {
18261 if (this.holdDown && this.ripples.length > 0) {
18262 return;
18263 }
18264
18265 var ripple = this.addRipple();
18266
18267 ripple.downAction(event);
18268
18269 if (!this._animating) {
18270 this._animating = true;
18271 this.animate();
18272 }
18273 },
18274
18275 /**
18276 * Provokes a ripple up effect via a UI event,
18277 * respecting the `noink` property.
18278 * @param {Event=} event
18279 */
18280 uiUpAction: function(event) {
18281 if (!this.noink) {
18282 this.upAction(event);
18283 }
18284 },
18285
18286 /**
18287 * Provokes a ripple up effect via a UI event,
18288 * *not* respecting the `noink` property.
18289 * @param {Event=} event
18290 */
18291 upAction: function(event) {
18292 if (this.holdDown) {
18293 return;
18294 }
18295
18296 this.ripples.forEach(function(ripple) {
18297 ripple.upAction(event);
18298 });
18299
18300 this._animating = true;
18301 this.animate();
18302 },
18303
18304 onAnimationComplete: function() {
18305 this._animating = false;
18306 this.$.background.style.backgroundColor = null;
18307 this.fire('transitionend');
18308 },
18309
18310 addRipple: function() {
18311 var ripple = new Ripple(this);
18312
18313 Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);
18314 this.$.background.style.backgroundColor = ripple.color;
18315 this.ripples.push(ripple);
18316
18317 this._setAnimating(true);
18318
18319 return ripple;
18320 },
18321
18322 removeRipple: function(ripple) {
18323 var rippleIndex = this.ripples.indexOf(ripple);
18324
18325 if (rippleIndex < 0) {
18326 return;
18327 }
18328
18329 this.ripples.splice(rippleIndex, 1);
18330
18331 ripple.remove();
18332
18333 if (!this.ripples.length) {
18334 this._setAnimating(false);
18335 }
18336 },
18337
18338 animate: function() {
18339 if (!this._animating) {
18340 return;
18341 }
18342 var index;
18343 var ripple;
18344
18345 for (index = 0; index < this.ripples.length; ++index) {
18346 ripple = this.ripples[index];
18347
18348 ripple.draw();
18349
18350 this.$.background.style.opacity = ripple.outerOpacity;
18351
18352 if (ripple.isOpacityFullyDecayed && !ripple.isRestingAtMaxRadius) {
18353 this.removeRipple(ripple);
18354 }
18355 }
18356
18357 if (!this.shouldKeepAnimating && this.ripples.length === 0) {
18358 this.onAnimationComplete();
18359 } else {
18360 window.requestAnimationFrame(this._boundAnimate);
18361 }
18362 },
18363
18364 _onEnterKeydown: function() {
18365 this.uiDownAction();
18366 this.async(this.uiUpAction, 1);
18367 },
18368
18369 _onSpaceKeydown: function() {
18370 this.uiDownAction();
18371 },
18372
18373 _onSpaceKeyup: function() {
18374 this.uiUpAction();
18375 },
18376
18377 // note: holdDown does not respect noink since it can be a focus based
18378 // effect.
18379 _holdDownChanged: function(newVal, oldVal) {
18380 if (oldVal === undefined) {
18381 return;
18382 }
18383 if (newVal) {
18384 this.downAction();
18385 } else {
18386 this.upAction();
18387 }
18388 }
18389
18390 /**
18391 Fired when the animation finishes.
18392 This is useful if you want to wait until
18393 the ripple animation finishes to perform some action.
18394
18395 @event transitionend
18396 @param {{node: Object}} detail Contains the animated node.
18397 */
18398 });
18399 })();
18400 </script>
18401 <script>
18402 /**
18403 * `Polymer.PaperRippleBehavior` dynamically implements a ripple
18404 * when the element has focus via pointer or keyboard.
18405 *
18406 * NOTE: This behavior is intended to be used in conjunction with and after
18407 * `Polymer.IronButtonState` and `Polymer.IronControlState`.
18408 *
18409 * @polymerBehavior Polymer.PaperRippleBehavior
18410 */
18411 Polymer.PaperRippleBehavior = {
18412 properties: {
18413 /**
18414 * If true, the element will not produce a ripple effect when interacted
18415 * with via the pointer.
18416 */
18417 noink: {
18418 type: Boolean,
18419 observer: '_noinkChanged'
18420 },
18421
18422 /**
18423 * @type {Element|undefined}
18424 */
18425 _rippleContainer: {
18426 type: Object,
18427 }
18428 },
18429
18430 /**
18431 * Ensures a `<paper-ripple>` element is available when the element is
18432 * focused.
18433 */
18434 _buttonStateChanged: function() {
18435 if (this.focused) {
18436 this.ensureRipple();
18437 }
18438 },
18439
18440 /**
18441 * In addition to the functionality provided in `IronButtonState`, ensures
18442 * a ripple effect is created when the element is in a `pressed` state.
18443 */
18444 _downHandler: function(event) {
18445 Polymer.IronButtonStateImpl._downHandler.call(this, event);
18446 if (this.pressed) {
18447 this.ensureRipple(event);
18448 }
18449 },
18450
18451 /**
18452 * Ensures this element contains a ripple effect. For startup efficiency
18453 * the ripple effect is dynamically on demand when needed.
18454 * @param {!Event=} optTriggeringEvent (optional) event that triggered the
18455 * ripple.
18456 */
18457 ensureRipple: function(optTriggeringEvent) {
18458 if (!this.hasRipple()) {
18459 this._ripple = this._createRipple();
18460 this._ripple.noink = this.noink;
18461 var rippleContainer = this._rippleContainer || this.root;
18462 if (rippleContainer) {
18463 Polymer.dom(rippleContainer).appendChild(this._ripple);
18464 }
18465 if (optTriggeringEvent) {
18466 // Check if the event happened inside of the ripple container
18467 // Fall back to host instead of the root because distributed text
18468 // nodes are not valid event targets
18469 var domContainer = Polymer.dom(this._rippleContainer || this);
18470 var target = Polymer.dom(optTriggeringEvent).rootTarget;
18471 if (domContainer.deepContains( /** @type {Node} */(target))) {
18472 this._ripple.uiDownAction(optTriggeringEvent);
18473 }
18474 }
18475 }
18476 },
18477
18478 /**
18479 * Returns the `<paper-ripple>` element used by this element to create
18480 * ripple effects. The element's ripple is created on demand, when
18481 * necessary, and calling this method will force the
18482 * ripple to be created.
18483 */
18484 getRipple: function() {
18485 this.ensureRipple();
18486 return this._ripple;
18487 },
18488
18489 /**
18490 * Returns true if this element currently contains a ripple effect.
18491 * @return {boolean}
18492 */
18493 hasRipple: function() {
18494 return Boolean(this._ripple);
18495 },
18496
18497 /**
18498 * Create the element's ripple effect via creating a `<paper-ripple>`.
18499 * Override this method to customize the ripple element.
18500 * @return {!PaperRippleElement} Returns a `<paper-ripple>` element.
18501 */
18502 _createRipple: function() {
18503 return /** @type {!PaperRippleElement} */ (
18504 document.createElement('paper-ripple'));
18505 },
18506
18507 _noinkChanged: function(noink) {
18508 if (this.hasRipple()) {
18509 this._ripple.noink = noink;
18510 }
18511 }
18512 };
18513 </script>
18514 <script>
18515 /**
18516 * `Polymer.PaperInkyFocusBehavior` implements a ripple when the element has k eyboard focus.
18517 *
18518 * @polymerBehavior Polymer.PaperInkyFocusBehavior
18519 */
18520 Polymer.PaperInkyFocusBehaviorImpl = {
18521 observers: [
18522 '_focusedChanged(receivedFocusFromKeyboard)'
18523 ],
18524
18525 _focusedChanged: function(receivedFocusFromKeyboard) {
18526 if (receivedFocusFromKeyboard) {
18527 this.ensureRipple();
18528 }
18529 if (this.hasRipple()) {
18530 this._ripple.holdDown = receivedFocusFromKeyboard;
18531 }
18532 },
18533
18534 _createRipple: function() {
18535 var ripple = Polymer.PaperRippleBehavior._createRipple();
18536 ripple.id = 'ink';
18537 ripple.setAttribute('center', '');
18538 ripple.classList.add('circle');
18539 return ripple;
18540 }
18541 };
18542
18543 /** @polymerBehavior Polymer.PaperInkyFocusBehavior */
18544 Polymer.PaperInkyFocusBehavior = [
18545 Polymer.IronButtonState,
18546 Polymer.IronControlState,
18547 Polymer.PaperRippleBehavior,
18548 Polymer.PaperInkyFocusBehaviorImpl
18549 ];
18550 </script>
18551 <script>
18552 /**
18553 * Use `Polymer.PaperCheckedElementBehavior` to implement a custom element
18554 * that has a `checked` property similar to `Polymer.IronCheckedElementBehavio r`
18555 * and is compatible with having a ripple effect.
18556 * @polymerBehavior Polymer.PaperCheckedElementBehavior
18557 */
18558 Polymer.PaperCheckedElementBehaviorImpl = {
18559 /**
18560 * Synchronizes the element's checked state with its ripple effect.
18561 */
18562 _checkedChanged: function() {
18563 Polymer.IronCheckedElementBehaviorImpl._checkedChanged.call(this);
18564 if (this.hasRipple()) {
18565 if (this.checked) {
18566 this._ripple.setAttribute('checked', '');
18567 } else {
18568 this._ripple.removeAttribute('checked');
18569 }
18570 }
18571 },
18572
18573 /**
18574 * Synchronizes the element's `active` and `checked` state.
18575 */
18576 _buttonStateChanged: function() {
18577 Polymer.PaperRippleBehavior._buttonStateChanged.call(this);
18578 if (this.disabled) {
18579 return;
18580 }
18581 if (this.isAttached) {
18582 this.checked = this.active;
18583 }
18584 }
18585 };
18586
18587 /** @polymerBehavior Polymer.PaperCheckedElementBehavior */
18588 Polymer.PaperCheckedElementBehavior = [
18589 Polymer.PaperInkyFocusBehavior,
18590 Polymer.IronCheckedElementBehavior,
18591 Polymer.PaperCheckedElementBehaviorImpl
18592 ];
18593 </script>
18594
18595
18596 <dom-module id="paper-checkbox" assetpath="/res/imp/bower_components/paper-check box/">
18597 <template strip-whitespace="">
18598 <style>
18599 :host {
18600 display: inline-block;
18601 white-space: nowrap;
18602 cursor: pointer;
18603 --calculated-paper-checkbox-size: var(--paper-checkbox-size, 18px);
18604 @apply(--paper-font-common-base);
18605 line-height: 0;
18606 -webkit-tap-highlight-color: transparent;
18607 }
18608
18609 :host([hidden]) {
18610 display: none !important;
18611 }
18612
18613 :host(:focus) {
18614 outline: none;
18615 }
18616
18617 .hidden {
18618 display: none;
18619 }
18620
18621 #checkboxContainer {
18622 display: inline-block;
18623 position: relative;
18624 width: var(--calculated-paper-checkbox-size);
18625 height: var(--calculated-paper-checkbox-size);
18626 min-width: var(--calculated-paper-checkbox-size);
18627 margin: var(--paper-checkbox-margin, initial);
18628 vertical-align: var(--paper-checkbox-vertical-align, middle);
18629 background-color: var(--paper-checkbox-unchecked-background-color, trans parent);
18630 }
18631
18632 #ink {
18633 position: absolute;
18634
18635 /* Center the ripple in the checkbox by negative offsetting it by
18636 * (inkWidth - rippleWidth) / 2 */
18637 top: calc(0px - (2.66 * var(--calculated-paper-checkbox-size) - var(--ca lculated-paper-checkbox-size)) / 2);
18638 left: calc(0px - (2.66 * var(--calculated-paper-checkbox-size) - var(--c alculated-paper-checkbox-size)) / 2);
18639 width: calc(2.66 * var(--calculated-paper-checkbox-size));
18640 height: calc(2.66 * var(--calculated-paper-checkbox-size));
18641 color: var(--paper-checkbox-unchecked-ink-color, --primary-text-color);
18642 opacity: 0.6;
18643 pointer-events: none;
18644 }
18645
18646 :host-context([dir="rtl"]) #ink {
18647 right: calc(0px - (2.66 * var(--calculated-paper-checkbox-size) - var(-- calculated-paper-checkbox-size)) / 2);
18648 left: auto;
18649 }
18650
18651 #ink[checked] {
18652 color: var(--paper-checkbox-checked-ink-color, --primary-color);
18653 }
18654
18655 #checkbox {
18656 position: relative;
18657 box-sizing: border-box;
18658 height: 100%;
18659 border: solid 2px;
18660 border-color: var(--paper-checkbox-unchecked-color, --primary-text-color );
18661 border-radius: 2px;
18662 pointer-events: none;
18663 -webkit-transition: background-color 140ms, border-color 140ms;
18664 transition: background-color 140ms, border-color 140ms;
18665 }
18666
18667 /* checkbox checked animations */
18668 #checkbox.checked #checkmark {
18669 -webkit-animation: checkmark-expand 140ms ease-out forwards;
18670 animation: checkmark-expand 140ms ease-out forwards;
18671 }
18672
18673 @-webkit-keyframes checkmark-expand {
18674 0% {
18675 -webkit-transform: scale(0, 0) rotate(45deg);
18676 }
18677 100% {
18678 -webkit-transform: scale(1, 1) rotate(45deg);
18679 }
18680 }
18681
18682 @keyframes checkmark-expand {
18683 0% {
18684 transform: scale(0, 0) rotate(45deg);
18685 }
18686 100% {
18687 transform: scale(1, 1) rotate(45deg);
18688 }
18689 }
18690
18691 #checkbox.checked {
18692 background-color: var(--paper-checkbox-checked-color, --primary-color);
18693 border-color: var(--paper-checkbox-checked-color, --primary-color);
18694 }
18695
18696 #checkmark {
18697 position: absolute;
18698 width: 36%;
18699 height: 70%;
18700 border-style: solid;
18701 border-top: none;
18702 border-left: none;
18703 border-right-width: calc(2/15 * var(--calculated-paper-checkbox-size));
18704 border-bottom-width: calc(2/15 * var(--calculated-paper-checkbox-size));
18705 border-color: var(--paper-checkbox-checkmark-color, white);
18706 -webkit-transform-origin: 97% 86%;
18707 transform-origin: 97% 86%;
18708 box-sizing: content-box; /* protect against page-level box-sizing */
18709 }
18710
18711 :host-context([dir="rtl"]) #checkmark {
18712 -webkit-transform-origin: 50% 14%;
18713 transform-origin: 50% 14%;
18714 }
18715
18716 /* label */
18717 #checkboxLabel {
18718 position: relative;
18719 display: inline-block;
18720 vertical-align: middle;
18721 padding-left: var(--paper-checkbox-label-spacing, 8px);
18722 white-space: normal;
18723 line-height: normal;
18724 color: var(--paper-checkbox-label-color, --primary-text-color);
18725 @apply(--paper-checkbox-label);
18726 }
18727
18728 :host([checked]) #checkboxLabel {
18729 color: var(--paper-checkbox-label-checked-color, --paper-checkbox-label- color);
18730 @apply(--paper-checkbox-label-checked);
18731 }
18732
18733 :host-context([dir="rtl"]) #checkboxLabel {
18734 padding-right: var(--paper-checkbox-label-spacing, 8px);
18735 padding-left: 0;
18736 }
18737
18738 #checkboxLabel[hidden] {
18739 display: none;
18740 }
18741
18742 /* disabled state */
18743
18744 :host([disabled]) #checkbox {
18745 opacity: 0.5;
18746 border-color: var(--paper-checkbox-unchecked-color, --primary-text-color );
18747 }
18748
18749 :host([disabled][checked]) #checkbox {
18750 background-color: var(--paper-checkbox-unchecked-color, --primary-text-c olor);
18751 opacity: 0.5;
18752 }
18753
18754 :host([disabled]) #checkboxLabel {
18755 opacity: 0.65;
18756 }
18757
18758 /* invalid state */
18759 #checkbox.invalid:not(.checked) {
18760 border-color: var(--paper-checkbox-error-color, --error-color);
18761 }
18762 </style>
18763
18764 <div id="checkboxContainer">
18765 <div id="checkbox" class$="[[_computeCheckboxClass(checked, invalid)]]">
18766 <div id="checkmark" class$="[[_computeCheckmarkClass(checked)]]"></div>
18767 </div>
18768 </div>
18769
18770 <div id="checkboxLabel"><content></content></div>
18771 </template>
18772
18773 <script>
18774 Polymer({
18775 is: 'paper-checkbox',
18776
18777 behaviors: [
18778 Polymer.PaperCheckedElementBehavior
18779 ],
18780
18781 hostAttributes: {
18782 role: 'checkbox',
18783 'aria-checked': false,
18784 tabindex: 0
18785 },
18786
18787 properties: {
18788 /**
18789 * Fired when the checked state changes due to user interaction.
18790 *
18791 * @event change
18792 */
18793
18794 /**
18795 * Fired when the checked state changes.
18796 *
18797 * @event iron-change
18798 */
18799 ariaActiveAttribute: {
18800 type: String,
18801 value: 'aria-checked'
18802 }
18803 },
18804
18805 _computeCheckboxClass: function(checked, invalid) {
18806 var className = '';
18807 if (checked) {
18808 className += 'checked ';
18809 }
18810 if (invalid) {
18811 className += 'invalid';
18812 }
18813 return className;
18814 },
18815
18816 _computeCheckmarkClass: function(checked) {
18817 return checked ? '' : 'hidden';
18818 },
18819
18820 // create ripple inside the checkboxContainer
18821 _createRipple: function() {
18822 this._rippleContainer = this.$.checkboxContainer;
18823 return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this);
18824 }
18825
18826 });
18827 </script>
18828 </dom-module>
18829
18830
18831 <dom-module id="paper-icon-button" assetpath="/res/imp/bower_components/paper-ic on-button/">
18832 <template strip-whitespace="">
18833 <style>
18834 :host {
18835 display: inline-block;
18836 position: relative;
18837 padding: 8px;
18838 outline: none;
18839 -webkit-user-select: none;
18840 -moz-user-select: none;
18841 -ms-user-select: none;
18842 user-select: none;
18843 cursor: pointer;
18844 z-index: 0;
18845 line-height: 1;
18846
18847 width: 40px;
18848 height: 40px;
18849
18850 /* NOTE: Both values are needed, since some phones require the value to be `transparent`. */
18851 -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
18852 -webkit-tap-highlight-color: transparent;
18853
18854 /* Because of polymer/2558, this style has lower specificity than * */
18855 box-sizing: border-box !important;
18856
18857 @apply(--paper-icon-button);
18858 }
18859
18860 :host #ink {
18861 color: var(--paper-icon-button-ink-color, --primary-text-color);
18862 opacity: 0.6;
18863 }
18864
18865 :host([disabled]) {
18866 color: var(--paper-icon-button-disabled-text, --disabled-text-color);
18867 pointer-events: none;
18868 cursor: auto;
18869
18870 @apply(--paper-icon-button-disabled);
18871 }
18872
18873 :host(:hover) {
18874 @apply(--paper-icon-button-hover);
18875 }
18876
18877 iron-icon {
18878 --iron-icon-width: 100%;
18879 --iron-icon-height: 100%;
18880 }
18881 </style>
18882
18883 <iron-icon id="icon" src="[[src]]" icon="[[icon]]" alt$="[[alt]]"></iron-ico n>
18884 </template>
18885
18886 <script>
18887 Polymer({
18888 is: 'paper-icon-button',
18889
18890 hostAttributes: {
18891 role: 'button',
18892 tabindex: '0'
18893 },
18894
18895 behaviors: [
18896 Polymer.PaperInkyFocusBehavior
18897 ],
18898
18899 properties: {
18900 /**
18901 * The URL of an image for the icon. If the src property is specified,
18902 * the icon property should not be.
18903 */
18904 src: {
18905 type: String
18906 },
18907
18908 /**
18909 * Specifies the icon name or index in the set of icons available in
18910 * the icon's icon set. If the icon property is specified,
18911 * the src property should not be.
18912 */
18913 icon: {
18914 type: String
18915 },
18916
18917 /**
18918 * Specifies the alternate text for the button, for accessibility.
18919 */
18920 alt: {
18921 type: String,
18922 observer: "_altChanged"
18923 }
18924 },
18925
18926 _altChanged: function(newValue, oldValue) {
18927 var label = this.getAttribute('aria-label');
18928
18929 // Don't stomp over a user-set aria-label.
18930 if (!label || oldValue == label) {
18931 this.setAttribute('aria-label', newValue);
18932 }
18933 }
18934 });
18935 </script>
18936 </dom-module>
18937
18938
18939 <dom-module id="iron-a11y-announcer" assetpath="/res/imp/bower_components/iron-a 11y-announcer/">
18940 <template>
18941 <style>
18942 :host {
18943 display: inline-block;
18944 position: fixed;
18945 clip: rect(0px,0px,0px,0px);
18946 }
18947 </style>
18948 <div aria-live$="[[mode]]">[[_text]]</div>
18949 </template>
18950
18951 <script>
18952
18953 (function() {
18954 'use strict';
18955
18956 Polymer.IronA11yAnnouncer = Polymer({
18957 is: 'iron-a11y-announcer',
18958
18959 properties: {
18960
18961 /**
18962 * The value of mode is used to set the `aria-live` attribute
18963 * for the element that will be announced. Valid values are: `off`,
18964 * `polite` and `assertive`.
18965 */
18966 mode: {
18967 type: String,
18968 value: 'polite'
18969 },
18970
18971 _text: {
18972 type: String,
18973 value: ''
18974 }
18975 },
18976
18977 created: function() {
18978 if (!Polymer.IronA11yAnnouncer.instance) {
18979 Polymer.IronA11yAnnouncer.instance = this;
18980 }
18981
18982 document.body.addEventListener('iron-announce', this._onIronAnnounce.b ind(this));
18983 },
18984
18985 /**
18986 * Cause a text string to be announced by screen readers.
18987 *
18988 * @param {string} text The text that should be announced.
18989 */
18990 announce: function(text) {
18991 this._text = '';
18992 this.async(function() {
18993 this._text = text;
18994 }, 100);
18995 },
18996
18997 _onIronAnnounce: function(event) {
18998 if (event.detail && event.detail.text) {
18999 this.announce(event.detail.text);
19000 }
19001 }
19002 });
19003
19004 Polymer.IronA11yAnnouncer.instance = null;
19005
19006 Polymer.IronA11yAnnouncer.requestAvailability = function() {
19007 if (!Polymer.IronA11yAnnouncer.instance) {
19008 Polymer.IronA11yAnnouncer.instance = document.createElement('iron-a11y -announcer');
19009 }
19010
19011 document.body.appendChild(Polymer.IronA11yAnnouncer.instance);
19012 };
19013 })();
19014
19015 </script>
19016 </dom-module>
19017 <script>
19018
19019 /*
19020 `<iron-input>` adds two-way binding and custom validators using `Polymer.IronVal idatorBehavior`
19021 to `<input>`.
19022
19023 ### Two-way binding
19024
19025 By default you can only get notified of changes to an `input`'s `value` due to u ser input:
19026
19027 <input value="{{myValue::input}}">
19028
19029 `iron-input` adds the `bind-value` property that mirrors the `value` property, a nd can be used
19030 for two-way data binding. `bind-value` will notify if it is changed either by us er input or by script.
19031
19032 <input is="iron-input" bind-value="{{myValue}}">
19033
19034 ### Custom validators
19035
19036 You can use custom validators that implement `Polymer.IronValidatorBehavior` wit h `<iron-input>`.
19037
19038 <input is="iron-input" validator="my-custom-validator">
19039
19040 ### Stopping invalid input
19041
19042 It may be desirable to only allow users to enter certain characters. You can use the
19043 `prevent-invalid-input` and `allowed-pattern` attributes together to accomplish this. This feature
19044 is separate from validation, and `allowed-pattern` does not affect how the input is validated.
19045
19046 <!-- only allow characters that match [0-9] -->
19047 <input is="iron-input" prevent-invalid-input allowed-pattern="[0-9]">
19048
19049 @hero hero.svg
19050 @demo demo/index.html
19051 */
19052
19053 Polymer({
19054
19055 is: 'iron-input',
19056
19057 extends: 'input',
19058
19059 behaviors: [
19060 Polymer.IronValidatableBehavior
19061 ],
19062
19063 properties: {
19064
19065 /**
19066 * Use this property instead of `value` for two-way data binding.
19067 */
19068 bindValue: {
19069 observer: '_bindValueChanged',
19070 type: String
19071 },
19072
19073 /**
19074 * Set to true to prevent the user from entering invalid input. If `allowe dPattern` is set,
19075 * any character typed by the user will be matched against that pattern, a nd rejected if it's not a match.
19076 * Pasted input will have each character checked individually; if any char acter
19077 * doesn't match `allowedPattern`, the entire pasted string will be reject ed.
19078 * If `allowedPattern` is not set, it will use the `type` attribute (only supported for `type=number`).
19079 */
19080 preventInvalidInput: {
19081 type: Boolean
19082 },
19083
19084 /**
19085 * Regular expression that list the characters allowed as input.
19086 * This pattern represents the allowed characters for the field; as the us er inputs text,
19087 * each individual character will be checked against the pattern (rather t han checking
19088 * the entire value as a whole). The recommended format should be a list o f allowed characters;
19089 * for example, `[a-zA-Z0-9.+-!;:]`
19090 */
19091 allowedPattern: {
19092 type: String,
19093 observer: "_allowedPatternChanged"
19094 },
19095
19096 _previousValidInput: {
19097 type: String,
19098 value: ''
19099 },
19100
19101 _patternAlreadyChecked: {
19102 type: Boolean,
19103 value: false
19104 }
19105
19106 },
19107
19108 listeners: {
19109 'input': '_onInput',
19110 'keypress': '_onKeypress'
19111 },
19112
19113 /** @suppress {checkTypes} */
19114 registered: function() {
19115 // Feature detect whether we need to patch dispatchEvent (i.e. on FF and I E).
19116 if (!this._canDispatchEventOnDisabled()) {
19117 this._origDispatchEvent = this.dispatchEvent;
19118 this.dispatchEvent = this._dispatchEventFirefoxIE;
19119 }
19120 },
19121
19122 created: function() {
19123 Polymer.IronA11yAnnouncer.requestAvailability();
19124 },
19125
19126 _canDispatchEventOnDisabled: function() {
19127 var input = document.createElement('input');
19128 var canDispatch = false;
19129 input.disabled = true;
19130
19131 input.addEventListener('feature-check-dispatch-event', function() {
19132 canDispatch = true;
19133 });
19134
19135 try {
19136 input.dispatchEvent(new Event('feature-check-dispatch-event'));
19137 } catch(e) {}
19138
19139 return canDispatch;
19140 },
19141
19142 _dispatchEventFirefoxIE: function() {
19143 // Due to Firefox bug, events fired on disabled form controls can throw
19144 // errors; furthermore, neither IE nor Firefox will actually dispatch
19145 // events from disabled form controls; as such, we toggle disable around
19146 // the dispatch to allow notifying properties to notify
19147 // See issue #47 for details
19148 var disabled = this.disabled;
19149 this.disabled = false;
19150 this._origDispatchEvent.apply(this, arguments);
19151 this.disabled = disabled;
19152 },
19153
19154 get _patternRegExp() {
19155 var pattern;
19156 if (this.allowedPattern) {
19157 pattern = new RegExp(this.allowedPattern);
19158 } else {
19159 switch (this.type) {
19160 case 'number':
19161 pattern = /[0-9.,e-]/;
19162 break;
19163 }
19164 }
19165 return pattern;
19166 },
19167
19168 ready: function() {
19169 this.bindValue = this.value;
19170 },
19171
19172 /**
19173 * @suppress {checkTypes}
19174 */
19175 _bindValueChanged: function() {
19176 if (this.value !== this.bindValue) {
19177 this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue;
19178 }
19179 // manually notify because we don't want to notify until after setting val ue
19180 this.fire('bind-value-changed', {value: this.bindValue});
19181 },
19182
19183 _allowedPatternChanged: function() {
19184 // Force to prevent invalid input when an `allowed-pattern` is set
19185 this.preventInvalidInput = this.allowedPattern ? true : false;
19186 },
19187
19188 _onInput: function() {
19189 // Need to validate each of the characters pasted if they haven't
19190 // been validated inside `_onKeypress` already.
19191 if (this.preventInvalidInput && !this._patternAlreadyChecked) {
19192 var valid = this._checkPatternValidity();
19193 if (!valid) {
19194 this._announceInvalidCharacter('Invalid string of characters not enter ed.');
19195 this.value = this._previousValidInput;
19196 }
19197 }
19198
19199 this.bindValue = this.value;
19200 this._previousValidInput = this.value;
19201 this._patternAlreadyChecked = false;
19202 },
19203
19204 _isPrintable: function(event) {
19205 // What a control/printable character is varies wildly based on the browse r.
19206 // - most control characters (arrows, backspace) do not send a `keypress` event
19207 // in Chrome, but the *do* on Firefox
19208 // - in Firefox, when they do send a `keypress` event, control chars have
19209 // a charCode = 0, keyCode = xx (for ex. 40 for down arrow)
19210 // - printable characters always send a keypress event.
19211 // - in Firefox, printable chars always have a keyCode = 0. In Chrome, the keyCode
19212 // always matches the charCode.
19213 // None of this makes any sense.
19214
19215 // For these keys, ASCII code == browser keycode.
19216 var anyNonPrintable =
19217 (event.keyCode == 8) || // backspace
19218 (event.keyCode == 9) || // tab
19219 (event.keyCode == 13) || // enter
19220 (event.keyCode == 27); // escape
19221
19222 // For these keys, make sure it's a browser keycode and not an ASCII code.
19223 var mozNonPrintable =
19224 (event.keyCode == 19) || // pause
19225 (event.keyCode == 20) || // caps lock
19226 (event.keyCode == 45) || // insert
19227 (event.keyCode == 46) || // delete
19228 (event.keyCode == 144) || // num lock
19229 (event.keyCode == 145) || // scroll lock
19230 (event.keyCode > 32 && event.keyCode < 41) || // page up/down, end, ho me, arrows
19231 (event.keyCode > 111 && event.keyCode < 124); // fn keys
19232
19233 return !anyNonPrintable && !(event.charCode == 0 && mozNonPrintable);
19234 },
19235
19236 _onKeypress: function(event) {
19237 if (!this.preventInvalidInput && this.type !== 'number') {
19238 return;
19239 }
19240 var regexp = this._patternRegExp;
19241 if (!regexp) {
19242 return;
19243 }
19244
19245 // Handle special keys and backspace
19246 if (event.metaKey || event.ctrlKey || event.altKey)
19247 return;
19248
19249 // Check the pattern either here or in `_onInput`, but not in both.
19250 this._patternAlreadyChecked = true;
19251
19252 var thisChar = String.fromCharCode(event.charCode);
19253 if (this._isPrintable(event) && !regexp.test(thisChar)) {
19254 event.preventDefault();
19255 this._announceInvalidCharacter('Invalid character ' + thisChar + ' not e ntered.');
19256 }
19257 },
19258
19259 _checkPatternValidity: function() {
19260 var regexp = this._patternRegExp;
19261 if (!regexp) {
19262 return true;
19263 }
19264 for (var i = 0; i < this.value.length; i++) {
19265 if (!regexp.test(this.value[i])) {
19266 return false;
19267 }
19268 }
19269 return true;
19270 },
19271
19272 /**
19273 * Returns true if `value` is valid. The validator provided in `validator` w ill be used first,
19274 * then any constraints.
19275 * @return {boolean} True if the value is valid.
19276 */
19277 validate: function() {
19278 // First, check what the browser thinks. Some inputs (like type=number)
19279 // behave weirdly and will set the value to "" if something invalid is
19280 // entered, but will set the validity correctly.
19281 var valid = this.checkValidity();
19282
19283 // Only do extra checking if the browser thought this was valid.
19284 if (valid) {
19285 // Empty, required input is invalid
19286 if (this.required && this.value === '') {
19287 valid = false;
19288 } else if (this.hasValidator()) {
19289 valid = Polymer.IronValidatableBehavior.validate.call(this, this.value );
19290 }
19291 }
19292
19293 this.invalid = !valid;
19294 this.fire('iron-input-validate');
19295 return valid;
19296 },
19297
19298 _announceInvalidCharacter: function(message) {
19299 this.fire('iron-announce', { text: message });
19300 }
19301 });
19302
19303 /*
19304 The `iron-input-validate` event is fired whenever `validate()` is called.
19305 @event iron-input-validate
19306 */
19307
19308 </script>
19309 <script>
19310
19311 // Generate unique, monotonically increasing IDs for labels (needed by
19312 // aria-labelledby) and add-ons.
19313 Polymer.PaperInputHelper = {};
19314 Polymer.PaperInputHelper.NextLabelID = 1;
19315 Polymer.PaperInputHelper.NextAddonID = 1;
19316
19317 /**
19318 * Use `Polymer.PaperInputBehavior` to implement inputs with `<paper-input-con tainer>`. This
19319 * behavior is implemented by `<paper-input>`. It exposes a number of properti es from
19320 * `<paper-input-container>` and `<input is="iron-input">` and they should be bound in your
19321 * template.
19322 *
19323 * The input element can be accessed by the `inputElement` property if you nee d to access
19324 * properties or methods that are not exposed.
19325 * @polymerBehavior Polymer.PaperInputBehavior
19326 */
19327 Polymer.PaperInputBehaviorImpl = {
19328
19329 properties: {
19330 /**
19331 * Fired when the input changes due to user interaction.
19332 *
19333 * @event change
19334 */
19335
19336 /**
19337 * The label for this input. If you're using PaperInputBehavior to
19338 * implement your own paper-input-like element, bind this to
19339 * `<label>`'s content and `hidden` property, e.g.
19340 * `<label hidden$="[[!label]]">[[label]]</label>` in your `template`
19341 */
19342 label: {
19343 type: String
19344 },
19345
19346 /**
19347 * The value for this input. If you're using PaperInputBehavior to
19348 * implement your own paper-input-like element, bind this to
19349 * the `<input is="iron-input">`'s `bindValue`
19350 * property, or the value property of your input that is `notify:true`.
19351 */
19352 value: {
19353 notify: true,
19354 type: String
19355 },
19356
19357 /**
19358 * Set to true to disable this input. If you're using PaperInputBehavior t o
19359 * implement your own paper-input-like element, bind this to
19360 * both the `<paper-input-container>`'s and the input's `disabled` propert y.
19361 */
19362 disabled: {
19363 type: Boolean,
19364 value: false
19365 },
19366
19367 /**
19368 * Returns true if the value is invalid. If you're using PaperInputBehavio r to
19369 * implement your own paper-input-like element, bind this to both the
19370 * `<paper-input-container>`'s and the input's `invalid` property.
19371 *
19372 * If `autoValidate` is true, the `invalid` attribute is managed automatic ally,
19373 * which can clobber attempts to manage it manually.
19374 */
19375 invalid: {
19376 type: Boolean,
19377 value: false,
19378 notify: true
19379 },
19380
19381 /**
19382 * Set to true to prevent the user from entering invalid input. If you're
19383 * using PaperInputBehavior to implement your own paper-input-like elemen t,
19384 * bind this to `<input is="iron-input">`'s `preventInvalidInput` property .
19385 */
19386 preventInvalidInput: {
19387 type: Boolean
19388 },
19389
19390 /**
19391 * Set this to specify the pattern allowed by `preventInvalidInput`. If
19392 * you're using PaperInputBehavior to implement your own paper-input-like
19393 * element, bind this to the `<input is="iron-input">`'s `allowedPattern`
19394 * property.
19395 */
19396 allowedPattern: {
19397 type: String
19398 },
19399
19400 /**
19401 * The type of the input. The supported types are `text`, `number` and `pa ssword`.
19402 * If you're using PaperInputBehavior to implement your own paper-input-li ke element,
19403 * bind this to the `<input is="iron-input">`'s `type` property.
19404 */
19405 type: {
19406 type: String
19407 },
19408
19409 /**
19410 * The datalist of the input (if any). This should match the id of an exis ting `<datalist>`.
19411 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19412 * element, bind this to the `<input is="iron-input">`'s `list` property.
19413 */
19414 list: {
19415 type: String
19416 },
19417
19418 /**
19419 * A pattern to validate the `input` with. If you're using PaperInputBehav ior to
19420 * implement your own paper-input-like element, bind this to
19421 * the `<input is="iron-input">`'s `pattern` property.
19422 */
19423 pattern: {
19424 type: String
19425 },
19426
19427 /**
19428 * Set to true to mark the input as required. If you're using PaperInputBe havior to
19429 * implement your own paper-input-like element, bind this to
19430 * the `<input is="iron-input">`'s `required` property.
19431 */
19432 required: {
19433 type: Boolean,
19434 value: false
19435 },
19436
19437 /**
19438 * The error message to display when the input is invalid. If you're using
19439 * PaperInputBehavior to implement your own paper-input-like element,
19440 * bind this to the `<paper-input-error>`'s content, if using.
19441 */
19442 errorMessage: {
19443 type: String
19444 },
19445
19446 /**
19447 * Set to true to show a character counter.
19448 */
19449 charCounter: {
19450 type: Boolean,
19451 value: false
19452 },
19453
19454 /**
19455 * Set to true to disable the floating label. If you're using PaperInputBe havior to
19456 * implement your own paper-input-like element, bind this to
19457 * the `<paper-input-container>`'s `noLabelFloat` property.
19458 */
19459 noLabelFloat: {
19460 type: Boolean,
19461 value: false
19462 },
19463
19464 /**
19465 * Set to true to always float the label. If you're using PaperInputBehavi or to
19466 * implement your own paper-input-like element, bind this to
19467 * the `<paper-input-container>`'s `alwaysFloatLabel` property.
19468 */
19469 alwaysFloatLabel: {
19470 type: Boolean,
19471 value: false
19472 },
19473
19474 /**
19475 * Set to true to auto-validate the input value. If you're using PaperInpu tBehavior to
19476 * implement your own paper-input-like element, bind this to
19477 * the `<paper-input-container>`'s `autoValidate` property.
19478 */
19479 autoValidate: {
19480 type: Boolean,
19481 value: false
19482 },
19483
19484 /**
19485 * Name of the validator to use. If you're using PaperInputBehavior to
19486 * implement your own paper-input-like element, bind this to
19487 * the `<input is="iron-input">`'s `validator` property.
19488 */
19489 validator: {
19490 type: String
19491 },
19492
19493 // HTMLInputElement attributes for binding if needed
19494
19495 /**
19496 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19497 * element, bind this to the `<input is="iron-input">`'s `autocomplete` pr operty.
19498 */
19499 autocomplete: {
19500 type: String,
19501 value: 'off'
19502 },
19503
19504 /**
19505 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19506 * element, bind this to the `<input is="iron-input">`'s `autofocus` prope rty.
19507 */
19508 autofocus: {
19509 type: Boolean,
19510 observer: '_autofocusChanged'
19511 },
19512
19513 /**
19514 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19515 * element, bind this to the `<input is="iron-input">`'s `inputmode` prope rty.
19516 */
19517 inputmode: {
19518 type: String
19519 },
19520
19521 /**
19522 * The minimum length of the input value.
19523 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19524 * element, bind this to the `<input is="iron-input">`'s `minlength` prope rty.
19525 */
19526 minlength: {
19527 type: Number
19528 },
19529
19530 /**
19531 * The maximum length of the input value.
19532 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19533 * element, bind this to the `<input is="iron-input">`'s `maxlength` prope rty.
19534 */
19535 maxlength: {
19536 type: Number
19537 },
19538
19539 /**
19540 * The minimum (numeric or date-time) input value.
19541 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19542 * element, bind this to the `<input is="iron-input">`'s `min` property.
19543 */
19544 min: {
19545 type: String
19546 },
19547
19548 /**
19549 * The maximum (numeric or date-time) input value.
19550 * Can be a String (e.g. `"2000-1-1"`) or a Number (e.g. `2`).
19551 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19552 * element, bind this to the `<input is="iron-input">`'s `max` property.
19553 */
19554 max: {
19555 type: String
19556 },
19557
19558 /**
19559 * Limits the numeric or date-time increments.
19560 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19561 * element, bind this to the `<input is="iron-input">`'s `step` property.
19562 */
19563 step: {
19564 type: String
19565 },
19566
19567 /**
19568 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19569 * element, bind this to the `<input is="iron-input">`'s `name` property.
19570 */
19571 name: {
19572 type: String
19573 },
19574
19575 /**
19576 * A placeholder string in addition to the label. If this is set, the labe l will always float.
19577 */
19578 placeholder: {
19579 type: String,
19580 // need to set a default so _computeAlwaysFloatLabel is run
19581 value: ''
19582 },
19583
19584 /**
19585 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19586 * element, bind this to the `<input is="iron-input">`'s `readonly` proper ty.
19587 */
19588 readonly: {
19589 type: Boolean,
19590 value: false
19591 },
19592
19593 /**
19594 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19595 * element, bind this to the `<input is="iron-input">`'s `size` property.
19596 */
19597 size: {
19598 type: Number
19599 },
19600
19601 // Nonstandard attributes for binding if needed
19602
19603 /**
19604 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19605 * element, bind this to the `<input is="iron-input">`'s `autocapitalize` property.
19606 */
19607 autocapitalize: {
19608 type: String,
19609 value: 'none'
19610 },
19611
19612 /**
19613 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19614 * element, bind this to the `<input is="iron-input">`'s `autocorrect` pro perty.
19615 */
19616 autocorrect: {
19617 type: String,
19618 value: 'off'
19619 },
19620
19621 /**
19622 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19623 * element, bind this to the `<input is="iron-input">`'s `autosave` proper ty,
19624 * used with type=search.
19625 */
19626 autosave: {
19627 type: String
19628 },
19629
19630 /**
19631 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19632 * element, bind this to the `<input is="iron-input">`'s `results` propert y,
19633 * used with type=search.
19634 */
19635 results: {
19636 type: Number
19637 },
19638
19639 /**
19640 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19641 * element, bind this to the `<input is="iron-input">`'s `accept` property ,
19642 * used with type=file.
19643 */
19644 accept: {
19645 type: String
19646 },
19647
19648 /**
19649 * If you're using PaperInputBehavior to implement your own paper-input-li ke
19650 * element, bind this to the`<input is="iron-input">`'s `multiple` propert y,
19651 * used with type=file.
19652 */
19653 multiple: {
19654 type: Boolean
19655 },
19656
19657 _ariaDescribedBy: {
19658 type: String,
19659 value: ''
19660 },
19661
19662 _ariaLabelledBy: {
19663 type: String,
19664 value: ''
19665 }
19666
19667 },
19668
19669 listeners: {
19670 'addon-attached': '_onAddonAttached',
19671 },
19672
19673 keyBindings: {
19674 'shift+tab:keydown': '_onShiftTabDown'
19675 },
19676
19677 hostAttributes: {
19678 tabindex: 0
19679 },
19680
19681 /**
19682 * Returns a reference to the input element.
19683 */
19684 get inputElement() {
19685 return this.$.input;
19686 },
19687
19688 /**
19689 * Returns a reference to the focusable element.
19690 */
19691 get _focusableElement() {
19692 return this.inputElement;
19693 },
19694
19695 registered: function() {
19696 // These types have some default placeholder text; overlapping
19697 // the label on top of it looks terrible. Auto-float the label in this cas e.
19698 this._typesThatHaveText = ["date", "datetime", "datetime-local", "month",
19699 "time", "week", "file"];
19700 },
19701
19702 attached: function() {
19703 this._updateAriaLabelledBy();
19704
19705 if (this.inputElement &&
19706 this._typesThatHaveText.indexOf(this.inputElement.type) !== -1) {
19707 this.alwaysFloatLabel = true;
19708 }
19709 },
19710
19711 _appendStringWithSpace: function(str, more) {
19712 if (str) {
19713 str = str + ' ' + more;
19714 } else {
19715 str = more;
19716 }
19717 return str;
19718 },
19719
19720 _onAddonAttached: function(event) {
19721 var target = event.path ? event.path[0] : event.target;
19722 if (target.id) {
19723 this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedB y, target.id);
19724 } else {
19725 var id = 'paper-input-add-on-' + Polymer.PaperInputHelper.NextAddonID++;
19726 target.id = id;
19727 this._ariaDescribedBy = this._appendStringWithSpace(this._ariaDescribedB y, id);
19728 }
19729 },
19730
19731 /**
19732 * Validates the input element and sets an error style if needed.
19733 *
19734 * @return {boolean}
19735 */
19736 validate: function() {
19737 return this.inputElement.validate();
19738 },
19739
19740 /**
19741 * Forward focus to inputElement. Overriden from IronControlState.
19742 */
19743 _focusBlurHandler: function(event) {
19744 Polymer.IronControlState._focusBlurHandler.call(this, event);
19745
19746 // Forward the focus to the nested input.
19747 if (this.focused && !this._shiftTabPressed)
19748 this._focusableElement.focus();
19749 },
19750
19751 /**
19752 * Handler that is called when a shift+tab keypress is detected by the menu.
19753 *
19754 * @param {CustomEvent} event A key combination event.
19755 */
19756 _onShiftTabDown: function(event) {
19757 var oldTabIndex = this.getAttribute('tabindex');
19758 this._shiftTabPressed = true;
19759 this.setAttribute('tabindex', '-1');
19760 this.async(function() {
19761 this.setAttribute('tabindex', oldTabIndex);
19762 this._shiftTabPressed = false;
19763 }, 1);
19764 },
19765
19766 /**
19767 * If `autoValidate` is true, then validates the element.
19768 */
19769 _handleAutoValidate: function() {
19770 if (this.autoValidate)
19771 this.validate();
19772 },
19773
19774 /**
19775 * Restores the cursor to its original position after updating the value.
19776 * @param {string} newValue The value that should be saved.
19777 */
19778 updateValueAndPreserveCaret: function(newValue) {
19779 // Not all elements might have selection, and even if they have the
19780 // right properties, accessing them might throw an exception (like for
19781 // <input type=number>)
19782 try {
19783 var start = this.inputElement.selectionStart;
19784 this.value = newValue;
19785
19786 // The cursor automatically jumps to the end after re-setting the value,
19787 // so restore it to its original position.
19788 this.inputElement.selectionStart = start;
19789 this.inputElement.selectionEnd = start;
19790 } catch (e) {
19791 // Just set the value and give up on the caret.
19792 this.value = newValue;
19793 }
19794 },
19795
19796 _computeAlwaysFloatLabel: function(alwaysFloatLabel, placeholder) {
19797 return placeholder || alwaysFloatLabel;
19798 },
19799
19800 _updateAriaLabelledBy: function() {
19801 var label = Polymer.dom(this.root).querySelector('label');
19802 if (!label) {
19803 this._ariaLabelledBy = '';
19804 return;
19805 }
19806 var labelledBy;
19807 if (label.id) {
19808 labelledBy = label.id;
19809 } else {
19810 labelledBy = 'paper-input-label-' + Polymer.PaperInputHelper.NextLabelID ++;
19811 label.id = labelledBy;
19812 }
19813 this._ariaLabelledBy = labelledBy;
19814 },
19815
19816 _onChange:function(event) {
19817 // In the Shadow DOM, the `change` event is not leaked into the
19818 // ancestor tree, so we must do this manually.
19819 // See https://w3c.github.io/webcomponents/spec/shadow/#events-that-are-no t-leaked-into-ancestor-trees.
19820 if (this.shadowRoot) {
19821 this.fire(event.type, {sourceEvent: event}, {
19822 node: this,
19823 bubbles: event.bubbles,
19824 cancelable: event.cancelable
19825 });
19826 }
19827 },
19828
19829 _autofocusChanged: function() {
19830 // Firefox doesn't respect the autofocus attribute if it's applied after
19831 // the page is loaded (Chrome/WebKit do respect it), preventing an
19832 // autofocus attribute specified in markup from taking effect when the
19833 // element is upgraded. As a workaround, if the autofocus property is set,
19834 // and the focus hasn't already been moved elsewhere, we take focus.
19835 if (this.autofocus && this._focusableElement) {
19836
19837 // In IE 11, the default document.activeElement can be the page's
19838 // outermost html element, but there are also cases (under the
19839 // polyfill?) in which the activeElement is not a real HTMLElement, but
19840 // just a plain object. We identify the latter case as having no valid
19841 // activeElement.
19842 var activeElement = document.activeElement;
19843 var isActiveElementValid = activeElement instanceof HTMLElement;
19844
19845 // Has some other element has already taken the focus?
19846 var isSomeElementActive = isActiveElementValid &&
19847 activeElement !== document.body &&
19848 activeElement !== document.documentElement; /* IE 11 */
19849 if (!isSomeElementActive) {
19850 // No specific element has taken the focus yet, so we can take it.
19851 this._focusableElement.focus();
19852 }
19853 }
19854 }
19855 }
19856
19857 /** @polymerBehavior */
19858 Polymer.PaperInputBehavior = [
19859 Polymer.IronControlState,
19860 Polymer.IronA11yKeysBehavior,
19861 Polymer.PaperInputBehaviorImpl
19862 ];
19863 </script>
19864 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400, 300,300italic,400italic,500,500italic,700,700italic">
19865 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono :400,700">
19866 <style is="custom-style">
19867
19868 :root {
19869
19870 /* Shared Styles */
19871 --paper-font-common-base: {
19872 font-family: 'Roboto', 'Noto', sans-serif;
19873 -webkit-font-smoothing: antialiased;
19874 };
19875
19876 --paper-font-common-code: {
19877 font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace;
19878 -webkit-font-smoothing: antialiased;
19879 };
19880
19881 --paper-font-common-expensive-kerning: {
19882 text-rendering: optimizeLegibility;
19883 };
19884
19885 --paper-font-common-nowrap: {
19886 white-space: nowrap;
19887 overflow: hidden;
19888 text-overflow: ellipsis;
19889 };
19890
19891 /* Material Font Styles */
19892
19893 --paper-font-display4: {
19894 @apply(--paper-font-common-base);
19895 @apply(--paper-font-common-nowrap);
19896
19897 font-size: 112px;
19898 font-weight: 300;
19899 letter-spacing: -.044em;
19900 line-height: 120px;
19901 };
19902
19903 --paper-font-display3: {
19904 @apply(--paper-font-common-base);
19905 @apply(--paper-font-common-nowrap);
19906
19907 font-size: 56px;
19908 font-weight: 400;
19909 letter-spacing: -.026em;
19910 line-height: 60px;
19911 };
19912
19913 --paper-font-display2: {
19914 @apply(--paper-font-common-base);
19915
19916 font-size: 45px;
19917 font-weight: 400;
19918 letter-spacing: -.018em;
19919 line-height: 48px;
19920 };
19921
19922 --paper-font-display1: {
19923 @apply(--paper-font-common-base);
19924
19925 font-size: 34px;
19926 font-weight: 400;
19927 letter-spacing: -.01em;
19928 line-height: 40px;
19929 };
19930
19931 --paper-font-headline: {
19932 @apply(--paper-font-common-base);
19933
19934 font-size: 24px;
19935 font-weight: 400;
19936 letter-spacing: -.012em;
19937 line-height: 32px;
19938 };
19939
19940 --paper-font-title: {
19941 @apply(--paper-font-common-base);
19942 @apply(--paper-font-common-nowrap);
19943
19944 font-size: 20px;
19945 font-weight: 500;
19946 line-height: 28px;
19947 };
19948
19949 --paper-font-subhead: {
19950 @apply(--paper-font-common-base);
19951
19952 font-size: 16px;
19953 font-weight: 400;
19954 line-height: 24px;
19955 };
19956
19957 --paper-font-body2: {
19958 @apply(--paper-font-common-base);
19959
19960 font-size: 14px;
19961 font-weight: 500;
19962 line-height: 24px;
19963 };
19964
19965 --paper-font-body1: {
19966 @apply(--paper-font-common-base);
19967
19968 font-size: 14px;
19969 font-weight: 400;
19970 line-height: 20px;
19971 };
19972
19973 --paper-font-caption: {
19974 @apply(--paper-font-common-base);
19975 @apply(--paper-font-common-nowrap);
19976
19977 font-size: 12px;
19978 font-weight: 400;
19979 letter-spacing: 0.011em;
19980 line-height: 20px;
19981 };
19982
19983 --paper-font-menu: {
19984 @apply(--paper-font-common-base);
19985 @apply(--paper-font-common-nowrap);
19986
19987 font-size: 13px;
19988 font-weight: 500;
19989 line-height: 24px;
19990 };
19991
19992 --paper-font-button: {
19993 @apply(--paper-font-common-base);
19994 @apply(--paper-font-common-nowrap);
19995
19996 font-size: 14px;
19997 font-weight: 500;
19998 letter-spacing: 0.018em;
19999 line-height: 24px;
20000 text-transform: uppercase;
20001 };
20002
20003 --paper-font-code2: {
20004 @apply(--paper-font-common-code);
20005
20006 font-size: 14px;
20007 font-weight: 700;
20008 line-height: 20px;
20009 };
20010
20011 --paper-font-code1: {
20012 @apply(--paper-font-common-code);
20013
20014 font-size: 14px;
20015 font-weight: 500;
20016 line-height: 20px;
20017 };
20018
20019 }
20020
20021 </style>
20022 <script>
20023
20024 /**
20025 * Use `Polymer.PaperInputAddonBehavior` to implement an add-on for `<paper-in put-container>`. A
20026 * add-on appears below the input, and may display information based on the in put value and
20027 * validity such as a character counter or an error message.
20028 * @polymerBehavior
20029 */
20030 Polymer.PaperInputAddonBehavior = {
20031
20032 hostAttributes: {
20033 'add-on': ''
20034 },
20035
20036 attached: function() {
20037 this.fire('addon-attached');
20038 },
20039
20040 /**
20041 * The function called by `<paper-input-container>` when the input value or validity changes.
20042 * @param {{
20043 * inputElement: (Element|undefined),
20044 * value: (string|undefined),
20045 * invalid: boolean
20046 * }} state -
20047 * inputElement: The input element.
20048 * value: The input value.
20049 * invalid: True if the input value is invalid.
20050 */
20051 update: function(state) {
20052 }
20053
20054 };
20055
20056 </script>
20057
20058
20059 <dom-module id="paper-input-char-counter" assetpath="/res/imp/bower_components/p aper-input/">
20060 <template>
20061 <style>
20062 :host {
20063 display: inline-block;
20064 float: right;
20065
20066 @apply(--paper-font-caption);
20067 @apply(--paper-input-char-counter);
20068 }
20069
20070 :host([hidden]) {
20071 display: none !important;
20072 }
20073
20074 :host-context([dir="rtl"]) {
20075 float: left;
20076 }
20077 </style>
20078
20079 <span>[[_charCounterStr]]</span>
20080 </template>
20081 </dom-module>
20082
20083 <script>
20084 Polymer({
20085 is: 'paper-input-char-counter',
20086
20087 behaviors: [
20088 Polymer.PaperInputAddonBehavior
20089 ],
20090
20091 properties: {
20092 _charCounterStr: {
20093 type: String,
20094 value: '0'
20095 }
20096 },
20097
20098 /**
20099 * This overrides the update function in PaperInputAddonBehavior.
20100 * @param {{
20101 * inputElement: (Element|undefined),
20102 * value: (string|undefined),
20103 * invalid: boolean
20104 * }} state -
20105 * inputElement: The input element.
20106 * value: The input value.
20107 * invalid: True if the input value is invalid.
20108 */
20109 update: function(state) {
20110 if (!state.inputElement) {
20111 return;
20112 }
20113
20114 state.value = state.value || '';
20115
20116 var counter = state.value.toString().length.toString();
20117
20118 if (state.inputElement.hasAttribute('maxlength')) {
20119 counter += '/' + state.inputElement.getAttribute('maxlength');
20120 }
20121
20122 this._charCounterStr = counter;
20123 }
20124 });
20125 </script>
20126
20127
20128 <dom-module id="paper-input-container" assetpath="/res/imp/bower_components/pape r-input/">
20129 <template>
20130 <style>
20131 :host {
20132 display: block;
20133 padding: 8px 0;
20134
20135 @apply(--paper-input-container);
20136 }
20137
20138 :host([inline]) {
20139 display: inline-block;
20140 }
20141
20142 :host([disabled]) {
20143 pointer-events: none;
20144 opacity: 0.33;
20145
20146 @apply(--paper-input-container-disabled);
20147 }
20148
20149 :host([hidden]) {
20150 display: none !important;
20151 }
20152
20153 .floated-label-placeholder {
20154 @apply(--paper-font-caption);
20155 }
20156
20157 .underline {
20158 position: relative;
20159 }
20160
20161 .focused-line {
20162 @apply(--layout-fit);
20163
20164 background: var(--paper-input-container-focus-color, --primary-color);
20165 height: 2px;
20166
20167 -webkit-transform-origin: center center;
20168 transform-origin: center center;
20169 -webkit-transform: scale3d(0,1,1);
20170 transform: scale3d(0,1,1);
20171
20172 @apply(--paper-input-container-underline-focus);
20173 }
20174
20175 .underline.is-highlighted .focused-line {
20176 -webkit-transform: none;
20177 transform: none;
20178 -webkit-transition: -webkit-transform 0.25s;
20179 transition: transform 0.25s;
20180
20181 @apply(--paper-transition-easing);
20182 }
20183
20184 .underline.is-invalid .focused-line {
20185 background: var(--paper-input-container-invalid-color, --error-color);
20186 -webkit-transform: none;
20187 transform: none;
20188 -webkit-transition: -webkit-transform 0.25s;
20189 transition: transform 0.25s;
20190
20191 @apply(--paper-transition-easing);
20192 }
20193
20194 .unfocused-line {
20195 @apply(--layout-fit);
20196
20197 background: var(--paper-input-container-color, --secondary-text-color);
20198 height: 1px;
20199
20200 @apply(--paper-input-container-underline);
20201 }
20202
20203 :host([disabled]) .unfocused-line {
20204 border-bottom: 1px dashed;
20205 border-color: var(--paper-input-container-color, --secondary-text-color) ;
20206 background: transparent;
20207
20208 @apply(--paper-input-container-underline-disabled);
20209 }
20210
20211 .label-and-input-container {
20212 @apply(--layout-flex-auto);
20213 @apply(--layout-relative);
20214
20215 width: 100%;
20216 max-width: 100%;
20217 }
20218
20219 .input-content {
20220 @apply(--layout-horizontal);
20221 @apply(--layout-center);
20222
20223 position: relative;
20224 }
20225
20226 .input-content ::content label,
20227 .input-content ::content .paper-input-label {
20228 position: absolute;
20229 top: 0;
20230 right: 0;
20231 left: 0;
20232 width: 100%;
20233 font: inherit;
20234 color: var(--paper-input-container-color, --secondary-text-color);
20235 -webkit-transition: -webkit-transform 0.25s, width 0.25s;
20236 transition: transform 0.25s, width 0.25s;
20237 -webkit-transform-origin: left top;
20238 transform-origin: left top;
20239
20240 @apply(--paper-font-common-nowrap);
20241 @apply(--paper-font-subhead);
20242 @apply(--paper-input-container-label);
20243 @apply(--paper-transition-easing);
20244 }
20245
20246 .input-content.label-is-floating ::content label,
20247 .input-content.label-is-floating ::content .paper-input-label {
20248 -webkit-transform: translateY(-75%) scale(0.75);
20249 transform: translateY(-75%) scale(0.75);
20250
20251 /* Since we scale to 75/100 of the size, we actually have 100/75 of the
20252 original space now available */
20253 width: 133%;
20254
20255 @apply(--paper-input-container-label-floating);
20256 }
20257
20258 :host-context([dir="rtl"]) .input-content.label-is-floating ::content labe l,
20259 :host-context([dir="rtl"]) .input-content.label-is-floating ::content .pap er-input-label {
20260 /* TODO(noms): Figure out why leaving the width at 133% before the anima tion
20261 * actually makes
20262 * it wider on the right side, not left side, as you would expect in RTL */
20263 width: 100%;
20264 -webkit-transform-origin: right top;
20265 transform-origin: right top;
20266 }
20267
20268 .input-content.label-is-highlighted ::content label,
20269 .input-content.label-is-highlighted ::content .paper-input-label {
20270 color: var(--paper-input-container-focus-color, --primary-color);
20271
20272 @apply(--paper-input-container-label-focus);
20273 }
20274
20275 .input-content.is-invalid ::content label,
20276 .input-content.is-invalid ::content .paper-input-label {
20277 color: var(--paper-input-container-invalid-color, --error-color);
20278 }
20279
20280 .input-content.label-is-hidden ::content label,
20281 .input-content.label-is-hidden ::content .paper-input-label {
20282 visibility: hidden;
20283 }
20284
20285 .input-content ::content input,
20286 .input-content ::content textarea,
20287 .input-content ::content iron-autogrow-textarea,
20288 .input-content ::content .paper-input-input {
20289 position: relative; /* to make a stacking context */
20290 outline: none;
20291 box-shadow: none;
20292 padding: 0;
20293 width: 100%;
20294 max-width: 100%;
20295 background: transparent;
20296 border: none;
20297 color: var(--paper-input-container-input-color, --primary-text-color);
20298 -webkit-appearance: none;
20299 text-align: inherit;
20300
20301 @apply(--paper-font-subhead);
20302 @apply(--paper-input-container-input);
20303 }
20304
20305 ::content [prefix] {
20306 @apply(--paper-font-subhead);
20307
20308 @apply(--paper-input-prefix);
20309 @apply(--layout-flex-none);
20310 }
20311
20312 ::content [suffix] {
20313 @apply(--paper-font-subhead);
20314
20315 @apply(--paper-input-suffix);
20316 @apply(--layout-flex-none);
20317 }
20318
20319 /* Firefox sets a min-width on the input, which can cause layout issues */
20320 .input-content ::content input {
20321 min-width: 0;
20322 }
20323
20324 .input-content ::content textarea {
20325 resize: none;
20326 }
20327
20328 .add-on-content {
20329 position: relative;
20330 }
20331
20332 .add-on-content.is-invalid ::content * {
20333 color: var(--paper-input-container-invalid-color, --error-color);
20334 }
20335
20336 .add-on-content.is-highlighted ::content * {
20337 color: var(--paper-input-container-focus-color, --primary-color);
20338 }
20339 </style>
20340
20341 <template is="dom-if" if="[[!noLabelFloat]]">
20342 <div class="floated-label-placeholder" aria-hidden="true">&nbsp;</div>
20343 </template>
20344
20345 <div class$="[[_computeInputContentClass(noLabelFloat,alwaysFloatLabel,focus ed,invalid,_inputHasContent)]]">
20346 <content select="[prefix]" id="prefix"></content>
20347
20348 <div class="label-and-input-container" id="labelAndInputContainer">
20349 <content select=":not([add-on]):not([prefix]):not([suffix])"></content>
20350 </div>
20351
20352 <content select="[suffix]"></content>
20353 </div>
20354
20355 <div class$="[[_computeUnderlineClass(focused,invalid)]]">
20356 <div class="unfocused-line"></div>
20357 <div class="focused-line"></div>
20358 </div>
20359
20360 <div class$="[[_computeAddOnContentClass(focused,invalid)]]">
20361 <content id="addOnContent" select="[add-on]"></content>
20362 </div>
20363 </template>
20364 </dom-module>
20365
20366 <script>
20367 Polymer({
20368 is: 'paper-input-container',
20369
20370 properties: {
20371 /**
20372 * Set to true to disable the floating label. The label disappears when th e input value is
20373 * not null.
20374 */
20375 noLabelFloat: {
20376 type: Boolean,
20377 value: false
20378 },
20379
20380 /**
20381 * Set to true to always float the floating label.
20382 */
20383 alwaysFloatLabel: {
20384 type: Boolean,
20385 value: false
20386 },
20387
20388 /**
20389 * The attribute to listen for value changes on.
20390 */
20391 attrForValue: {
20392 type: String,
20393 value: 'bind-value'
20394 },
20395
20396 /**
20397 * Set to true to auto-validate the input value when it changes.
20398 */
20399 autoValidate: {
20400 type: Boolean,
20401 value: false
20402 },
20403
20404 /**
20405 * True if the input is invalid. This property is set automatically when t he input value
20406 * changes if auto-validating, or when the `iron-input-validate` event is heard from a child.
20407 */
20408 invalid: {
20409 observer: '_invalidChanged',
20410 type: Boolean,
20411 value: false
20412 },
20413
20414 /**
20415 * True if the input has focus.
20416 */
20417 focused: {
20418 readOnly: true,
20419 type: Boolean,
20420 value: false,
20421 notify: true
20422 },
20423
20424 _addons: {
20425 type: Array
20426 // do not set a default value here intentionally - it will be initialize d lazily when a
20427 // distributed child is attached, which may occur before configuration f or this element
20428 // in polyfill.
20429 },
20430
20431 _inputHasContent: {
20432 type: Boolean,
20433 value: false
20434 },
20435
20436 _inputSelector: {
20437 type: String,
20438 value: 'input,textarea,.paper-input-input'
20439 },
20440
20441 _boundOnFocus: {
20442 type: Function,
20443 value: function() {
20444 return this._onFocus.bind(this);
20445 }
20446 },
20447
20448 _boundOnBlur: {
20449 type: Function,
20450 value: function() {
20451 return this._onBlur.bind(this);
20452 }
20453 },
20454
20455 _boundOnInput: {
20456 type: Function,
20457 value: function() {
20458 return this._onInput.bind(this);
20459 }
20460 },
20461
20462 _boundValueChanged: {
20463 type: Function,
20464 value: function() {
20465 return this._onValueChanged.bind(this);
20466 }
20467 }
20468 },
20469
20470 listeners: {
20471 'addon-attached': '_onAddonAttached',
20472 'iron-input-validate': '_onIronInputValidate'
20473 },
20474
20475 get _valueChangedEvent() {
20476 return this.attrForValue + '-changed';
20477 },
20478
20479 get _propertyForValue() {
20480 return Polymer.CaseMap.dashToCamelCase(this.attrForValue);
20481 },
20482
20483 get _inputElement() {
20484 return Polymer.dom(this).querySelector(this._inputSelector);
20485 },
20486
20487 get _inputElementValue() {
20488 return this._inputElement[this._propertyForValue] || this._inputElement.va lue;
20489 },
20490
20491 ready: function() {
20492 if (!this._addons) {
20493 this._addons = [];
20494 }
20495 this.addEventListener('focus', this._boundOnFocus, true);
20496 this.addEventListener('blur', this._boundOnBlur, true);
20497 },
20498
20499 attached: function() {
20500 if (this.attrForValue) {
20501 this._inputElement.addEventListener(this._valueChangedEvent, this._bound ValueChanged);
20502 } else {
20503 this.addEventListener('input', this._onInput);
20504 }
20505
20506 // Only validate when attached if the input already has a value.
20507 if (this._inputElementValue != '') {
20508 this._handleValueAndAutoValidate(this._inputElement);
20509 } else {
20510 this._handleValue(this._inputElement);
20511 }
20512 },
20513
20514 _onAddonAttached: function(event) {
20515 if (!this._addons) {
20516 this._addons = [];
20517 }
20518 var target = event.target;
20519 if (this._addons.indexOf(target) === -1) {
20520 this._addons.push(target);
20521 if (this.isAttached) {
20522 this._handleValue(this._inputElement);
20523 }
20524 }
20525 },
20526
20527 _onFocus: function() {
20528 this._setFocused(true);
20529 },
20530
20531 _onBlur: function() {
20532 this._setFocused(false);
20533 this._handleValueAndAutoValidate(this._inputElement);
20534 },
20535
20536 _onInput: function(event) {
20537 this._handleValueAndAutoValidate(event.target);
20538 },
20539
20540 _onValueChanged: function(event) {
20541 this._handleValueAndAutoValidate(event.target);
20542 },
20543
20544 _handleValue: function(inputElement) {
20545 var value = this._inputElementValue;
20546
20547 // type="number" hack needed because this.value is empty until it's valid
20548 if (value || value === 0 || (inputElement.type === 'number' && !inputEleme nt.checkValidity())) {
20549 this._inputHasContent = true;
20550 } else {
20551 this._inputHasContent = false;
20552 }
20553
20554 this.updateAddons({
20555 inputElement: inputElement,
20556 value: value,
20557 invalid: this.invalid
20558 });
20559 },
20560
20561 _handleValueAndAutoValidate: function(inputElement) {
20562 if (this.autoValidate) {
20563 var valid;
20564 if (inputElement.validate) {
20565 valid = inputElement.validate(this._inputElementValue);
20566 } else {
20567 valid = inputElement.checkValidity();
20568 }
20569 this.invalid = !valid;
20570 }
20571
20572 // Call this last to notify the add-ons.
20573 this._handleValue(inputElement);
20574 },
20575
20576 _onIronInputValidate: function(event) {
20577 this.invalid = this._inputElement.invalid;
20578 },
20579
20580 _invalidChanged: function() {
20581 if (this._addons) {
20582 this.updateAddons({invalid: this.invalid});
20583 }
20584 },
20585
20586 /**
20587 * Call this to update the state of add-ons.
20588 * @param {Object} state Add-on state.
20589 */
20590 updateAddons: function(state) {
20591 for (var addon, index = 0; addon = this._addons[index]; index++) {
20592 addon.update(state);
20593 }
20594 },
20595
20596 _computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, invalid, _inputHasContent) {
20597 var cls = 'input-content';
20598 if (!noLabelFloat) {
20599 var label = this.querySelector('label');
20600
20601 if (alwaysFloatLabel || _inputHasContent) {
20602 cls += ' label-is-floating';
20603 // If the label is floating, ignore any offsets that may have been
20604 // applied from a prefix element.
20605 this.$.labelAndInputContainer.style.position = 'static';
20606
20607 if (invalid) {
20608 cls += ' is-invalid';
20609 } else if (focused) {
20610 cls += " label-is-highlighted";
20611 }
20612 } else {
20613 // When the label is not floating, it should overlap the input element .
20614 if (label) {
20615 this.$.labelAndInputContainer.style.position = 'relative';
20616 }
20617 }
20618 } else {
20619 if (_inputHasContent) {
20620 cls += ' label-is-hidden';
20621 }
20622 }
20623 return cls;
20624 },
20625
20626 _computeUnderlineClass: function(focused, invalid) {
20627 var cls = 'underline';
20628 if (invalid) {
20629 cls += ' is-invalid';
20630 } else if (focused) {
20631 cls += ' is-highlighted'
20632 }
20633 return cls;
20634 },
20635
20636 _computeAddOnContentClass: function(focused, invalid) {
20637 var cls = 'add-on-content';
20638 if (invalid) {
20639 cls += ' is-invalid';
20640 } else if (focused) {
20641 cls += ' is-highlighted'
20642 }
20643 return cls;
20644 }
20645 });
20646 </script>
20647
20648
20649 <dom-module id="paper-input-error" assetpath="/res/imp/bower_components/paper-in put/">
20650 <template>
20651 <style>
20652 :host {
20653 display: inline-block;
20654 visibility: hidden;
20655
20656 color: var(--paper-input-container-invalid-color, --error-color);
20657
20658 @apply(--paper-font-caption);
20659 @apply(--paper-input-error);
20660 position: absolute;
20661 left:0;
20662 right:0;
20663 }
20664
20665 :host([invalid]) {
20666 visibility: visible;
20667 };
20668 </style>
20669
20670 <content></content>
20671 </template>
20672 </dom-module>
20673
20674 <script>
20675 Polymer({
20676 is: 'paper-input-error',
20677
20678 behaviors: [
20679 Polymer.PaperInputAddonBehavior
20680 ],
20681
20682 properties: {
20683 /**
20684 * True if the error is showing.
20685 */
20686 invalid: {
20687 readOnly: true,
20688 reflectToAttribute: true,
20689 type: Boolean
20690 }
20691 },
20692
20693 /**
20694 * This overrides the update function in PaperInputAddonBehavior.
20695 * @param {{
20696 * inputElement: (Element|undefined),
20697 * value: (string|undefined),
20698 * invalid: boolean
20699 * }} state -
20700 * inputElement: The input element.
20701 * value: The input value.
20702 * invalid: True if the input value is invalid.
20703 */
20704 update: function(state) {
20705 this._setInvalid(state.invalid);
20706 }
20707 });
20708 </script>
20709
20710
20711 <dom-module id="paper-input" assetpath="/res/imp/bower_components/paper-input/">
20712 <template>
20713 <style>
20714 :host {
20715 display: block;
20716 }
20717
20718 :host([hidden]) {
20719 display: none !important;
20720 }
20721
20722 input::-webkit-input-placeholder {
20723 color: var(--paper-input-container-color, --secondary-text-color);
20724 }
20725
20726 input:-moz-placeholder {
20727 color: var(--paper-input-container-color, --secondary-text-color);
20728 }
20729
20730 input::-moz-placeholder {
20731 color: var(--paper-input-container-color, --secondary-text-color);
20732 }
20733
20734 input:-ms-input-placeholder {
20735 color: var(--paper-input-container-color, --secondary-text-color);
20736 }
20737 </style>
20738
20739 <paper-input-container no-label-float="[[noLabelFloat]]" always-float-label= "[[_computeAlwaysFloatLabel(alwaysFloatLabel,placeholder)]]" auto-validate$="[[a utoValidate]]" disabled$="[[disabled]]" invalid="[[invalid]]">
20740
20741 <content select="[prefix]"></content>
20742
20743 <label hidden$="[[!label]]" aria-hidden="true" for="input">[[label]]</labe l>
20744
20745 <input is="iron-input" id="input" aria-labelledby$="[[_ariaLabelledBy]]" a ria-describedby$="[[_ariaDescribedBy]]" disabled$="[[disabled]]" title$="[[title ]]" bind-value="{{value}}" invalid="{{invalid}}" prevent-invalid-input="[[preven tInvalidInput]]" allowed-pattern="[[allowedPattern]]" validator="[[validator]]" type$="[[type]]" pattern$="[[pattern]]" required$="[[required]]" autocomplete$=" [[autocomplete]]" autofocus$="[[autofocus]]" inputmode$="[[inputmode]]" minlengt h$="[[minlength]]" maxlength$="[[maxlength]]" min$="[[min]]" max$="[[max]]" step $="[[step]]" name$="[[name]]" placeholder$="[[placeholder]]" readonly$="[[readon ly]]" list$="[[list]]" size$="[[size]]" autocapitalize$="[[autocapitalize]]" aut ocorrect$="[[autocorrect]]" on-change="_onChange" tabindex$="[[tabindex]]" autos ave$="[[autosave]]" results$="[[results]]" accept$="[[accept]]" multiple$="[[mul tiple]]">
20746
20747 <content select="[suffix]"></content>
20748
20749 <template is="dom-if" if="[[errorMessage]]">
20750 <paper-input-error aria-live="assertive">[[errorMessage]]</paper-input-e rror>
20751 </template>
20752
20753 <template is="dom-if" if="[[charCounter]]">
20754 <paper-input-char-counter></paper-input-char-counter>
20755 </template>
20756
20757 </paper-input-container>
20758 </template>
20759 </dom-module>
20760
20761 <script>
20762 Polymer({
20763 is: 'paper-input',
20764
20765 behaviors: [
20766 Polymer.IronFormElementBehavior,
20767 Polymer.PaperInputBehavior
20768 ]
20769 });
20770 </script>
20771 <dom-module id="bot-filters" assetpath="/res/imp/botlist/">
20772 <template>
20773 <style include="iron-flex iron-flex-alignment iron-positioning">
20774 :host {
20775 display: block;
20776 font-family: sans-serif;
20777 }
20778 .container {
20779 min-height: 120px;
20780 width: 100%;
20781 }
20782
20783 .item {
20784 border-bottom: 1px solid #EEE;
20785 max-width: 250px;
20786 min-height: 1.0em;
20787 min-width: 100px;
20788 padding: 0.1em 0.2em;
20789 line-height: 1.5em;
20790 }
20791
20792 .iron-selected {
20793 background-color: #4285f4;
20794 color: white;
20795 }
20796
20797 .header {
20798 height: 2em;
20799 padding: .25em;
20800 line-height: 2em;
20801 }
20802
20803 .selector {
20804 border: 1px solid black;
20805 margin: 0 5px;
20806 max-height: 200px;
20807 min-height: 130px;
20808 min-width: 200px;
20809 overflow: auto;
20810 }
20811
20812 .icons {
20813 cursor:pointer;
20814 height:20px;
20815 margin:2px;
20816 width:20px;
20817 flex-shrink: 0;
20818 }
20819
20820 .side-by-side {
20821 display: inline-block;
20822 vertical-align: top;
20823 }
20824
20825 paper-checkbox {
20826 max-height: 2em;
20827 }
20828 </style>
20829
20830 <div class="container horizontal layout">
20831
20832 <div>
20833 <div class="header">Columns:</div>
20834 <div class="selector">
20835 <template is="dom-repeat" items="[[columns]]" as="col">
20836 <div class="item horizontal layout" label="[[col]]">
20837 <span>[[col]]</span>
20838 <span class="flex"></span>
20839 <iron-icon class="icons" icon="icons:remove-circle-outline" hidd en="{{_cantRemoveColumn(col,columns.*)}}" on-tap="removeColumn">
20840 </iron-icon>
20841 </div>
20842 </template>
20843 </div>
20844 </div>
20845
20846 <div class="narrow-down-selector">
20847 <div>
20848 <paper-input id="filter" label="Narrow options" no-label-float="true" value="{{query}}"></paper-input>
20849 </div>
20850
20851 <div class="selector side-by-side">
20852 <iron-selector attr-for-selected="label" selected="{{primary_selected} }">
20853 <template is="dom-repeat" items="[[primary_items]]" as="item">
20854 <div class="item horizontal layout" label="[[item]]">
20855 <iron-icon style="margin:0 -6px;" icon="icons:more-vert">
20856 </iron-icon>
20857 <span>[[item]]</span>
20858 <span class="flex"></span>
20859 <iron-icon class="icons" icon="icons:arrow-back" hidden="{{_cant AddColumn(item,columns.*)}}" on-tap="addColumn">
20860 </iron-icon>
20861 </div>
20862 </template>
20863 </iron-selector>
20864 </div>
20865
20866 <div class="selector side-by-side">
20867 <template is="dom-repeat" items="[[secondary_items]]" as="item">
20868 <div class="item horizontal layout" label="[[item]]">
20869 <span>[[item]]</span>
20870 <span class="flex"></span>
20871 <iron-icon class="icons" icon="icons:arrow-forward" hidden="{{_can tAddFilter(primary_selected,item,filters.*)}}" on-tap="addFilter">
20872 </iron-icon>
20873 </div>
20874 </template>
20875 </div>
20876 </div>
20877
20878 <div>
20879 <div class="header">Filters: </div>
20880 <div class="selector">
20881 <template is="dom-repeat" items="[[filters]]" as="fil">
20882 <div class="item horizontal layout" label="[[fil]]">
20883 <span>[[fil]]</span>
20884 <span class="flex"></span>
20885 <iron-icon class="icons" icon="icons:remove-circle-outline" hidden ="{{_cantRemoveFilter(fil,filters.*)}}" on-tap="removeFilter">
20886 </iron-icon>
20887 </div>
20888 </template>
20889 </div>
20890 </div>
20891
20892 <paper-checkbox checked="{{verbose}}">Verbose Entries</paper-checkbox>
20893
20894 </div>
20895
20896 </template>
20897 <script>
20898 (function(){
20899 var FILTER_SEP = " | ";
20900 // filterMap is a map of primary -> function. The function returns a boolea n
20901 // "does the bot (first arg) match the second argument". These functions wi ll
20902 // have "this" be the botlist, and will have
20903 var filterMap = {
20904 cores: function(bot, cores){
20905 var o = this._cores(bot);
20906 return o.indexOf(cores) !== -1;
20907 },
20908 cpu: function(bot, cpu){
20909 var o = this._dimension(bot, "cpu") || ["none"];
20910 return o.indexOf(cpu) !== -1;
20911 },
20912 devices: function(bot, device){
20913 if (device === "none") {
20914 return this._devices(bot).length === 0;
20915 }
20916 // extract the deviceType, if it is not "unknown".
20917 device = this._unalias(device);
20918 var found = false;
20919 this._devices(bot).forEach(function(d) {
20920 if (this._deviceType(d) === device) {
20921 found = true;
20922 }
20923 }.bind(this));
20924 return found;
20925 },
20926 gpu: function(bot, gpu){
20927 var o = this._dimension(bot, "gpu") || ["none"];
20928 return o.indexOf(this._unalias(gpu)) !== -1;
20929 },
20930 id: function(bot, id) {
20931 return bot.bot_id === id;
20932 },
20933 os: function(bot, os){
20934 var o = this._dimension(bot, "os") || ["Unknown"];
20935 return o.indexOf(os) !== -1;
20936 },
20937 pool: function(bot, pool){
20938 var o = this._dimension(bot, "pool") || ["Unknown"];
20939 return o.indexOf(pool) !== -1;
20940 },
20941 status: function(bot, status){
20942 if (status === "quarantined") {
20943 return bot.quarantined;
20944 } else if (status === "dead") {
20945 return bot.is_dead;
20946 } else {
20947 // Status must be available.
20948 return !bot.quarantined && !bot.is_dead;
20949 }
20950 },
20951 task: function(bot, task) {
20952 if (task === "idle") {
20953 return this._taskId(bot) === "idle";
20954 }
20955 // task === "busy"
20956 return this._taskId(bot) !== "idle";
20957 }
20958 };
20959
20960 // returns true if string b is in string a, case notwithstanding.
20961 var containsCaseInsensitive = function(a, b) {
20962 return a.toLocaleLowerCase().indexOf(b.toLocaleLowerCase()) !== -1;
20963 };
20964
20965 Polymer({
20966 is: "bot-filters",
20967 properties: {
20968 // input
20969 primary_map: {
20970 type: Object,
20971 },
20972 primary_arr: {
20973 type: Array,
20974 },
20975
20976 // output
20977 columns: {
20978 type: Array,
20979 value: function() {
20980 return ["id","os","task","status"];
20981 },
20982 notify: true,
20983 },
20984 filter: {
20985 type: Object,
20986 computed: "_makeFilter(filters.*)",
20987 notify: true,
20988 },
20989 verbose: {
20990 type: Boolean,
20991 value: false,
20992 notify: true,
20993 },
20994
20995 // private
20996 filters:{
20997 type:Array,
20998 value: function() {
20999 return [];
21000 }
21001 },
21002 filter_selected: {
21003 type: String,
21004 value:"",
21005 },
21006 primary_items: {
21007 type: Array,
21008 computed: "_primary(query, primary_map, primary_arr, columns)",
21009 },
21010 primary_selected: {
21011 type: String,
21012 value: "",
21013 },
21014 query: {
21015 type:String,
21016 },
21017 secondary_items: {
21018 type: Array,
21019 computed: "_secondary(primary_selected, query, primary_map)",
21020 },
21021
21022 },
21023
21024 addColumn: function(e) {
21025 var col = e.model.item;
21026 e.preventDefault();
21027 e.stopPropagation();
21028 if (this._cantAddColumn(col)) {
21029 return;
21030 }
21031 this.push("columns", col);
21032 },
21033
21034 addFilter: function(e) {
21035 var filterItem = e.model.item;
21036 if (this._cantAddFilter(this.primary_selected, filterItem)) {
21037 return;
21038 }
21039 var filter = this.primary_selected + FILTER_SEP + filterItem;
21040 this.push("filters", filter);
21041 },
21042
21043 removeColumn: function(e){
21044 var col = e.model.col;
21045 if (this._cantRemoveColumn(col, this.columns)){
21046 return;
21047 }
21048 var idx = this.columns.indexOf(col);
21049 if (idx !== -1) {
21050 this.splice("columns", idx, 1);
21051 }
21052 this.set("column_selected","");
21053 },
21054
21055 removeFilter: function(e){
21056 var filter = e.model.fil;
21057 if (this._cantRemoveFilter(filter)){
21058 return;
21059 }
21060 var idx = this.filters.indexOf(filter);
21061 if (idx !== -1) {
21062 this.splice("filters", idx, 1);
21063 }
21064 this.set("filter_selected","");
21065 },
21066
21067 _cantAddColumn: function(col) {
21068 if (!col) {
21069 return true;
21070 }
21071 return this.columns.indexOf(col) !== -1;
21072 },
21073
21074 _cantAddFilter: function(primary_selected, filterItem) {
21075 if (!primary_selected || !filterItem) {
21076 return true;
21077 }
21078 var filter = primary_selected + FILTER_SEP + filterItem;
21079 return this.filters.indexOf(filter) !== -1;
21080 },
21081
21082 _cantRemoveColumn: function(col) {
21083 return !col || col === "id" || this.columns.indexOf(col) === -1;
21084 },
21085
21086 _cantRemoveFilter: function(filter_selected) {
21087 return !filter_selected || this.filters.indexOf(filter_selected) === -1;
21088 },
21089
21090 _makeFilter: function() {
21091 // The filters belonging to the same primary key will be or'd together. Those groups will be and'd together.
21092 var filterGroups = {};
21093 this.filters.forEach(function(filterString){
21094 var idx = filterString.indexOf(FILTER_SEP);
21095 var primary = filterString.slice(0, idx);
21096 var param = filterString.slice(idx + FILTER_SEP.length);
21097 var arr = filterGroups[primary] || [];
21098 arr.push(param);
21099 filterGroups[primary] = arr;
21100 });
21101 return {
21102 filter: function(bot){
21103 var retVal = true;
21104 for (primary in filterGroups){
21105 var params = filterGroups[primary];
21106 var filter = filterMap[primary];
21107 var groupResult = false;
21108 if (filter) {
21109 params.forEach(function(param){
21110 groupResult = groupResult || filter.bind(this)(bot,param);
21111 }.bind(this));
21112 }
21113 retVal = retVal && groupResult;
21114 }
21115 return retVal;
21116 }
21117 }
21118 },
21119
21120 _primary: function(query, primary_map, primary_arr) {
21121 var arr = this.primary_arr.filter(function(s){
21122 if (containsCaseInsensitive(s, query)) {
21123 return true;
21124 }
21125 var opts = primary_map[s];
21126 for (var i = 0; i < opts.length; i++) {
21127 if (containsCaseInsensitive(opts[i], query)) {
21128 return true;
21129 }
21130 }
21131 return false;
21132 });
21133 // Update the selected to be the current one (if it is still with being
21134 // shown) or the first match.
21135 if (this.query && arr.length > 0 &&
21136 arr.indexOf(this.primary_selected) === -1) {
21137 this.set("primary_selected", arr[0]);
21138 }
21139 return arr;
21140 },
21141 _secondary: function(primary_selected, query, primary_map) {
21142 if (!primary_selected) {
21143 return [];
21144 }
21145 var opts = primary_map[primary_selected].filter(function(s){
21146 return containsCaseInsensitive(s, query);
21147 });
21148
21149 return opts;
21150 },
21151
21152 });
21153 })();
21154 </script>
21155 </dom-module><dom-module id="bot-list" assetpath="/res/imp/botlist/">
21156 <template>
21157 <style include="iron-flex iron-flex-alignment iron-positioning">
21158 bot-filters {
21159 margin-bottom:2px;
21160 }
21161 .bot {
21162 margin:5px;
21163 max-width:400px;
21164 min-height:100px;
21165 min-width:300px;
21166 }
21167 table {
21168 border-collapse: collapse;
21169 border: 1px solid black;
21170 }
21171 td, th {
21172 border: 1px solid black;
21173 padding: 5px;
21174 }
21175
21176 .bot-list th > span {
21177 display:inline-block;
21178 }
21179
21180 .quarantined, .bad-device {
21181 background-color: #ffdddd;
21182 border: 2px solid black;
21183 }
21184 .dead {
21185 background-color: #cccccc;
21186 border: 2px solid black;
21187 }
21188 </style>
21189
21190 <swarming-app auth_headers="{{auth_headers}}" busy="[[busy]]" name="Swarming Bot List">
21191
21192 <bot-filters primary_map="[[primary_map]]" primary_arr="[[primary_arr]]" c olumns="{{columns}}" filter="{{filter}}" verbose="{{verbose}}">
21193 </bot-filters>
21194
21195 <bot-list-data auth_headers="[[auth_headers]]" bots="{{bots}}" busy="{{bus y}}" primary_map="{{primary_map}}" primary_arr="{{primary_arr}}">
21196 </bot-list-data>
21197
21198 <table class="bot-list">
21199 <thead on-sort_change="sortChange">
21200
21201 <tr><th>
21202 <span>Bot Id</span>
21203 <sort-toggle name="id"></sort-toggle>
21204 </th>
21205
21206 <th hidden$="[[_hide('task', columns.*)]]">
21207 <span>Current Task</span>
21208 <sort-toggle name="task"></sort-toggle>
21209 </th>
21210
21211 <template is="dom-repeat" items="[[plain_columns]]" as="c">
21212 <th hidden$="[[_hide(c)]]">
21213 <span>[[_header(c)]]</span>
21214 <sort-toggle name="[[c]]"></sort-toggle>
21215 </th>
21216 </template>
21217 </tr></thead>
21218 <tbody>
21219 <template id="bot_table" is="dom-repeat" items="[[bots]]" as="bot" ini tial-count="50" sort="_sortBotTable" filter="_filterBotTable">
21220
21221 <tr class$="[[_botClass(bot)]]">
21222 <td><a class="center" href$="[[_botLink(bot.bot_id)]]" target="_bl ank">[[bot.bot_id]]</a></td>
21223 <td hidden$="[[_hide('task', columns.*)]]">
21224 Current Task:
21225 <a href$="[[_taskLink(bot)]]">[[_taskId(bot)]]</a>
21226 </td>
21227
21228 <template is="dom-repeat" items="[[plain_columns]]" as="c">
21229 <td hidden$="[[_hide(c)]]">[[_column(c, bot, verbose)]]</td>
21230 </template>
21231
21232 </tr>
21233 <template is="dom-repeat" items="[[_devices(bot)]]" as="device">
21234 <tr hidden$="[[_hide('devices', columns.*)]]" class$="[[_deviceCla ss(device)]]">
21235 <td></td>
21236 <td hidden$="[[_hide('task', columns.*)]]"></td>
21237 <template is="dom-repeat" items="[[plain_columns]]" as="c">
21238 <td hidden$="[[_hide(c)]]">[[_deviceColumn(c, device, verbose) ]]</td>
21239 </template>
21240 </tr>
21241 </template>
21242 </template>
21243 </tbody>
21244 </table>
21245
21246 </swarming-app>
21247
21248 </template>
21249 <script>
21250 (function(){
21251 var special_columns = ["id", "task"];
21252
21253 var headerMap = {
21254 // "id" and "task" are special, so they don't go here and are just
21255 // hard-coded below.
21256 "cores": "Cores",
21257 "cpu": "CPU",
21258 "devices": "Devices",
21259 "gpu": "GPU",
21260 "os": "OS",
21261 "pool": "Pool",
21262 "status": "Status",
21263 };
21264
21265 // This maps column name to a function that will return the content.
21266 var columnMap = {
21267 cores: function(bot){
21268 var cores = this._cores(bot);
21269 if (this.verbose){
21270 return cores.join(" | ");
21271 }
21272 return cores[0];
21273 },
21274 cpu: function(bot){
21275 var cpus = this._dimension(bot, 'cpu') || ['Unknown'];
21276 if (this.verbose){
21277 return cpus.join(" | ");
21278 }
21279 return cpus[0];
21280 },
21281 devices: function(bot){
21282 return this._devices(bot).length + " devices attached";
21283 },
21284 gpu: function(bot){
21285 var gpus = this._dimension(bot, 'gpu')
21286 if (!gpus) {
21287 return "none";
21288 }
21289 var verbose = []
21290 var named = [];
21291 // non-verbose mode has only the top level GPU info "e.g. NVidia"
21292 // which is found by looking for gpu ids w/o a colon.
21293 gpus.forEach(function(g){
21294 var alias = this._gpuAlias(g);
21295 if (alias === "UNKNOWN") {
21296 verbose.push(g);
21297 if (g.indexOf(":") === -1){
21298 named.push(g);
21299 }
21300 return;
21301 }
21302 verbose.push(this._applyAlias(g,alias));
21303 if (g.indexOf(":") === -1){
21304 named.push(this._applyAlias(g,alias));
21305 }
21306 }.bind(this))
21307 if (this.verbose){
21308 return verbose.join(" | ");
21309 }
21310 return named.join(" | ");
21311 },
21312 id: function(bot) {
21313 return bot.bot_id;
21314 },
21315 os: function(bot){
21316 var os = this._dimension(bot, 'os') || ['Unknown'];
21317 if (this.verbose){
21318 return os.join(" | ");
21319 }
21320 return os[0];
21321 },
21322 pool: function(bot) {
21323 var pool = this._dimension(bot, 'pool') || ['Unknown'];
21324 return pool.join(" | ");
21325 },
21326 status: function(bot){
21327 if (bot.quarantined) {
21328 return "Quarantined: " + bot.quarantined;
21329 }
21330 if (bot.is_dead) {
21331 return "Dead: " + bot.is_dead;
21332 }
21333 return "Alive";
21334 },
21335 task: function(bot){
21336 return this._taskId(bot);
21337 }
21338
21339 };
21340
21341 Polymer({
21342 is: 'bot-list',
21343 behaviors: [SwarmingBehaviors.BotListBehavior],
21344
21345 properties: {
21346
21347 columns: {
21348 type: Array,
21349 },
21350 // Should have a property "filter" which is a function.
21351 filter: {
21352 type: Object,
21353 },
21354
21355 plain_columns: {
21356 type: Array,
21357 computed: "_stripSpecial(columns.*)",
21358 },
21359
21360 sorts: {
21361 type: Array,
21362 },
21363
21364 verbose: {
21365 type: Boolean,
21366 }
21367 },
21368
21369 observers: ['_reRender(filter.*)', '_checkSorts(columns.*)'],
21370
21371 _botClass: function(bot) {
21372 if (bot.quarantined) {
21373 return "quarantined";
21374 }
21375 if (bot.is_dead) {
21376 return "dead";
21377 }
21378 return "";
21379 },
21380
21381 _botLink: function(id) {
21382 return "/restricted/bot/"+id;
21383 },
21384
21385 _checkSorts: function() {
21386 if (!this.sorts) {
21387 return;
21388 }
21389 this.sorts = this.sorts.filter(function(s){
21390 return this.columns.indexOf(s) !== -1;
21391 }.bind(this));
21392 this._reRender();
21393 },
21394
21395 _column: function(col, bot){
21396 return columnMap[col].bind(this)(bot);
21397 },
21398
21399 _deviceColumn: function(col, device){
21400 if (col === "devices") {
21401 var str = this._androidAlias(device);
21402 if (device.okay) {
21403 str = this._applyAlias(this._deviceType(device), str);
21404 }
21405 str += " S/N:";
21406 str += device.serial;
21407 return str;
21408 }
21409 if (col === "status") {
21410 return device.state;
21411 }
21412 return "";
21413 },
21414
21415 _deviceClass: function(device) {
21416 if (!device.okay) {
21417 return "bad-device";
21418 }
21419 return "";
21420 },
21421
21422 _filterBotTable: function(bot) {
21423 if (!this.filter || !this.filter.filter) {
21424 return true;
21425 }
21426 return this.filter.filter.bind(this)(bot);
21427 },
21428
21429 _header: function(col){
21430 return headerMap[col];
21431 },
21432
21433 _hide: function(col) {
21434 return this.columns.indexOf(col) === -1;
21435 },
21436
21437 _reRender: function(filter, sort) {
21438 this.$.bot_table.render();
21439 },
21440
21441 _sortBotTable: function(botA, botB) {
21442 if (!this.sorts) {
21443 return 0;
21444 }
21445 for (var i = 0; i< this.sorts.length; i++) {
21446 var s = this.sorts[i];
21447 var botACol = this._column(s.name, botA);
21448 var botBCol = this._column(s.name, botB);
21449 // s.sort is either -1 or 1 (if it is 0, it should have been removed f rom this list).
21450 var sort = s.sort * botACol.localeCompare(botBCol);
21451 // Try numeric, aka "natural" sort and use it if ns is not NaN.
21452 var ns = botACol - botBCol;
21453 if (ns) {
21454 sort = s.sort * ns;
21455 }
21456
21457 if (sort) { // If there is a difference with this sort column, use
21458 return sort;
21459 }
21460 }
21461 return 0;
21462 },
21463
21464 sortChange: function(e) {
21465 if (!(e && e.detail && e.detail.name)) {
21466 return;
21467 }
21468 var sorts = this.sorts || [];
21469 var found = false;
21470 for (var i = 0; i<sorts.length; i++) {
21471 if (sorts[i].name === e.detail.name) {
21472 sorts[i].sort = e.detail.sort;
21473 found = true;
21474 break;
21475 }
21476 }
21477 if (!found) {
21478 sorts.push(e.detail);
21479 }
21480
21481 this.sorts=sorts;
21482 this._reRender();
21483 },
21484
21485 _stripSpecial: function(){
21486 return this.columns.filter(function(c){
21487 return special_columns.indexOf(c) === -1;
21488 }).sort();
21489 },
21490
21491 _taskId: function(data) {
21492 if (data && data.task_id) {
21493 return data.task_id;
21494 }
21495 return "idle";
21496 },
21497
21498 _taskLink: function(data) {
21499 if (data && data.task_id) {
21500 return "/user/task/" + data.task_id;
21501 }
21502 return undefined;
21503 }
21504
21505 });
21506 })();
21507 </script>
14650 </dom-module></div></body></html> 21508 </dom-module></div></body></html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698