text: /**
  * @license
  * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
  * Use of this source code is governed by a BSD-style
  * license that can be found in the LICENSE file or at
  * https://developers.google.com/open-source/licenses/bsd */
  
  /*
    This is a limited shim for ShadowDOM css styling.
    https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#styles
  
    The intention here is to support only the styling features which can be
    relatively simply implemented. The goal is to allow users to avoid the
    most obvious pitfalls and do so without compromising performance significantly.
    For ShadowDOM styling that's not covered here, a set of best practices
    can be provided that should allow users to accomplish more complex styling.
  
    The following is a list of specific ShadowDOM styling features and a brief
    discussion of the approach used to shim.
  
    Shimmed features:
  
    * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host
    element using the :host rule. To shim this feature, the :host styles are
    reformatted and prefixed with a given scope name and promoted to a
    document level stylesheet.
    For example, given a scope name of .foo, a rule like this:
  
      :host {
          background: red;
        }
      }
  
    becomes:
  
      .foo {
        background: red;
      }
  
    * encapsultion: Styles defined within ShadowDOM, apply only to
    dom inside the ShadowDOM. Polymer uses one of two techniques to imlement
    this feature.
  
    By default, rules are prefixed with the host element tag name
    as a descendant selector. This ensures styling does not leak out of the 'top'
    of the element's ShadowDOM. For example,
  
    div {
        font-weight: bold;
      }
  
    becomes:
  
    x-foo div {
        font-weight: bold;
      }
  
    becomes:
  
  
    Alternatively, if WebComponents.ShadowCSS.strictStyling is set to true then
    selectors are scoped by adding an attribute selector suffix to each
    simple selector that contains the host element tag name. Each element
    in the element's ShadowDOM template is also given the scope attribute.
    Thus, these rules match only elements that have the scope attribute.
    For example, given a scope name of x-foo, a rule like this:
  
      div {
        font-weight: bold;
      }
  
    becomes:
  
      div[x-foo] {
        font-weight: bold;
      }
  
    Note that elements that are dynamically added to a scope must have the scope
    selector added to them manually.
  
    * upper/lower bound encapsulation: Styles which are defined outside a
    shadowRoot should not cross the ShadowDOM boundary and should not apply
    inside a shadowRoot.
  
    This styling behavior is not emulated. Some possible ways to do this that
    were rejected due to complexity and/or performance concerns include: (1) reset
    every possible property for every possible selector for a given scope name;
    (2) re-implement css in javascript.
  
    As an alternative, users should make sure to use selectors
    specific to the scope in which they are working.
  
    * ::distributed: This behavior is not emulated. It's often not necessary
    to style the contents of a specific insertion point and instead, descendants
    of the host element can be styled selectively. Users can also create an
    extra node around an insertion point and style that node's contents
    via descendent selectors. For example, with a shadowRoot like this:
  
      <style>
        ::content(div) {
          background: red;
        }
      </style>
      <content></content>
  
    could become:
  
      <style>
        / *@polyfill .content-container div * /
        ::content(div) {
          background: red;
        }
      </style>
      <div class="content-container">
        <content></content>
      </div>
  
    Note the use of @polyfill in the comment above a ShadowDOM specific style
    declaration. This is a directive to the styling shim to use the selector
    in comments in lieu of the next selector when running under polyfill.
  */
  
  export const ShadowCSS = {
    strictStyling: false,
    // change a selector like 'div' to 'name div'
    /** @this {ShadowCSS} */
    scopeRules: function(cssRules, scopeSelector, opt_transformer) {
      var cssText = '';
      if (cssRules) {
        Array.prototype.forEach.call(cssRules, function(rule) {
          if (rule.selectorText && (rule.style && rule.style.cssText !== undefined)) {
            cssText += this.scopeSelector(rule.selectorText, scopeSelector,
              this.strictStyling, opt_transformer) + ' {\n\t';
            cssText += this.propertiesFromRule(rule) + '\n}\n\n';
          } else if (rule.type === CSSRule.MEDIA_RULE) {
            cssText += '@media ' + rule.media.mediaText + ' {\n';
            cssText += this.scopeRules(rule.cssRules, scopeSelector);
            cssText += '\n}\n\n';
          } else {
            // KEYFRAMES_RULE in IE throws when we query cssText
            // when it contains a -webkit- property.
            // if this happens, we fallback to constructing the rule
            // from the CSSRuleSet
            // https://connect.microsoft.com/IE/feedbackdetail/view/955703/accessing-csstext-of-a-keyframe-rule-that-contains-a-webkit-property-via-cssom-generates-exception
            try {
              if (rule.cssText) {
                cssText += rule.cssText + '\n\n';
              }
            } catch(x) {
              if (rule.type === CSSRule.KEYFRAMES_RULE && rule.cssRules) {
                cssText += this.ieSafeCssTextFromKeyFrameRule(rule);
              }
            }
          }
        }, this);
      }
      return cssText;
    },
    /** @this {ShadowCSS} */
    ieSafeCssTextFromKeyFrameRule: function(rule) {
      var cssText = '@keyframes ' + rule.name + ' {';
      Array.prototype.forEach.call(rule.cssRules, function(rule) {
        cssText += ' ' + rule.keyText + ' {' + rule.style.cssText + '}';
      });
      cssText += ' }';
      return cssText;
    },
    /** @this {ShadowCSS} */
    scopeSelector: function(selector, scopeSelector, strict, opt_transformer) {
      var r = [], parts = selector.split(',');
      parts.forEach(function(p) {
        p = p.trim();
        if (opt_transformer) {
          p = opt_transformer(p);
        }
        if (this.selectorNeedsScoping(p, scopeSelector)) {
          p = (strict && !p.match(polyfillHostNoCombinator)) ?
              this.applyStrictSelectorScope(p, scopeSelector) :
              this.applySelectorScope(p, scopeSelector);
        }
        r.push(p);
      }, this);
      return r.join(', ');
    },
    /** @this {ShadowCSS} */
    selectorNeedsScoping: function(selector, scopeSelector) {
      if (Array.isArray(scopeSelector)) {
        return true;
      }
      var re = this.makeScopeMatcher(scopeSelector);
      return !selector.match(re);
    },
    /** @this {ShadowCSS} */
    makeScopeMatcher: function(scopeSelector) {
      scopeSelector = scopeSelector.replace(/\[/g, '\\[').replace(/\]/g, '\\]');
      return new RegExp('^(' + scopeSelector + ')' + selectorReSuffix, 'm');
    },
    /** @this {ShadowCSS} */
    applySelectorScope: function(selector, selectorScope) {
      return Array.isArray(selectorScope) ?
          this.applySelectorScopeList(selector, selectorScope) :
          this.applySimpleSelectorScope(selector, selectorScope);
    },
    // apply an array of selectors
    /** @this {ShadowCSS} */
    applySelectorScopeList: function(selector, scopeSelectorList) {
      var r = [];
      for (var i=0, s; (s=scopeSelectorList[i]); i++) {
        r.push(this.applySimpleSelectorScope(selector, s));
      }
      return r.join(', ');
    },
    // scope via name and [is=name]
    /** @this {ShadowCSS} */
    applySimpleSelectorScope: function(selector, scopeSelector) {
      if (selector.match(polyfillHostRe)) {
        selector = selector.replace(polyfillHostNoCombinator, scopeSelector);
        return selector.replace(polyfillHostRe, scopeSelector + ' ');
      } else {
        return scopeSelector + ' ' + selector;
      }
    },
    // return a selector with [name] suffix on each simple selector
    // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name]
    /** @this {ShadowCSS} */
    applyStrictSelectorScope: function(selector, scopeSelector) {
      scopeSelector = scopeSelector.replace(/\[is=([^\]]*)\]/g, '$1');
      var splits = [' ', '>', '+', '~'],
        scoped = selector,
        attrName = '[' + scopeSelector + ']';
      splits.forEach(function(sep) {
        var parts = scoped.split(sep);
        scoped = parts.map(function(p) {
          // remove :host since it should be unnecessary
          var t = p.trim().replace(polyfillHostRe, '');
          if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) {
            p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3');
          }
          return p;
        }).join(sep);
      });
      return scoped;
    },
    /** @this {ShadowCSS} */
    propertiesFromRule: function(rule) {
      var cssText = rule.style.cssText;
      // TODO(sorvell): Safari cssom incorrectly removes quotes from the content
      // property. (https://bugs.webkit.org/show_bug.cgi?id=118045)
      // don't replace attr rules
      if (rule.style.content && !rule.style.content.match(/['"]+|attr/)) {
        cssText = cssText.replace(/content:[^;]*;/g, 'content: \'' +
            rule.style.content + '\';');
      }
      // TODO(sorvell): we can workaround this issue here, but we need a list
      // of troublesome properties to fix https://github.com/Polymer/platform/issues/53
      //
      // inherit rules can be omitted from cssText
      // TODO(sorvell): remove when Blink bug is fixed:
      // https://code.google.com/p/chromium/issues/detail?id=358273
      var style = rule.style;
      for (var i in style) {
        if (style[i] === 'initial') {
          cssText += i + ': initial; ';
        }
      }
      return cssText;
    }
  };
  
  var selectorRe = /([^{]*)({[\s\S]*?})/gim,
      cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
      // TODO(sorvell): remove either content or comment
      cssCommentNextSelectorRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,
      cssContentNextSelectorRe = /polyfill-next-selector[^}]*content\:[\s]*?['"](.*?)['"][;\s]*}([^{]*?){/gim,
      // TODO(sorvell): remove either content or comment
      cssCommentRuleRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
      cssContentRuleRe = /(polyfill-rule)[^}]*(content\:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim,
      // TODO(sorvell): remove either content or comment
      cssCommentUnscopedRuleRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
      cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content\:[\s]*['"](.*?)['"])[;\s]*[^}]*}/gim,
      cssPseudoRe = /::(x-[^\s{,(]*)/gim,
      cssPartRe = /::part\(([^)]*)\)/gim,
      // note: :host pre-processed to -shadowcsshost.
      polyfillHost = '-shadowcsshost',
      // note: :host-context pre-processed to -shadowcsshostcontext.
      polyfillHostContext = '-shadowcsscontext',
      parenSuffix = ')(?:\\((' +
          '(?:\\([^)(]*\\)|[^)(]*)+?' +
          ')\\))?([^,{]*)';
      var cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'),
      cssColonHostContextRe = new RegExp('(' + polyfillHostContext + parenSuffix, 'gim'),
      selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$',
      colonHostRe = /\:host/gim,
      colonHostContextRe = /\:host-context/gim,
      /* host name without combinator */
      polyfillHostNoCombinator = polyfillHost + '-no-combinator',
      polyfillHostRe = new RegExp(polyfillHost, 'gim'),
      polyfillHostContextRe = new RegExp(polyfillHostContext, 'gim'),
      shadowDOMSelectorsRe = [
        />>>/g,
        /::shadow/g,
        /::content/g,
        // Deprecated selectors
        /\/deep\//g, // former >>>
        /\/shadow\//g, // former ::shadow
        /\/shadow-deep\//g, // former /deep/
        /\^\^/g,     // former /shadow/
        /\^(?!=)/g   // former /shadow-deep/
      ];
  