/*! ie11CustomProperties.js v3.1.0 | MIT License | https://git.io/fjXMN */
!(function () {
  'use strict'

  // check for support
  var testEl = document.createElement('i')
  testEl.style.setProperty('--x', 'y')
  if (testEl.style.getPropertyValue('--x') === 'y' || !testEl.msMatchesSelector)
    return

  if (!Element.prototype.matches)
    Element.prototype.matches = Element.prototype.msMatchesSelector

  var listeners = [],
    root = document,
    Observer

  function qsa(el, selector) {
    try {
      return el.querySelectorAll(selector)
    } catch (e) {
      // console.warn('the Selector '+selector+' can not be parsed');
      return []
    }
  }
  function onElement(selector, callback) {
    var listener = {
      selector: selector,
      callback: callback,
      elements: new WeakMap(),
    }
    var els = qsa(root, listener.selector),
      i = 0,
      el
    while ((el = els[i++])) {
      listener.elements.set(el, true)
      listener.callback.call(el, el)
    }
    listeners.push(listener)
    if (!Observer) {
      Observer = new MutationObserver(checkMutations)
      Observer.observe(root, {
        childList: true,
        subtree: true,
      })
    }
    checkListener(listener)
  }
  function checkListener(listener, target) {
    var i = 0,
      el,
      els = []
    try {
      target && target.matches(listener.selector) && els.push(target)
    } catch (e) {}
    if (loaded) {
      // ok? check inside node on innerHTML - only when loaded
      Array.prototype.push.apply(els, qsa(target || root, listener.selector))
    }
    while ((el = els[i++])) {
      if (listener.elements.has(el)) continue
      listener.elements.set(el, true)
      listener.callback.call(el, el)
    }
  }
  function checkListeners(inside) {
    var i = 0,
      listener
    while ((listener = listeners[i++])) checkListener(listener, inside)
  }
  function checkMutations(mutations) {
    var j = 0,
      i,
      mutation,
      nodes,
      target
    while ((mutation = mutations[j++])) {
      ;(nodes = mutation.addedNodes), (i = 0)
      while ((target = nodes[i++]))
        target.nodeType === 1 && checkListeners(target)
    }
  }

  var loaded = false
  document.addEventListener('DOMContentLoaded', function () {
    loaded = true
  })

  // svg polyfills
  function copyProperty(prop, from, to) {
    var desc = Object.getOwnPropertyDescriptor(from, prop)
    Object.defineProperty(to, prop, desc)
  }
  if (!('classList' in Element.prototype)) {
    copyProperty('classList', HTMLElement.prototype, Element.prototype)
  }
  if (!('innerHTML' in Element.prototype)) {
    copyProperty('innerHTML', HTMLElement.prototype, Element.prototype)
  }
  if (!('sheet' in SVGStyleElement.prototype)) {
    Object.defineProperty(SVGStyleElement.prototype, 'sheet', {
      get: function () {
        var all = document.styleSheets,
          i = 0,
          sheet
        while ((sheet = all[i++])) {
          if (sheet.ownerNode === this) return sheet
        }
      },
    })
  }

  // main logic

  // cached regexps, better performance
  const regFindSetters = /([\s{;])(--([A-Za-z0-9-_]*)\s*:([^;!}{]+)(!important)?)(?=\s*([;}]|$))/g
  const regFindGetters = /([{;]\s*)([A-Za-z0-9-_]+\s*:[^;}{]*var\([^!;}{]+)(!important)?(?=\s*([;}$]|$))/g
  const regRuleIEGetters = /-ieVar-([^:]+):/g
  const regRuleIESetters = /-ie-([^};]+)/g
  //const regHasVar = /var\(/;
  const regPseudos = /:(hover|active|focus|target|visited|link|:before|:after|:first-letter|:first-line)/

  onElement('link[rel="stylesheet"]', function (el) {
    fetchCss(el.href, function (css) {
      var newCss = rewriteCss(css)
      if (css === newCss) return
      newCss = relToAbs(el.href, newCss)
      el.disabled = true
      var style = document.createElement('style')
      if (el.media) style.setAttribute('media', el.media)
      el.parentNode.insertBefore(style, el)
      activateStyleElement(style, newCss)
    })
  })

  function foundStyle(el) {
    if (el.ieCP_polyfilled) return
    if (el.ieCP_elementSheet) return
    var css = el.innerHTML
    var newCss = rewriteCss(css)
    if (css === newCss) return
    activateStyleElement(el, newCss)
  }
  onElement('style', foundStyle)
  // immediate, to pass w3c-tests, bud its a bad idea
  // addEventListener('DOMNodeInserted',function(e){ e.target.tagName === 'STYLE' && foundStyle(e.target); });

  onElement('[ie-style]', function (el) {
    var newCss = rewriteCss('{' + el.getAttribute('ie-style')).substr(1)
    el.style.cssText += ';' + newCss
    var found = parseRewrittenStyle(el.style)
    if (found.getters) addGetterElement(el, found.getters, '%styleAttr')
    if (found.setters) addSetterElement(el, found.setters)
  })

  function relToAbs(base, css) {
    return css.replace(/url\(([^)]+)\)/g, function ($0, $1) {
      $1 = $1.trim().replace(/(^['"]|['"]$)/g, '')
      if ($1.match(/^([a-z]+:|\/)/)) return $0
      base = base.replace(/\?.*/, '')
      return 'url(' + base + './../' + $1 + ')'
    })
  }

  // ie has a bug, where unknown properties at pseudo-selectors are computed at the element
  // #el::after { -content:'x'; } => getComputedStyle(el)['-content'] == 'x'
  // should we add something like -ieVar-pseudo_after-content:'x'?
  function rewriteCss(css) {
    /* uncomment if spec finished and needed by someone
		css = css.replace(/@property ([^{]+){([^}]+)}/, function($0, prop, body){
			prop = prop.trim();
			const declaration = {name:prop};
			body.split(';').forEach(function(pair){
				const x = pair.split(':');
				if (x[1]) declaration[ x[0].trim() ] = x[1];
			});
			declaration['inherits'] = declaration['inherits'].trim()==='true' ? true : false;
			declaration['initialValue'] = declaration['initial-value'];
			CSS.registerProperty(declaration)
			return '/*\n @property ... removed \n*'+'/';
		});
		*/
    return css
      .replace(regFindSetters, function ($0, $1, $2, $3, $4, important) {
        return (
          $1 + '-ie-' + (important ? '❗' : '') + $3 + ':' + encodeValue($4)
        )
      })
      .replace(regFindGetters, function ($0, $1, $2, important) {
        return $1 + '-ieVar-' + (important ? '❗' : '') + $2 + '; ' + $2 // keep the original, so chaining works "--x:var(--y)"
      })
  }
  function encodeValue(value) {
    return value
    return value.replace(/ /g, '␣')
  }
  const keywords = { initial: 1, inherit: 1, revert: 1, unset: 1 }
  function decodeValue(value) {
    return value
    if (value === undefined) return
    value = value.replace(/␣/g, ' ')
    const trimmed = value.trim()
    if (keywords[trimmed]) return trimmed
    return value
  }

  // beta
  const styles_of_getter_properties = {}

  function parseRewrittenStyle(style) {
    // less memory then parameter cssText?

    // beta
    style['z-index'] // ie11 can access unknown properties in stylesheets only if accessed a dashed known property

    const cssText = style.cssText
    var matchesGetters = cssText.match(regRuleIEGetters),
      j,
      match
    if (matchesGetters) {
      var getters = [] // eg. [border,color]
      for (j = 0; (match = matchesGetters[j++]); ) {
        let propName = match.slice(7, -1)
        if (propName[0] === '❗') propName = propName.substr(1)
        getters.push(propName)

        // beta
        if (!styles_of_getter_properties[propName])
          styles_of_getter_properties[propName] = []
        styles_of_getter_properties[propName].push(style)
      }
    }
    var matchesSetters = cssText.match(regRuleIESetters)
    if (matchesSetters) {
      var setters = {} // eg. [--color:#fff, --padding:10px];
      for (j = 0; (match = matchesSetters[j++]); ) {
        let x = match.substr(4).split(':')
        let propName = x[0]
        let propValue = x[1]
        if (propName[0] === '❗') propName = propName.substr(1)
        setters[propName] = propValue
      }
    }
    return { getters: getters, setters: setters }
  }
  function activateStyleElement(style, css) {
    style.innerHTML = css
    style.ieCP_polyfilled = true
    var rules = style.sheet.rules,
      i = 0,
      rule // cssRules = CSSRuleList, rules = MSCSSRuleList
    while ((rule = rules[i++])) {
      const found = parseRewrittenStyle(rule.style)
      if (found.getters) addGettersSelector(rule.selectorText, found.getters)
      if (found.setters) addSettersSelector(rule.selectorText, found.setters)

      // mediaQueries: redraw the hole document
      // better add events for each element?
      const media =
        rule.parentRule &&
        rule.parentRule.media &&
        rule.parentRule.media.mediaText
      if (media && (found.getters || found.setters)) {
        matchMedia(media).addListener(function () {
          drawTree(document.documentElement)
        })
      }
    }

    // beta
    redrawStyleSheets()
  }

  function addGettersSelector(selector, properties) {
    selectorAddPseudoListeners(selector)
    onElement(unPseudo(selector), function (el) {
      addGetterElement(el, properties, selector)
      drawElement(el)
    })
  }
  function addGetterElement(el, properties, selector) {
    var i = 0,
      prop,
      j
    const selectors = selector.split(',') // split grouped selectors
    el.setAttribute('iecp-needed', true)
    if (!el.ieCPSelectors) el.ieCPSelectors = {}
    while ((prop = properties[i++])) {
      for (j = 0; (selector = selectors[j++]); ) {
        const parts = selector.trim().split('::')
        if (!el.ieCPSelectors[prop]) el.ieCPSelectors[prop] = []
        el.ieCPSelectors[prop].push({
          selector: parts[0],
          pseudo: parts[1] ? '::' + parts[1] : '',
        })
      }
    }
  }
  function addSettersSelector(selector, propVals) {
    selectorAddPseudoListeners(selector)
    onElement(unPseudo(selector), function (el) {
      addSetterElement(el, propVals)
    })
  }
  function addSetterElement(el, propVals) {
    if (!el.ieCP_setters) el.ieCP_setters = {}
    for (var prop in propVals) {
      // eg. {foo:#fff, bar:baz}
      el.ieCP_setters['--' + prop] = 1
    }
    drawTree(el)
  }

  //beta
  function redrawStyleSheets() {
    for (var prop in styles_of_getter_properties) {
      let styles = styles_of_getter_properties[prop]
      for (var i = 0, style; (style = styles[i++]); ) {
        if (style.owningElement) continue
        var value = style['-ieVar-' + prop]
        if (!value) continue
        value = styleComputeValueWidthVars(
          getComputedStyle(document.documentElement),
          value
        )
        if (value === '') continue
        try {
          style[prop] = value
        } catch (e) {}
      }
    }
  }

  const pseudos = {
    hover: {
      on: 'mouseenter',
      off: 'mouseleave',
    },
    focus: {
      on: 'focusin',
      off: 'focusout',
    },
    active: {
      on: 'CSSActivate',
      off: 'CSSDeactivate',
    },
  }
  function selectorAddPseudoListeners(selector) {
    // ie11 has the strange behavoir, that groups of selectors are individual rules, but starting with the full selector:
    // td, th, button { color:red } results in this rules:
    // "td, th, button" | "th, th" | "th"
    selector = selector.split(',')[0]
    for (var pseudo in pseudos) {
      var parts = selector.split(':' + pseudo)
      if (parts.length > 1) {
        var ending = parts[1].match(/^[^\s]*/) // ending elementpart of selector (used for not(:active))
        let sel = unPseudo(parts[0] + ending)
        const listeners = pseudos[pseudo]
        onElement(sel, function (el) {
          el.addEventListener(listeners.on, drawTreeEvent)
          el.addEventListener(listeners.off, drawTreeEvent)
        })
      }
    }
  }
  let CSSActive = null
  document.addEventListener('mousedown', function (e) {
    setTimeout(function () {
      if (e.target === document.activeElement) {
        var evt = document.createEvent('Event')
        evt.initEvent('CSSActivate', true, true)
        CSSActive = e.target
        CSSActive.dispatchEvent(evt)
      }
    })
  })
  document.addEventListener('mouseup', function () {
    if (CSSActive) {
      var evt = document.createEvent('Event')
      evt.initEvent('CSSDeactivate', true, true)
      CSSActive.dispatchEvent(evt)
      CSSActive = null
    }
  })

  function unPseudo(selector) {
    return selector.replace(regPseudos, '').replace(':not()', '')
  }

  var uniqueCounter = 0

  /* old *
	function _drawElement(el) {
		if (!el.ieCP_unique) { // use el.uniqueNumber? but needs class for the css-selector => test performance
			el.ieCP_unique = ++uniqueCounter;
			el.classList.add('iecp-u' + el.ieCP_unique);
		}
		var style = getComputedStyle(el);
		if (el.ieCP_sheet) while (el.ieCP_sheet.rules[0]) el.ieCP_sheet.deleteRule(0);
		for (var prop in el.ieCPSelectors) {
			var important = style['-ieVar-❗' + prop];
			let valueWithVar = important || style['-ieVar-' + prop];
			if (!valueWithVar) continue; // todo, what if '0'

			var details = {};
			var value = styleComputeValueWidthVars(style, valueWithVar, details);

			if (important) value += ' !important';
			for (var i=0, item; item=el.ieCPSelectors[prop][i++];) { // todo: split and use requestAnimationFrame?
				if (item.selector === '%styleAttr') {
					el.style[prop] = value;
				} else {

					// beta
					if (!important && details.allByRoot !== false) continue; // dont have to draw root-properties

					//let selector = item.selector.replace(/>? \.[^ ]+/, ' ', item.selector); // todo: try to equalize specificity
					let selector = item.selector;
					elementStyleSheet(el).insertRule(selector + '.iecp-u' + el.ieCP_unique + item.pseudo + ' {' + prop + ':' + value + '}', 0);
				}
			}
		}
	}
	function elementStyleSheet(el){
		if (!el.ieCP_sheet) {
			const styleEl = document.createElement('style');
			styleEl.ieCP_elementSheet = 1;
			//el.appendChild(styleEl); // yes! self-closing tags can have style as children, but - if i set innerHTML, the stylesheet is lost
			document.head.appendChild(styleEl);
			el.ieCP_sheet = styleEl.sheet;
		}
		return el.ieCP_sheet;
	}

	/* */
  function _drawElement(el) {
    if (!el.ieCP_unique) {
      // use el.uniqueNumber? but needs class for the css-selector => test performance
      el.ieCP_unique = ++uniqueCounter
      el.classList.add('iecp-u' + el.ieCP_unique)
    }
    var style = getComputedStyle(el)
    let css = ''
    for (var prop in el.ieCPSelectors) {
      var important = style['-ieVar-❗' + prop]
      let valueWithVar = important || style['-ieVar-' + prop]
      if (!valueWithVar) continue // todo, what if '0'
      var details = {}
      var value = styleComputeValueWidthVars(style, valueWithVar, details)
      //if (value==='initial') value = initials[prop];
      if (important) value += ' !important'
      for (var i = 0, item; (item = el.ieCPSelectors[prop][i++]); ) {
        // todo: split and use requestAnimationFrame?
        if (item.selector === '%styleAttr') {
          el.style[prop] = value
        } else {
          // beta
          if (!important && details.allByRoot !== false) continue // dont have to draw root-properties

          //let selector = item.selector.replace(/>? \.[^ ]+/, ' ', item.selector); // todo: try to equalize specificity
          let selector = item.selector
          css +=
            selector +
            '.iecp-u' +
            el.ieCP_unique +
            item.pseudo +
            '{' +
            prop +
            ':' +
            value +
            '}\n'
          // el.runtimeStyle[prop] = value; // todo
        }
      }
    }
    elementSetCss(el, css)
  }
  function elementSetCss(el, css) {
    if (!el.ieCP_styleEl && css) {
      const styleEl = document.createElement('style')
      styleEl.ieCP_elementSheet = 1
      //el.appendChild(styleEl); // yes! self-closing tags can have style as children, but - if i set innerHTML, the stylesheet is lost
      document.head.appendChild(styleEl)
      el.ieCP_styleEl = styleEl
    }
    if (el.ieCP_styleEl) el.ieCP_styleEl.innerHTML = css
  }
  /* */

  function drawTree(target) {
    if (!target) return
    var els = target.querySelectorAll('[iecp-needed]')
    if (target.hasAttribute && target.hasAttribute('iecp-needed'))
      drawElement(target) // self
    for (var i = 0, el; (el = els[i++]); ) drawElement(el) // tree
  }
  // draw queue
  let drawQueue = new Set()
  let collecting = false
  let drawing = false
  function drawElement(el) {
    drawQueue.add(el)
    if (collecting) return
    collecting = true
    requestAnimationFrame(function () {
      //setImmediate(function(){
      collecting = false
      drawing = true
      drawQueue.forEach(_drawElement)
      drawQueue.clear()
      setTimeout(function () {
        // mutationObserver will trigger delayed, requestAnimationFrame will miss some changes
        drawing = false
      })
    })
  }

  function drawTreeEvent(e) {
    drawTree(e.target)
  }

  function findVars(str, cb) {
    // css value parser
    let level = 0,
      openedLevel = null,
      lastPoint = 0,
      newStr = '',
      i = 0,
      char,
      insideCalc
    while ((char = str[i++])) {
      if (char === '(') {
        ++level
        if (
          openedLevel === null &&
          str[i - 4] + str[i - 3] + str[i - 2] === 'var'
        ) {
          openedLevel = level
          newStr += str.substring(lastPoint, i - 4)
          lastPoint = i
        }
        if (str[i - 5] + str[i - 4] + str[i - 3] + str[i - 2] === 'calc') {
          insideCalc = level
        }
      }
      if (char === ')' && openedLevel === level) {
        let variable = str.substring(lastPoint, i - 1).trim(),
          fallback
        let x = variable.indexOf(',')
        if (x !== -1) {
          fallback = variable.slice(x + 1)
          variable = variable.slice(0, x)
        }
        newStr += cb(variable, fallback, insideCalc)
        lastPoint = i
        openedLevel = null
      }
      if (char === ')') {
        --level
        if (insideCalc === level) insideCalc = null
      }
    }
    newStr += str.substring(lastPoint)
    return newStr
  }
  function styleComputeValueWidthVars(style, valueWithVars, details) {
    return findVars(valueWithVars, function (variable, fallback, insideCalc) {
      var value = style.getPropertyValue(variable)
      if (insideCalc) value = value.replace(/^calc\(/, '(') // prevent nested calc
      if (details && style.lastPropertyServedBy !== document.documentElement)
        details.allByRoot = false
      if (value === '' && fallback)
        value = styleComputeValueWidthVars(style, fallback, details)
      return value
    })
  }

  // mutation listener
  var observer = new MutationObserver(function (mutations) {
    if (drawing) return
    for (var i = 0, mutation; (mutation = mutations[i++]); ) {
      if (mutation.attributeName === 'iecp-needed') continue // why?
      // recheck all selectors if it targets new elements?
      drawTree(mutation.target)
    }
  })
  setTimeout(function () {
    observer.observe(document, { attributes: true, subtree: true })
  })

  // :target listener
  var oldHash = location.hash
  addEventListener('hashchange', function (e) {
    var newEl = document.getElementById(location.hash.substr(1))
    if (newEl) {
      var oldEl = document.getElementById(oldHash.substr(1))
      drawTree(newEl)
      drawTree(oldEl)
    } else {
      drawTree(document)
    }
    oldHash = location.hash
  })

  // add owningElement to Element.style
  var descriptor = Object.getOwnPropertyDescriptor(
    HTMLElement.prototype,
    'style'
  )
  var styleGetter = descriptor.get
  descriptor.get = function () {
    const style = styleGetter.call(this)
    style.owningElement = this
    return style
  }
  Object.defineProperty(HTMLElement.prototype, 'style', descriptor)

  // add computedFor to computed style-objects
  var originalGetComputed = getComputedStyle
  window.getComputedStyle = function (el) {
    var style = originalGetComputed.apply(this, arguments)
    style.computedFor = el
    //style.pseudoElt = pseudoElt; //not needed at the moment
    return style
  }

  // getPropertyValue / setProperty hooks
  const StyleProto = CSSStyleDeclaration.prototype

  const oldGetP = StyleProto.getPropertyValue
  StyleProto.getPropertyValue = function (property) {
    this.lastPropertyServedBy = false
    property = property.trim()

    /* *
		if (this.owningElement) {
			const ieProperty = '-ieVar-'+property;
			const iePropertyImportant = '-ieVar-❗'+property;
			let value = this[iePropertyImportant] || this[ieProperty];
			if (value !== undefined) {
				// todo, test if syntax valid
				return value;
			}
		}
		/* */

    if (property[0] !== '-' || property[1] !== '-')
      return oldGetP.apply(this, arguments)
    const undashed = property.substr(2)
    const ieProperty = '-ie-' + undashed
    const iePropertyImportant = '-ie-❗' + undashed
    let value = decodeValue(this[iePropertyImportant] || this[ieProperty])

    if (this.computedFor) {
      // computedStyle
      if (value !== undefined && !inheritingKeywords[value]) {
        //if (regHasVar.test(value))  // todo: to i need this check?!!! i think its faster without
        value = styleComputeValueWidthVars(this, value)
        this.lastPropertyServedBy = this.computedFor
      } else {
        // inherited
        if (
          inheritingKeywords[value] ||
          !register[property] ||
          register[property].inherits
        ) {
          //let el = this.pseudoElt ? this.computedFor : this.computedFor.parentNode;
          let el = this.computedFor.parentNode
          while (el.nodeType === 1) {
            // how slower would it be to getComputedStyle for every element, not just with defined ieCP_setters
            if (el.ieCP_setters && el.ieCP_setters[property]) {
              // i could make
              // value = el.nodeType ? getComputedStyle(this.computedFor.parentNode).getPropertyValue(property)
              // but i fear performance, stupid?
              var style = getComputedStyle(el)
              var tmpVal = decodeValue(
                style[iePropertyImportant] || style[ieProperty]
              )
              if (tmpVal !== undefined) {
                // calculated style from current element not from the element the value was inherited from! (style, value)
                //value = tmpVal; if (regHasVar.test(tmpVal))  // todo: to i need this check?!!! i think its faster without
                value = styleComputeValueWidthVars(this, tmpVal)
                this.lastPropertyServedBy = el
                break
              }
            }
            el = el.parentNode
          }
        }
      }
      if (value === 'initial') return ''
    }
    //if ((value === undefined || value === 'initial') && register[property]) value = register[property].initialValue; // todo?
    if (value === undefined && register[property])
      value = register[property].initialValue
    if (value === undefined) return ''
    return value
  }
  const inheritingKeywords = { inherit: 1, revert: 1, unset: 1 }

  const oldSetP = StyleProto.setProperty
  StyleProto.setProperty = function (property, value, prio) {
    if (property[0] !== '-' || property[1] !== '-')
      return oldSetP.apply(this, arguments)
    const el = this.owningElement
    if (el) {
      if (!el.ieCP_setters) el.ieCP_setters = {}
      el.ieCP_setters[property] = 1
    }
    property = '-ie-' + (prio === 'important' ? '❗' : '') + property.substr(2)
    this.cssText += '; ' + property + ':' + encodeValue(value) + ';'
    //this[property] = value;
    el === document.documentElement && redrawStyleSheets()
    el && drawTree(el) // its delayed internal
  }

  /*
	var descriptor = Object.getOwnPropertyDescriptor(StyleProto, 'cssText');
	var cssTextGetter = descriptor.get;
	var cssTextSetter = descriptor.set;
	// descriptor.get = function () {
	// 	const style = styleGetter.call(this);
	// 	style.owningElement = this;
	// 	return style;
	// }
	descriptor.set = function (css) {
		var el = this.owningElement;
		if (el) {
			css = rewriteCss('{'+css).substr(1);
			cssTextSetter.call(this, css);
			var found = parseRewrittenStyle(this);
			if (found.getters) addGetterElement(el, found.getters, '%styleAttr');
			if (found.setters) addSetterElement(el, found.setters);
			return;
		}
		return cssTextSetter.call(this, css);
	}
	Object.defineProperty(StyleProto, 'cssText', descriptor);
	*/

  if (!window.CSS) window.CSS = {}
  const register = {}
  CSS.registerProperty = function (options) {
    register[options.name] = options
  }

  // fix "initial" keyword with generated custom properties, this is not supported ad all by ie, should i make a separate "inherit"-polyfill?
  /*
	const computed = getComputedStyle(document.documentElement)
	const initials = {};
	for (let i in computed) {
		initials[i.replace(/([A-Z])/, function(x){ return '-'+x.toLowerCase(x) })] = computed[i];
	}
	initials['display'] = 'inline';
	*/

  // utils
  function fetchCss(url, callback) {
    var request = new XMLHttpRequest()
    request.open('GET', url)
    request.overrideMimeType('text/css')
    request.onload = function () {
      if (request.status >= 200 && request.status < 400) {
        callback(request.responseText)
      }
    }
    request.send()
  }
})()
