<commit_before>/* global console, module, window, document, navigator, process */

;(function() {
  'use strict'

  var instances = []
  var lastUsedColorIndex = 0
  // Solarized accent colors http://ethanschoonover.com/solarized
  var colors = [
    '#B58900',
    '#CB4B16',
    '#DC322F',
    '#D33682',
    '#6C71C4',
    '#268BD2',
    '#2AA198',
    '#859900'
  ]
  // Taken from ansi-styles npm module
  // https://github.com/sindresorhus/ansi-styles/blob/master/index.js
  var ansiColors = {
    modifiers: {
      reset: [0, 0],
      bold: [1, 22], // 21 isn't widely supported and 22 does the same thing
      dim: [2, 22],
      italic: [3, 23],
      underline: [4, 24],
      inverse: [7, 27],
      hidden: [8, 28],
      strikethrough: [9, 29]
    },
    colors: {
      black: [30, 39],
      red: [31, 39],
      green: [32, 39],
      yellow: [33, 39],
      blue: [34, 39],
      magenta: [35, 39],
      cyan: [36, 39],
      white: [37, 39],
      gray: [90, 39]
    },
    bgColors: {
      bgBlack: [40, 49],
      bgRed: [41, 49],
      bgGreen: [42, 49],
      bgYellow: [43, 49],
      bgBlue: [44, 49],
      bgMagenta: [45, 49],
      bgCyan: [46, 49],
      bgWhite: [47, 49]
    }
  };
  var filterRegExps = []

  function Logdown(opts) {
    // Enforces new.
    if (!(this instanceof Logdown)) {
      return new Logdown(opts)
    }

    opts = opts || {}

    var prefix = opts.prefix === undefined ? '' : opts.prefix
    prefix = sanitizeStringToBrowser(prefix)
    if (prefix && isPrefixAlreadyInUse(prefix, instances)) {
      return getInstanceByPrefix(prefix, instances)
    }

    //
    this.markdown = opts.markdown === undefined ? true : opts.markdown
    this.prefix = prefix

    //
    instances.push(this)

    if (isBrowser()) {
      this.prefixColor = colors[lastUsedColorIndex % colors.length]
      lastUsedColorIndex += 1
    } else if (isNode()) {
      this.prefixColor = getNextPrefixColor()
    }

    return this
  }

  // Static
  // ------

  Logdown.enable = function() {
    Array.prototype.forEach.call(arguments, function(str) {
      if (str[0] === '-') {
        Logdown.disable(str.substr(1))
      }

      var regExp = prepareRegExpForPrefixSearch(str)

      if (str === '*') {
        filterRegExps = [{
          type: 'enable',
          regExp: regExp
        }]
      } else {
        filterRegExps.push({
          type: 'enable',
          regExp: regExp
        })
      }
    })
  }

  Logdown.disable = function() {
    Array.prototype.forEach.call(arguments, function(str) {
      if (str[0] === '-') {
        Logdown.enable(str.substr(1))
      }

      var regExp = prepareRegExpForPrefixSearch(str)

      if (str === '*') {
        filterRegExps = [{
          type: 'disable',
          regExp: regExp
        }]
      } else {
        filterRegExps.push({
          type: 'disable',
          regExp: regExp
        })
      }
    })
  }

  // Public
  // ------

  var methods = ['log', 'info', 'warn', 'error']
  methods.forEach(function(method) {
    Logdown.prototype[method] = function() {
      var preparedOutput
      var args = []

      if (isDisabled(this)) {
        return
      }

      var text = Array.prototype.slice.call(arguments, 0).join(' ');
      // var text = arguments[0];

      if (isBrowser()) {
        text = sanitizeStringToBrowser(text)
        preparedOutput = prepareOutputToBrowser(text, this)

        // IE9 workaround
        // http://stackoverflow.com/questions/5538972/
        //  console-log-apply-not-working-in-ie9
        Function.prototype.apply.call(
          console[method],
          console,
          [preparedOutput.parsedText]
            .concat(preparedOutput.styles, [preparedOutput.notText])
        )
      } else if (isNode()) {
        text = sanitizeStringToNode(text)
        preparedOutput = prepareOutputToNode(text, this)

        if (method === 'warn') {
          preparedOutput.parsedText =
            '\u001b[' + ansiColors.colors.yellow[0] + 'm' +
            '⚠' +
            '\u001b[' + ansiColors.colors.yellow[1] + 'm ' +
            preparedOutput.parsedText
        } else if (method === 'error') {
          preparedOutput.parsedText =
            '\u001b[' + ansiColors.colors.red[0] + 'm' +
            '✖' +
            '\u001b[' + ansiColors.colors.red[1] + 'm ' +
            preparedOutput.parsedText
        } else if (method === 'info') {
          preparedOutput.parsedText =
            '\u001b[' + ansiColors.colors.blue[0] + 'm' +
            'ℹ' +
            '\u001b[' + ansiColors.colors.blue[1] + 'm ' +
            preparedOutput.parsedText
        }

        //
        args.push(preparedOutput.parsedText)
        if (preparedOutput.notText) {
          args.push(preparedOutput.notText)
        }

        console[method].apply(
          console,
          args
        )
      }
    }
  })

  // Private
  // -------

  function parseMarkdown(text) {
    var styles = []
    var match = getNextMatch(text)

    while (match) {
      text = text.replace(match.rule.regexp, match.rule.replacer)

      if (isBrowser()) {
        styles.push(match.rule.style)
        styles.push('color:inherit;')
      }

      match = getNextMatch(text)
    }

    return {text: text, styles: styles}
  }

  function getNextMatch(text) {
    var matches = []
    var rules = []
    if (isBrowser()) {
      rules = [
        {
          regexp: /\*([^\*]+)\*/,
          replacer: function(match, submatch1) {
            return '%c' + submatch1 + '%c'
          },
          style: 'font-weight:bold;'
        },
        {
          regexp: /\_([^\_]+)\_/,
          replacer: function(match, submatch1) {
            return '%c' + submatch1 + '%c'
          },
          style: 'font-style:italic;'
        },
        {
          regexp: /\`([^\`]+)\`/,
          replacer: function(match, submatch1) {
            return '%c' + submatch1 + '%c';
          },
          style:
            'background:#FDF6E3; ' +
            'color:#586E75; ' +
            'padding:1px 5px; ' +
            'border-radius:4px;'
        }
      ]
    } else if (isNode()) {
      rules = [
        {
          regexp: /\*([^\*]+)\*/,
          replacer: function(match, submatch1) {
            return '\u001b[' + ansiColors.modifiers.bold[0] + 'm' +
                   submatch1 +
                   '\u001b[' + ansiColors.modifiers.bold[1] + 'm'
          }
        },
        {
          regexp: /\_([^\_]+)\_/,
          replacer: function(match, submatch1) {
            return '\u001b[' + ansiColors.modifiers.italic[0] + 'm' +
                   submatch1 +
                   '\u001b[' + ansiColors.modifiers.italic[1] + 'm'
          }
        },
        {
          regexp: /\`([^\`]+)\`/,
          replacer: function(match, submatch1) {
            return '\u001b[' + ansiColors.bgColors.bgYellow[0] + 'm' +
                   '\u001b[' + ansiColors.colors.black[0] + 'm' +
                   ' ' + submatch1 + ' ' +
                   '\u001b[' + ansiColors.colors.black[1] + 'm' +
                   '\u001b[' + ansiColors.bgColors.bgYellow[1] + 'm'
          }
        }
      ]
    }

    //
    rules.forEach(function(rule) {
      var match = text.match(rule.regexp)
      if (match) {
        matches.push({
          rule: rule,
          match: match
        })
      }
    })
    if (matches.length === 0) {
      return null;
    }

    //
    matches.sort(function(a, b) {
      return a.match.index - b.match.index
    })

    return matches[0]
  }

  function prepareOutputToBrowser(data, instance) {
    var parsedMarkdown
    var parsedText
    var styles
    //
    var notText

    if (typeof data === 'string') {
      if (instance.markdown &&
          isColorSupported()) {
        parsedMarkdown = parseMarkdown(data)
        parsedText = parsedMarkdown.text
        styles = parsedMarkdown.styles
      } else {
        parsedText = data
        styles = []
      }
    } else {
      parsedText = parsedText || ''
      styles = styles || []
      notText = data
    }

    if (instance.prefix) {
      if (isColorSupported()) {
        parsedText = '%c' + instance.prefix + '%c ' + parsedText
        styles.unshift(
          'color:' + instance.prefixColor + '; font-weight:bold;',
          'color:inherit;'
        )
      } else {
        parsedText = '[' + instance.prefix + '] ' + parsedText
      }
    }

    return {
      parsedText: parsedText,
      styles: styles,
      notText: notText
    }
  }

  function prepareOutputToNode(data, instance) {
    var parsedText = ''
    var notText

    if (instance.prefix) {
      if (isColorSupported()) {
        parsedText =
          '\u001b[' + instance.prefixColor[0] + 'm' +
          '\u001b[' + ansiColors.modifiers.bold[0] + 'm' +
          instance.prefix +
          '\u001b[' + ansiColors.modifiers.bold[1] + 'm' +
          '\u001b[' + instance.prefixColor[1] + 'm '
      } else {
        parsedText = '[' + instance.prefix + '] '
      }
    }

    if (typeof data === 'string') {
      if (instance.markdown) {
        parsedText += parseMarkdown(data).text
      } else {
        parsedText += data
      }
    } else {
      notText = data
    }

    return {
      parsedText: parsedText,
      styles: [],
      notText: notText
    }
  }

  function isDisabled(instance) {
    var isDisabled_ = false

    filterRegExps.forEach(function(filter) {
      if (filter.type === 'enable' && filter.regExp.test(instance.prefix)) {
        isDisabled_ = false
      } else if (filter.type === 'disable' &&
                 filter.regExp.test(instance.prefix)) {
        isDisabled_ = true
      }
    })

    return isDisabled_
  }

  function prepareRegExpForPrefixSearch(str) {
    return new RegExp('^' + str.replace(/\*/g, '.*?') + '$')
  }

  function isPrefixAlreadyInUse(prefix, instances) {
    var isPrefixAlreadyInUse_ = false

    instances.forEach(function(instance) {
      if (instance.prefix === prefix) {
        isPrefixAlreadyInUse_ = true
        return
      }
    })

    return isPrefixAlreadyInUse_
  }

  function getInstanceByPrefix(prefix, instances) {
    var instance

    instances.forEach(function(instanceCur) {
      if (instanceCur.prefix === prefix) {
        instance = instanceCur
        return
      }
    })

    return instance
  }

  function sanitizeStringToBrowser(str) {
    if (typeof str === 'string') {
      return str.replace(/\%c/g, '')
    } else {
      return str
    }
  }

  /**
   * Currently only WebKit-based Web Inspectors, Firefox >= v31,
   * and the Firebug extension (any Firefox version) are known
   * to support "%c" CSS customizations.
   *
   * Code took from https://github.com/visionmedia/debug/blob/master/browser.js
   */
  function isColorSupported() {
    if (isBrowser()) {
      // Is webkit? http://stackoverflow.com/a/16459606/376773
      var isWebkit = ('WebkitAppearance' in document.documentElement.style)
      // Is firebug? http://stackoverflow.com/a/398120/376773
      var isFirebug = (
        window.console &&
        (console.firebug || (console.exception && console.table))
      )
      // Is firefox >= v31?
      // https://developer.mozilla.org/en-US/docs/Tools/
      //  Web_Console#Styling_messages
      var isFirefox31Plus = (
        navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) &&
        parseInt(RegExp.$1, 10) >= 31
      )

      return (isWebkit || isFirebug || isFirefox31Plus)
    } else if (isNode()) {
      if (process.stdout && !process.stdout.isTTY) {
        return false;
      }

      if (process.platform === 'win32') {
        return true;
      }

      if ('COLORTERM' in process.env) {
        return true;
      }

      if (process.env.TERM === 'dumb') {
        return false;
      }

      if (
        /^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(process.env.TERM)
      ) {
        return true;
      }

      return false
    }
  }

  function isNode() {
    return (
      typeof module !== 'undefined' &&
      typeof module.exports !== 'undefined'
    )
  }

  function isBrowser() {
    return (typeof window !== 'undefined')
  }

  function sanitizeStringToNode(str) {
    return str;
  }

  var getNextPrefixColor = (function() {
    var lastUsed = 0
    var nodePrefixColors = [
      [31, 39], // red
      [32, 39], // green
      [33, 39], // yellow
      [34, 39], // blue
      [35, 39], // magenta
      [36, 39] // cyan
    ]

    return function() {
      return nodePrefixColors[(lastUsed += 1) % nodePrefixColors.length]
    }
  })()

  // Export module
  if (isNode()) {
    module.exports = Logdown
  } else if (isBrowser()) {
    window.Logdown = Logdown
  }
}())
<commit_msg>Update index.js<commit_after>/* global console, module, window, document, navigator, process */

;(function() {
  'use strict'

  var instances = []
  var lastUsedColorIndex = 0
  // Solarized accent colors http://ethanschoonover.com/solarized
  var colors = [
    '#B58900',
    '#CB4B16',
    '#DC322F',
    '#D33682',
    '#6C71C4',
    '#268BD2',
    '#2AA198',
    '#859900'
  ]
  // Taken from ansi-styles npm module
  // https://github.com/sindresorhus/ansi-styles/blob/master/index.js
  var ansiColors = {
    modifiers: {
      reset: [0, 0],
      bold: [1, 22], // 21 isn't widely supported and 22 does the same thing
      dim: [2, 22],
      italic: [3, 23],
      underline: [4, 24],
      inverse: [7, 27],
      hidden: [8, 28],
      strikethrough: [9, 29]
    },
    colors: {
      black: [30, 39],
      red: [31, 39],
      green: [32, 39],
      yellow: [33, 39],
      blue: [34, 39],
      magenta: [35, 39],
      cyan: [36, 39],
      white: [37, 39],
      gray: [90, 39]
    },
    bgColors: {
      bgBlack: [40, 49],
      bgRed: [41, 49],
      bgGreen: [42, 49],
      bgYellow: [43, 49],
      bgBlue: [44, 49],
      bgMagenta: [45, 49],
      bgCyan: [46, 49],
      bgWhite: [47, 49]
    }
  };
  var filterRegExps = []

  function Logdown(opts) {
    // Enforces new.
    if (!(this instanceof Logdown)) {
      return new Logdown(opts)
    }

    opts = opts || {}

    var prefix = opts.prefix === undefined ? '' : opts.prefix
    prefix = sanitizeStringToBrowser(prefix)
    if (prefix && isPrefixAlreadyInUse(prefix, instances)) {
      return getInstanceByPrefix(prefix, instances)
    }

    //
    this.markdown = opts.markdown === undefined ? true : opts.markdown
    this.prefix = prefix

    //
    instances.push(this)

    if (isBrowser()) {
      this.prefixColor = colors[lastUsedColorIndex % colors.length]
      lastUsedColorIndex += 1
    } else if (isNode()) {
      this.prefixColor = getNextPrefixColor()
    }

    return this
  }

  // Static
  // ------

  Logdown.enable = function() {
    Array.prototype.forEach.call(arguments, function(str) {
      if (str[0] === '-') {
        Logdown.disable(str.substr(1))
      }

      var regExp = prepareRegExpForPrefixSearch(str)

      if (str === '*') {
        filterRegExps = [{
          type: 'enable',
          regExp: regExp
        }]
      } else {
        filterRegExps.push({
          type: 'enable',
          regExp: regExp
        })
      }
    })
  }

  Logdown.disable = function() {
    Array.prototype.forEach.call(arguments, function(str) {
      if (str[0] === '-') {
        Logdown.enable(str.substr(1))
      }

      var regExp = prepareRegExpForPrefixSearch(str)

      if (str === '*') {
        filterRegExps = [{
          type: 'disable',
          regExp: regExp
        }]
      } else {
        filterRegExps.push({
          type: 'disable',
          regExp: regExp
        })
      }
    })
  }

  // Public
  // ------

  var methods = ['log', 'info', 'warn', 'error']
  methods.forEach(function(method) {
    Logdown.prototype[method] = function() {
      var preparedOutput
      var args = []

      if (isDisabled(this)) {
        return
      }

      var text = Array.prototype.slice.call(arguments, 0).join(' ');
      // var text = arguments[0];

      if (isBrowser()) {
        text = sanitizeStringToBrowser(text)
        preparedOutput = prepareOutputToBrowser(text, this)

        // IE9 workaround
        // http://stackoverflow.com/questions/5538972/
        //  console-log-apply-not-working-in-ie9
        Function.prototype.apply.call(
          console[method],
          console,
          [preparedOutput.parsedText]
            .concat(preparedOutput.styles,
                          'undefined' !== typeof preparedOutput.notText? [preparedOutput.notText] : '')
        )
      } else if (isNode()) {
        text = sanitizeStringToNode(text)
        preparedOutput = prepareOutputToNode(text, this)

        if (method === 'warn') {
          preparedOutput.parsedText =
            '\u001b[' + ansiColors.colors.yellow[0] + 'm' +
            '⚠' +
            '\u001b[' + ansiColors.colors.yellow[1] + 'm ' +
            preparedOutput.parsedText
        } else if (method === 'error') {
          preparedOutput.parsedText =
            '\u001b[' + ansiColors.colors.red[0] + 'm' +
            '✖' +
            '\u001b[' + ansiColors.colors.red[1] + 'm ' +
            preparedOutput.parsedText
        } else if (method === 'info') {
          preparedOutput.parsedText =
            '\u001b[' + ansiColors.colors.blue[0] + 'm' +
            'ℹ' +
            '\u001b[' + ansiColors.colors.blue[1] + 'm ' +
            preparedOutput.parsedText
        }

        //
        args.push(preparedOutput.parsedText)
        if (preparedOutput.notText) {
          args.push(preparedOutput.notText)
        }

        console[method].apply(
          console,
          args
        )
      }
    }
  })

  // Private
  // -------

  function parseMarkdown(text) {
    var styles = []
    var match = getNextMatch(text)

    while (match) {
      text = text.replace(match.rule.regexp, match.rule.replacer)

      if (isBrowser()) {
        styles.push(match.rule.style)
        styles.push('color:inherit;')
      }

      match = getNextMatch(text)
    }

    return {text: text, styles: styles}
  }

  function getNextMatch(text) {
    var matches = []
    var rules = []
    if (isBrowser()) {
      rules = [
        {
          regexp: /\*([^\*]+)\*/,
          replacer: function(match, submatch1) {
            return '%c' + submatch1 + '%c'
          },
          style: 'font-weight:bold;'
        },
        {
          regexp: /\_([^\_]+)\_/,
          replacer: function(match, submatch1) {
            return '%c' + submatch1 + '%c'
          },
          style: 'font-style:italic;'
        },
        {
          regexp: /\`([^\`]+)\`/,
          replacer: function(match, submatch1) {
            return '%c' + submatch1 + '%c';
          },
          style:
            'background:#FDF6E3; ' +
            'color:#586E75; ' +
            'padding:1px 5px; ' +
            'border-radius:4px;'
        }
      ]
    } else if (isNode()) {
      rules = [
        {
          regexp: /\*([^\*]+)\*/,
          replacer: function(match, submatch1) {
            return '\u001b[' + ansiColors.modifiers.bold[0] + 'm' +
                   submatch1 +
                   '\u001b[' + ansiColors.modifiers.bold[1] + 'm'
          }
        },
        {
          regexp: /\_([^\_]+)\_/,
          replacer: function(match, submatch1) {
            return '\u001b[' + ansiColors.modifiers.italic[0] + 'm' +
                   submatch1 +
                   '\u001b[' + ansiColors.modifiers.italic[1] + 'm'
          }
        },
        {
          regexp: /\`([^\`]+)\`/,
          replacer: function(match, submatch1) {
            return '\u001b[' + ansiColors.bgColors.bgYellow[0] + 'm' +
                   '\u001b[' + ansiColors.colors.black[0] + 'm' +
                   ' ' + submatch1 + ' ' +
                   '\u001b[' + ansiColors.colors.black[1] + 'm' +
                   '\u001b[' + ansiColors.bgColors.bgYellow[1] + 'm'
          }
        }
      ]
    }

    //
    rules.forEach(function(rule) {
      var match = text.match(rule.regexp)
      if (match) {
        matches.push({
          rule: rule,
          match: match
        })
      }
    })
    if (matches.length === 0) {
      return null;
    }

    //
    matches.sort(function(a, b) {
      return a.match.index - b.match.index
    })

    return matches[0]
  }

  function prepareOutputToBrowser(data, instance) {
    var parsedMarkdown
    var parsedText
    var styles
    //
    var notText

    if (typeof data === 'string') {
      if (instance.markdown &&
          isColorSupported()) {
        parsedMarkdown = parseMarkdown(data)
        parsedText = parsedMarkdown.text
        styles = parsedMarkdown.styles
      } else {
        parsedText = data
        styles = []
      }
    } else {
      parsedText = parsedText || ''
      styles = styles || []
      notText = data
    }

    if (instance.prefix) {
      if (isColorSupported()) {
        parsedText = '%c' + instance.prefix + '%c ' + parsedText
        styles.unshift(
          'color:' + instance.prefixColor + '; font-weight:bold;',
          'color:inherit;'
        )
      } else {
        parsedText = '[' + instance.prefix + '] ' + parsedText
      }
    }

    return {
      parsedText: parsedText,
      styles: styles,
      notText: notText
    }
  }

  function prepareOutputToNode(data, instance) {
    var parsedText = ''
    var notText

    if (instance.prefix) {
      if (isColorSupported()) {
        parsedText =
          '\u001b[' + instance.prefixColor[0] + 'm' +
          '\u001b[' + ansiColors.modifiers.bold[0] + 'm' +
          instance.prefix +
          '\u001b[' + ansiColors.modifiers.bold[1] + 'm' +
          '\u001b[' + instance.prefixColor[1] + 'm '
      } else {
        parsedText = '[' + instance.prefix + '] '
      }
    }

    if (typeof data === 'string') {
      if (instance.markdown) {
        parsedText += parseMarkdown(data).text
      } else {
        parsedText += data
      }
    } else {
      notText = data
    }

    return {
      parsedText: parsedText,
      styles: [],
      notText: notText
    }
  }

  function isDisabled(instance) {
    var isDisabled_ = false

    filterRegExps.forEach(function(filter) {
      if (filter.type === 'enable' && filter.regExp.test(instance.prefix)) {
        isDisabled_ = false
      } else if (filter.type === 'disable' &&
                 filter.regExp.test(instance.prefix)) {
        isDisabled_ = true
      }
    })

    return isDisabled_
  }

  function prepareRegExpForPrefixSearch(str) {
    return new RegExp('^' + str.replace(/\*/g, '.*?') + '$')
  }

  function isPrefixAlreadyInUse(prefix, instances) {
    var isPrefixAlreadyInUse_ = false

    instances.forEach(function(instance) {
      if (instance.prefix === prefix) {
        isPrefixAlreadyInUse_ = true
        return
      }
    })

    return isPrefixAlreadyInUse_
  }

  function getInstanceByPrefix(prefix, instances) {
    var instance

    instances.forEach(function(instanceCur) {
      if (instanceCur.prefix === prefix) {
        instance = instanceCur
        return
      }
    })

    return instance
  }

  function sanitizeStringToBrowser(str) {
    if (typeof str === 'string') {
      return str.replace(/\%c/g, '')
    } else {
      return str
    }
  }

  /**
   * Currently only WebKit-based Web Inspectors, Firefox >= v31,
   * and the Firebug extension (any Firefox version) are known
   * to support "%c" CSS customizations.
   *
   * Code took from https://github.com/visionmedia/debug/blob/master/browser.js
   */
  function isColorSupported() {
    if (isBrowser()) {
      // Is webkit? http://stackoverflow.com/a/16459606/376773
      var isWebkit = ('WebkitAppearance' in document.documentElement.style)
      // Is firebug? http://stackoverflow.com/a/398120/376773
      var isFirebug = (
        window.console &&
        (console.firebug || (console.exception && console.table))
      )
      // Is firefox >= v31?
      // https://developer.mozilla.org/en-US/docs/Tools/
      //  Web_Console#Styling_messages
      var isFirefox31Plus = (
        navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) &&
        parseInt(RegExp.$1, 10) >= 31
      )

      return (isWebkit || isFirebug || isFirefox31Plus)
    } else if (isNode()) {
      if (process.stdout && !process.stdout.isTTY) {
        return false;
      }

      if (process.platform === 'win32') {
        return true;
      }

      if ('COLORTERM' in process.env) {
        return true;
      }

      if (process.env.TERM === 'dumb') {
        return false;
      }

      if (
        /^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(process.env.TERM)
      ) {
        return true;
      }

      return false
    }
  }

  function isNode() {
    return (
      typeof module !== 'undefined' &&
      typeof module.exports !== 'undefined'
    )
  }

  function isBrowser() {
    return (typeof window !== 'undefined')
  }

  function sanitizeStringToNode(str) {
    return str;
  }

  var getNextPrefixColor = (function() {
    var lastUsed = 0
    var nodePrefixColors = [
      [31, 39], // red
      [32, 39], // green
      [33, 39], // yellow
      [34, 39], // blue
      [35, 39], // magenta
      [36, 39] // cyan
    ]

    return function() {
      return nodePrefixColors[(lastUsed += 1) % nodePrefixColors.length]
    }
  })()

  // Export module
  if (isNode()) {
    module.exports = Logdown
  } else if (isBrowser()) {
    window.Logdown = Logdown
  }
}())
<|endoftext|>


<commit_before>/*jshint node:true*/
/*global describe:false, it:false, beforeEach:false, afterEach: false*/
'use strict';

var cli = require('../lib/cli');
var plugins = require('../lib/plugins');
var spawn = require('child_process').spawn;
var path = require('path');
var fs = require('fs');
var expect = require('chai').expect;
var helpers = require('./helpers');

// ---

var readOut = helpers.readOut;

function comparePath(filePath) {
  return path.join(__dirname, 'compare', filePath);
}

// ---

describe('Command line interface', function() {

  /**
   * Spawn a child process calling the bin file with the specified options
   * @param {String} options Same as you would pass in the command line
   * @param {String} input Standard input
   * @param {Function} testCallback It receives the formatted file
   */
  var spawnEsformatter = function(id, options, input, testCallback) {
    var args = [path.join(__dirname, '../bin/esformatter')];
    if (typeof options === 'function') {
      testCallback = options;
      options = null;
    } else if (typeof input === 'function') {
      testCallback = input;
      input = null;
    }
    if (options) {
      args = args.concat(options.split(' '));
    }
    it('[cli ' + id + '] ' + options, function(mochaCallback) {
      var childprocess = spawn('node', args, {
        stdio: ['pipe', 'pipe', 'pipe']
      });
      var output = '';
      var errorInChildProcess = '';
      childprocess.stdout.on('data', function(data) {
        output += data.toString();
      });
      childprocess.stderr.on('data', function(data) {
        errorInChildProcess += data.toString();
      });
      childprocess.on('exit', function() {
        if (errorInChildProcess) {
          testCallback(new Error(errorInChildProcess));
          // we don't check for the error directly because sometimes we want
          // to test if the error is what we expect
          mochaCallback();
        } else {
          try {
            // There is an extra line feed from piping stdout
            testCallback(helpers.lineFeed(output));
            mochaCallback();
          } catch (ex) {
            mochaCallback(ex);
          }
        }
      });
      if (input) {
        try {
          var textInput = fs.readFileSync(input, 'utf-8');
          childprocess.stdin.write(textInput);
          childprocess.stdin.end();
        } catch (ex) {
          mochaCallback(ex);
        }
      }
    });
  };

  // this is much faster than spawning a childprocess, so we favor it when
  // possible (stdin tests still use the spawnEsformatter for now)
  function testCLI(id, options, testCallback) {
    it('[cli ' + id + '] ' + options.join(' '), function(mochaCallback) {

      var errors;
      var data;

      function mockCLI() {
        errors = '';
        data = '';

        cli.stdout = {
          write: function(msg) {
            data += msg;
          }
        };
        cli.stderr = {
          write: function(msg) {
            errors += msg;
          }
        };
      }

      function unmockCLI() {
        cli.stdout = process.stdout;
        cli.stderr = process.stderr;
        // otherwise registered plugins would persist between runs
        plugins.unregisterAll();
      }

      try {

        mockCLI();
        cli.run(cli.parse(options));
        unmockCLI();

        if (cli.exitCode) {
          testCallback(new Error(errors));
        } else {
          testCallback(data);
        }

        mochaCallback();
      } catch (err) {
        unmockCLI();
        mochaCallback(err);
      }
    });
  }

  // Format a file with default options
  testCLI(
    'default',
    ['--preset=default', comparePath('default/array_expression-in.js')],
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/default/array_expression'));
    }
  );

  // Format a file specifying some options
  testCLI(
    'config',
    [
      '--config',
      comparePath('custom/basic_function_indent-config.json'),
      comparePath('custom/basic_function_indent-in.js')
    ],
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/custom/basic_function_indent'));
    }
  );

  // Format file with jquery preset
  testCLI(
    'preset',
    ['--preset', 'jquery', comparePath('jquery/spacing-in.js')],
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/jquery/spacing'));
    }
  );

  // use settings from package.json file
  testCLI(
    'package.json',
    [comparePath('rc/package/package-in.js')],
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/rc/package/package'));
    }
  );

  // use settings from .esformatter file
  testCLI('rc', [comparePath('rc/top-in.js')], function(formattedFile) {
    expect(formattedFile).to.equal(readOut('/rc/top'));
  });

  // use settings from .esformatter file
  testCLI('rc nested', [comparePath('rc/nested/nested-in.js')], function(formattedFile) {
    expect(formattedFile).to.equal(readOut('/rc/nested/nested'));
  });

  // make sure .esformatter file have higher priority than package.json
  testCLI(
    'rc nested package',
    [comparePath('rc/package/rc/nested-in.js')],
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/rc/package/rc/nested'));
    }
  );

  // make sure .esformatter file have higher priority than package.json and
  // that configs are merged even if inside same folder
  testCLI(
    'nested package+rc',
    [comparePath('rc/package/nested/pkg_nested-in.js')],
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/rc/package/nested/pkg_nested'));
    }
  );

  // make sure it shows descriptive error message when config doesn't exist
  testCLI(
    'invalid config',
    ['-c', 'non-existent.json', comparePath('default/call_expression-in.js')],
    function(formattedFile) {
      expect(formattedFile.message).to.contain("Can't parse configuration file 'non-existent.json'");
    }
  );

  // make sure it shows descriptive error message when config file isn't valid
  testCLI(
    'invalid config 2',
    ['-c', comparePath('error/invalid.json'), comparePath('default/call_expression-in.js')],
    function(formattedFile) {
      var configPath = comparePath('error/invalid.json');
      expect(formattedFile.message).to.contain(
        "Can't parse configuration file '" + configPath + "'. Exception: Unexpected token l"
      );
    }
  );

  // make sure it shows descriptive error message when file doesn't exist
  testCLI('invalid file', ['fake-esformatter-123.js'], function(formattedFile) {
    expect(formattedFile.message).to.contain("Error: Can't read source file.");
    expect(formattedFile.message).to.contain("fake-esformatter-123.js");
  });

  // comments should be allowed on config.json files
  testCLI(
    'config', [
      '--config',
      comparePath('custom/commented_config-config.json'),
      comparePath('custom/commented_config-in.js')
    ],
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/custom/commented_config'));
    }
  );

  // plugins should be loaded from node_modules
  testCLI(
    'local plugin',
    [
      '--config',
      comparePath('custom/commented_config-config.json'),
      '--plugins',
      'esformatter-test-plugin',
      comparePath('custom/commented_config-in.js')
    ],
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/custom/commented_config').replace(/true/, 'false'));
    }
  );

  // glob expansion
  testCLI(
    'glob',
    [comparePath('default/arr*-in.js')],
    function(result) {
      expect(result).to.equal(
        readOut('default/array_expression') +
        readOut('default/array_pattern') +
        readOut('default/arrow_function_expression')
      );
    }
  );

  // glob expansion + ignore
  testCLI(
    'glob ignore',
    ['--ignore', '**/*_pattern-in.js', comparePath('default/arr*-in.js')],
    function(result) {
      expect(result).to.equal(
        readOut('default/array_expression') +
        readOut('default/arrow_function_expression')
      );
    }
  );

  // glob + multiple ignore
  testCLI(
    'glob ignore multi',
    [
      '--ignore',
      '**/*_pattern-in.js',
      '--ignore',
      '**/array_expression-in.js',
      comparePath('default/arr*-in.js')
    ],
    function(result) {
      expect(result).to.equal(
        readOut('default/arrow_function_expression')
      );
    }
  );

  // invalid glob expansion should throw error
  testCLI(
    'glob invalid',
    [comparePath('default/fake-file*-in.js')],
    function(formattedFile) {
      var msg = formattedFile.message.trim();
      var filePath = comparePath('default/fake-file*-in.js');
      expect(msg).to.contain("Error: Can't read source file.");
      expect(msg).to.contain(filePath);
    }
  );

  // invalid JS files should throw errors
  testCLI('invalid js', [comparePath('error/invalid-*.js')], function(formattedFile) {
    var msg = formattedFile.message;
    // using match because of absolute path and also because file order might
    // be different in some OS. we just make sure that error message contains
    // what we expect to find
    expect(msg).to.match(/Error: .+invalid-1.js:4:0 Unexpected token/);
    expect(msg).to.match(/Error: .+invalid-2.js:3:9 Invalid regular expression/);
  });

  describe('modify file in place', function() {
    var cpInPlace = comparePath('default/inplace-in.js.copy');
    var expectedInPlace = comparePath('default/inplace-out.js');

    beforeEach(function() {
      fs.writeFileSync(cpInPlace, fs.readFileSync(comparePath('default/inplace-in.js')));
    });

    afterEach(function() {
      fs.unlinkSync(cpInPlace);
    });

    testCLI('default', ['-i', cpInPlace], function(formattedFile) {
      // in place option should modify the input file and not output any data
      expect(formattedFile).to.equal('');
      expect(fs.readFileSync(cpInPlace, {
        encoding: 'utf8'
      })).to.equal(fs.readFileSync(expectedInPlace, {
        encoding: 'utf8'
      }));
    });
  });

  // -----------------------------
  // SLOW TESTS are executed later
  // -----------------------------

  // Format a file from standard input
  spawnEsformatter(
    'stdin',
    '--preset=default',
    comparePath('default/assignment_expression-in.js'),
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/default/assignment_expression'));
    }
  );

  // Format a file from standard input with options
  spawnEsformatter(
    'stdin+config',
    '--config ' + comparePath('custom/call_expression-config.json'),
    comparePath('custom/call_expression-in.js'),
    function(formattedFile) {
      expect(formattedFile).to.equal(readOut('/custom/call_expression'));
    }
  );

  // it should use locally installed esformatter version if available
  spawnEsformatter(
    'local install',
    ['--config', path.join(__dirname, 'bin/config.json'), comparePath('custom/commented_config-in.js')].join(' '),
    function(formattedFile) {
      expect(formattedFile.trim()).to.equal('fake-esformatter v0.0.0-alpha');
    }
  );

});
<commit_msg>s/formattedFile/result/<commit_after>/*jshint node:true*/
/*global describe:false, it:false, beforeEach:false, afterEach: false*/
'use strict';

var cli = require('../lib/cli');
var plugins = require('../lib/plugins');
var spawn = require('child_process').spawn;
var path = require('path');
var fs = require('fs');
var expect = require('chai').expect;
var helpers = require('./helpers');

// ---

var readOut = helpers.readOut;

function comparePath(filePath) {
  return path.join(__dirname, 'compare', filePath);
}

// ---

describe('Command line interface', function() {

  /**
   * Spawn a child process calling the bin file with the specified options
   * @param {String} options Same as you would pass in the command line
   * @param {String} input Standard input
   * @param {Function} testCallback It receives the formatted file
   */
  var spawnEsformatter = function(id, options, input, testCallback) {
    var args = [path.join(__dirname, '../bin/esformatter')];
    if (typeof options === 'function') {
      testCallback = options;
      options = null;
    } else if (typeof input === 'function') {
      testCallback = input;
      input = null;
    }
    if (options) {
      args = args.concat(options.split(' '));
    }
    it('[cli ' + id + '] ' + options, function(mochaCallback) {
      var childprocess = spawn('node', args, {
        stdio: ['pipe', 'pipe', 'pipe']
      });
      var output = '';
      var errorInChildProcess = '';
      childprocess.stdout.on('data', function(data) {
        output += data.toString();
      });
      childprocess.stderr.on('data', function(data) {
        errorInChildProcess += data.toString();
      });
      childprocess.on('exit', function() {
        if (errorInChildProcess) {
          testCallback(new Error(errorInChildProcess));
          // we don't check for the error directly because sometimes we want
          // to test if the error is what we expect
          mochaCallback();
        } else {
          try {
            // There is an extra line feed from piping stdout
            testCallback(helpers.lineFeed(output));
            mochaCallback();
          } catch (ex) {
            mochaCallback(ex);
          }
        }
      });
      if (input) {
        try {
          var textInput = fs.readFileSync(input, 'utf-8');
          childprocess.stdin.write(textInput);
          childprocess.stdin.end();
        } catch (ex) {
          mochaCallback(ex);
        }
      }
    });
  };

  // this is much faster than spawning a childprocess, so we favor it when
  // possible (stdin tests still use the spawnEsformatter for now)
  function testCLI(id, options, testCallback) {
    it('[cli ' + id + '] ' + options.join(' '), function(mochaCallback) {

      var errors;
      var data;

      function mockCLI() {
        errors = '';
        data = '';

        cli.stdout = {
          write: function(msg) {
            data += msg;
          }
        };
        cli.stderr = {
          write: function(msg) {
            errors += msg;
          }
        };
      }

      function unmockCLI() {
        cli.stdout = process.stdout;
        cli.stderr = process.stderr;
        // otherwise registered plugins would persist between runs
        plugins.unregisterAll();
      }

      try {

        mockCLI();
        cli.run(cli.parse(options));
        unmockCLI();

        if (cli.exitCode) {
          testCallback(new Error(errors));
        } else {
          testCallback(data);
        }

        mochaCallback();
      } catch (err) {
        unmockCLI();
        mochaCallback(err);
      }
    });
  }

  // Format a file with default options
  testCLI(
    'default',
    ['--preset=default', comparePath('default/array_expression-in.js')],
    function(result) {
      expect(result).to.equal(readOut('/default/array_expression'));
    }
  );

  // Format a file specifying some options
  testCLI(
    'config',
    [
      '--config',
      comparePath('custom/basic_function_indent-config.json'),
      comparePath('custom/basic_function_indent-in.js')
    ],
    function(result) {
      expect(result).to.equal(readOut('/custom/basic_function_indent'));
    }
  );

  // Format file with jquery preset
  testCLI(
    'preset',
    ['--preset', 'jquery', comparePath('jquery/spacing-in.js')],
    function(result) {
      expect(result).to.equal(readOut('/jquery/spacing'));
    }
  );

  // use settings from package.json file
  testCLI(
    'package.json',
    [comparePath('rc/package/package-in.js')],
    function(result) {
      expect(result).to.equal(readOut('/rc/package/package'));
    }
  );

  // use settings from .esformatter file
  testCLI('rc', [comparePath('rc/top-in.js')], function(result) {
    expect(result).to.equal(readOut('/rc/top'));
  });

  // use settings from .esformatter file
  testCLI('rc nested', [comparePath('rc/nested/nested-in.js')], function(result) {
    expect(result).to.equal(readOut('/rc/nested/nested'));
  });

  // make sure .esformatter file have higher priority than package.json
  testCLI(
    'rc nested package',
    [comparePath('rc/package/rc/nested-in.js')],
    function(result) {
      expect(result).to.equal(readOut('/rc/package/rc/nested'));
    }
  );

  // make sure .esformatter file have higher priority than package.json and
  // that configs are merged even if inside same folder
  testCLI(
    'nested package+rc',
    [comparePath('rc/package/nested/pkg_nested-in.js')],
    function(result) {
      expect(result).to.equal(readOut('/rc/package/nested/pkg_nested'));
    }
  );

  // make sure it shows descriptive error message when config doesn't exist
  testCLI(
    'invalid config',
    ['-c', 'non-existent.json', comparePath('default/call_expression-in.js')],
    function(result) {
      expect(result.message).to.contain("Can't parse configuration file 'non-existent.json'");
    }
  );

  // make sure it shows descriptive error message when config file isn't valid
  testCLI(
    'invalid config 2',
    ['-c', comparePath('error/invalid.json'), comparePath('default/call_expression-in.js')],
    function(result) {
      var configPath = comparePath('error/invalid.json');
      expect(result.message).to.contain(
        "Can't parse configuration file '" + configPath + "'. Exception: Unexpected token l"
      );
    }
  );

  // make sure it shows descriptive error message when file doesn't exist
  testCLI('invalid file', ['fake-esformatter-123.js'], function(result) {
    expect(result.message).to.contain("Error: Can't read source file.");
    expect(result.message).to.contain("fake-esformatter-123.js");
  });

  // comments should be allowed on config.json files
  testCLI(
    'config', [
      '--config',
      comparePath('custom/commented_config-config.json'),
      comparePath('custom/commented_config-in.js')
    ],
    function(result) {
      expect(result).to.equal(readOut('/custom/commented_config'));
    }
  );

  // plugins should be loaded from node_modules
  testCLI(
    'local plugin',
    [
      '--config',
      comparePath('custom/commented_config-config.json'),
      '--plugins',
      'esformatter-test-plugin',
      comparePath('custom/commented_config-in.js')
    ],
    function(result) {
      expect(result).to.equal(readOut('/custom/commented_config').replace(/true/, 'false'));
    }
  );

  // glob expansion
  testCLI(
    'glob',
    [comparePath('default/arr*-in.js')],
    function(result) {
      expect(result).to.equal(
        readOut('default/array_expression') +
        readOut('default/array_pattern') +
        readOut('default/arrow_function_expression')
      );
    }
  );

  // glob expansion + ignore
  testCLI(
    'glob ignore',
    ['--ignore', '**/*_pattern-in.js', comparePath('default/arr*-in.js')],
    function(result) {
      expect(result).to.equal(
        readOut('default/array_expression') +
        readOut('default/arrow_function_expression')
      );
    }
  );

  // glob + multiple ignore
  testCLI(
    'glob ignore multi',
    [
      '--ignore',
      '**/*_pattern-in.js',
      '--ignore',
      '**/array_expression-in.js',
      comparePath('default/arr*-in.js')
    ],
    function(result) {
      expect(result).to.equal(
        readOut('default/arrow_function_expression')
      );
    }
  );

  // invalid glob expansion should throw error
  testCLI(
    'glob invalid',
    [comparePath('default/fake-file*-in.js')],
    function(result) {
      var msg = result.message.trim();
      var filePath = comparePath('default/fake-file*-in.js');
      expect(msg).to.contain("Error: Can't read source file.");
      expect(msg).to.contain(filePath);
    }
  );

  // invalid JS files should throw errors
  testCLI('invalid js', [comparePath('error/invalid-*.js')], function(result) {
    var msg = result.message;
    // using match because of absolute path and also because file order might
    // be different in some OS. we just make sure that error message contains
    // what we expect to find
    expect(msg).to.match(/Error: .+invalid-1.js:4:0 Unexpected token/);
    expect(msg).to.match(/Error: .+invalid-2.js:3:9 Invalid regular expression/);
  });

  describe('modify file in place', function() {
    var cpInPlace = comparePath('default/inplace-in.js.copy');
    var expectedInPlace = comparePath('default/inplace-out.js');

    beforeEach(function() {
      fs.writeFileSync(cpInPlace, fs.readFileSync(comparePath('default/inplace-in.js')));
    });

    afterEach(function() {
      fs.unlinkSync(cpInPlace);
    });

    testCLI('default', ['-i', cpInPlace], function(result) {
      // in place option should modify the input file and not output any data
      expect(result).to.equal('');
      expect(fs.readFileSync(cpInPlace, {
        encoding: 'utf8'
      })).to.equal(fs.readFileSync(expectedInPlace, {
        encoding: 'utf8'
      }));
    });
  });

  // -----------------------------
  // SLOW TESTS are executed later
  // -----------------------------

  // Format a file from standard input
  spawnEsformatter(
    'stdin',
    '--preset=default',
    comparePath('default/assignment_expression-in.js'),
    function(result) {
      expect(result).to.equal(readOut('/default/assignment_expression'));
    }
  );

  // Format a file from standard input with options
  spawnEsformatter(
    'stdin+config',
    '--config ' + comparePath('custom/call_expression-config.json'),
    comparePath('custom/call_expression-in.js'),
    function(result) {
      expect(result).to.equal(readOut('/custom/call_expression'));
    }
  );

  // it should use locally installed esformatter version if available
  spawnEsformatter(
    'local install',
    ['--config', path.join(__dirname, 'bin/config.json'), comparePath('custom/commented_config-in.js')].join(' '),
    function(result) {
      expect(result.trim()).to.equal('fake-esformatter v0.0.0-alpha');
    }
  );

});
<|endoftext|>


<commit_before>import React from 'react';
import styled from 'styled-components';

const Table = styled('div').attrs({
  className: 'sticky-table-table'
})`
  white-space: nowrap;
  display: table;
  box-sizing: border-box;
`;

Table.displayName = 'Table';

const Row = styled('div').attrs({
  className: 'sticky-table-row'
})`
  display: table-row;

  & ${Cell}:first-child {
    border-right: 2px solid #e5e5e5;
  }
`;

Row.displayName = 'Row';

const Cell = styled('div').attrs({
  className: 'sticky-table-cell'
})`
  display: table-cell;
  box-sizing: border-box;

  padding: 0.5rem 0.75rem;
  border-bottom: 2px solid #e5e5e5;
  background-color: #fff;
`;

Cell.displayName = 'Cell';

const Wrapper = styled('div').attrs({
  className: 'sticky-table'
})`
  position: relative;
  overflow: auto;
  height: 100%;
  box-sizing: border-box;

  & ${Row}:nth-child(${props => `-n+${props.stickyHeaderCount}`}) ${Cell} {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
    z-index: 2;
  }

  & ${Row} ${Cell}:nth-child(-n+${props => props.stickyColumnCount}) {
    position: -webkit-sticky;
    position: sticky;
    left: 0;
    z-index: 2;
  }
  & ${Row}:nth-child(-n+${props =>
  props.stickyHeaderCount}) ${Cell}:nth-child(-n+${props =>
  props.stickyColumnCount}) {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
    left: 0;
    z-index: 3;

    &:first-child {
      border-right: 2px solid #e5e5e5;
    }
  }
`;

Wrapper.displayName = 'Wrapper';

function StickyTable({
  stickyColumnCount = 1,
  stickyHeaderCount = 1,
  children,
  ...rest
}) {
  return (
    <Wrapper
      stickyColumnCount={stickyColumnCount}
      stickyHeaderCount={stickyHeaderCount}
      {...rest}
    >

{children}

    </Wrapper>
  );
}

export { StickyTable, Table, Row, Cell };
<commit_msg>Cell needs to be defined before Row<commit_after>import React from 'react';
import styled from 'styled-components';

const Table = styled('div').attrs({
  className: 'sticky-table-table'
})`
  white-space: nowrap;
  display: table;
  box-sizing: border-box;
`;

Table.displayName = 'Table';

const Cell = styled('div').attrs({
  className: 'sticky-table-cell'
})`
  display: table-cell;
  box-sizing: border-box;

  padding: 0.5rem 0.75rem;
  border-bottom: 2px solid #e5e5e5;
  background-color: #fff;
`;

Cell.displayName = 'Cell';

const Row = styled('div').attrs({
  className: 'sticky-table-row'
})`
  display: table-row;

  & ${Cell}:first-child {
    border-right: 2px solid #e5e5e5;
  }
`;

Row.displayName = 'Row';

const Wrapper = styled('div').attrs({
  className: 'sticky-table'
})`
  position: relative;
  overflow: auto;
  height: 100%;
  box-sizing: border-box;

  & ${Row}:nth-child(${props => `-n+${props.stickyHeaderCount}`}) ${Cell} {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
    z-index: 2;
  }

  & ${Row} ${Cell}:nth-child(-n+${props => props.stickyColumnCount}) {
    position: -webkit-sticky;
    position: sticky;
    left: 0;
    z-index: 2;
  }
  & ${Row}:nth-child(-n+${props =>
  props.stickyHeaderCount}) ${Cell}:nth-child(-n+${props =>
  props.stickyColumnCount}) {
    position: -webkit-sticky;
    position: sticky;
    top: 0;
    left: 0;
    z-index: 3;

    &:first-child {
      border-right: 2px solid #e5e5e5;
    }
  }
`;

Wrapper.displayName = 'Wrapper';

function StickyTable({
  stickyColumnCount = 1,
  stickyHeaderCount = 1,
  children,
  ...rest
}) {
  return (
    <Wrapper
      stickyColumnCount={stickyColumnCount}
      stickyHeaderCount={stickyHeaderCount}
      {...rest}
    >

{children}

    </Wrapper>
  );
}

export { StickyTable, Table, Row, Cell };
<|endoftext|>


<commit_before>function getBaseClass(block, element) {
  return !element ? block : `${block}__${element}`;
}

function addModifier(baseClass, modifier) {
  return modifier ? `${baseClass}--${modifier}` : null;
}

function getClassArray(block, element, modifiers = []) {
  const baseClass = getBaseClass(block, element);
  const modifierFn = addModifier.bind(null, baseClass);
  return [baseClass].concat(modifiers.map(modifierFn));
}

function getClassesAsString(block, element, modifiers) {
  return getClassArray(block, element, modifiers).join(' ');
}

function bemmit(block) {
  return getClassesAsString.bind(null, block);
}

module.exports = bemmit;
<commit_msg>fix(modifiers): disallow empty modifiers<commit_after>function getBaseClass(block, element) {
  return !element ? block : `${block}__${element}`;
}

function addModifier(baseClass, modifier) {
  return modifier ? `${baseClass}--${modifier}` : null;
}

function getClassArray(block, element, modifiers = []) {
  const baseClass = getBaseClass(block, element);
  const modifierFn = addModifier.bind(null, baseClass);
  return [baseClass].concat(modifiers.map(modifierFn)).filter(c => c);
}

function getClassesAsString(block, element, modifiers) {
  return getClassArray(block, element, modifiers).join(' ');
}

function bemmit(block) {
  return getClassesAsString.bind(null, block);
}

module.exports = bemmit;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import {camelize} from './lib/String';
import {makeCancelable} from './lib/cancelablePromise';
import invariant from 'invariant';

const mapStyles = {
  container: {
    position: 'absolute',
    width: '100%',
    height: '100%'
  },
  map: {
    position: 'absolute',
    left: 0,
    right: 0,
    bottom: 0,
    top: 0
  }
};

const evtNames = [
  'ready',
  'click',
  'dragend',
  'recenter',
  'bounds_changed',
  'center_changed',
  'dblclick',
  'dragstart',
  'heading_change',
  'idle',
  'maptypeid_changed',
  'mousemove',
  'mouseout',
  'mouseover',
  'projection_changed',
  'resize',
  'rightclick',
  'tilesloaded',
  'tilt_changed',
  'zoom_changed'
];

export {wrapper as GoogleApiWrapper} from './GoogleApiComponent';
export {Marker} from './components/Marker';
export {InfoWindow} from './components/InfoWindow';
export {HeatMap} from './components/HeatMap';
export {Polygon} from './components/Polygon';

export class Map extends React.Component {
  constructor(props) {
    super(props);

    invariant(
      props.hasOwnProperty('google'),
      'You must include a `google` prop.'
    );

    this.listeners = {};
    this.state = {
      currentLocation: {
        lat: this.props.initialCenter.lat,
        lng: this.props.initialCenter.lng
      }
    };
  }

  componentDidMount() {
    if (this.props.centerAroundCurrentLocation) {
      if (navigator && navigator.geolocation) {
        this.geoPromise = makeCancelable(
          new Promise((resolve, reject) => {
            navigator.geolocation.getCurrentPosition(resolve, reject);
          })
        );

        this.geoPromise.promise
          .then(pos => {
            const coords = pos.coords;
            this.setState({
              currentLocation: {
                lat: coords.latitude,
                lng: coords.longitude
              }
            });
          })
          .catch(e => e);
      }
    }
    this.loadMap();
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevProps.google !== this.props.google) {
      this.loadMap();
    }
    if (this.props.visible !== prevProps.visible) {
      this.restyleMap();
    }
    if (this.props.zoom !== prevProps.zoom) {
      this.map.setZoom(this.props.zoom);
    }
    if (this.props.center !== prevProps.center) {
      this.setState({
        currentLocation: this.props.center
      });
    }
    if (prevState.currentLocation !== this.state.currentLocation) {
      this.recenterMap();
    }
  }

  componentWillUnmount() {
    const {google} = this.props;
    if (this.geoPromise) {
      this.geoPromise.cancel();
    }
    Object.keys(this.listeners).forEach(e => {
      google.maps.event.removeListener(this.listeners[e]);
    });
  }

  loadMap() {
    if (this.props && this.props.google) {
      const {google} = this.props;
      const maps = google.maps;

      const mapRef = this.refs.map;
      const node = ReactDOM.findDOMNode(mapRef);
      const curr = this.state.currentLocation;
      const center = new maps.LatLng(curr.lat, curr.lng);

      const mapTypeIds = this.props.google.maps.MapTypeId || {};
      const mapTypeFromProps = String(this.props.mapType).toUpperCase();

      const mapConfig = Object.assign(
        {},
        {
          mapTypeId: mapTypeIds[mapTypeFromProps],
          center: center,
          zoom: this.props.zoom,
          maxZoom: this.props.maxZoom,
          minZoom: this.props.maxZoom,
          clickableIcons: !!this.props.clickableIcons,
          disableDefaultUI: this.props.disableDefaultUI,
          zoomControl: this.props.zoomControl,
          mapTypeControl: this.props.mapTypeControl,
          scaleControl: this.props.scaleControl,
          streetViewControl: this.props.streetViewControl,
          panControl: this.props.panControl,
          rotateControl: this.props.rotateControl,
          scrollwheel: this.props.scrollwheel,
          draggable: this.props.draggable,
          keyboardShortcuts: this.props.keyboardShortcuts,
          disableDoubleClickZoom: this.props.disableDoubleClickZoom,
          noClear: this.props.noClear,
          styles: this.props.styles,
          gestureHandling: this.props.gestureHandling
        }
      );

      Object.keys(mapConfig).forEach(key => {
        // Allow to configure mapConfig with 'false'
        if (mapConfig[key] === null) {
          delete mapConfig[key];
        }
      });

      this.map = new maps.Map(node, mapConfig);

      evtNames.forEach(e => {
        this.listeners[e] = this.map.addListener(e, this.handleEvent(e));
      });
      maps.event.trigger(this.map, 'ready');
      this.forceUpdate();
    }
  }

  handleEvent(evtName) {
    let timeout;
    const handlerName = `on${camelize(evtName)}`;

    return e => {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      timeout = setTimeout(() => {
        if (this.props[handlerName]) {
          this.props[handlerName](this.props, this.map, e);
        }
      }, 0);
    };
  }

  recenterMap() {
    const map = this.map;

    const {google} = this.props;

    if (!google) return;
    const maps = google.maps;

    if (map) {
      let center = this.state.currentLocation;
      if (!(center instanceof google.maps.LatLng)) {
        center = new google.maps.LatLng(center.lat, center.lng);
      }
      // map.panTo(center)
      map.setCenter(center);
      maps.event.trigger(map, 'recenter');
    }
  }

  restyleMap() {
    if (this.map) {
      const {google} = this.props;
      google.maps.event.trigger(this.map, 'resize');
    }
  }

  renderChildren() {
    const {children} = this.props;

    if (!children) return;

    return React.Children.map(children, c => {
      if (!c) return;
      return React.cloneElement(c, {
        map: this.map,
        google: this.props.google,
        mapCenter: this.state.currentLocation
      });
    });
  }

  render() {
    const style = Object.assign({}, mapStyles.map, this.props.style, {
      display: this.props.visible ? 'inherit' : 'none'
    });

    const containerStyles = Object.assign(
      {},
      mapStyles.container,
      this.props.containerStyle
    );

    return (

          Loading map...

        {this.renderChildren()}

    );
  }
}

Map.propTypes = {
  google: PropTypes.object,
  zoom: PropTypes.number,
  centerAroundCurrentLocation: PropTypes.bool,
  center: PropTypes.object,
  initialCenter: PropTypes.object,
  className: PropTypes.string,
  style: PropTypes.object,
  containerStyle: PropTypes.object,
  visible: PropTypes.bool,
  mapType: PropTypes.string,
  maxZoom: PropTypes.number,
  minZoom: PropTypes.number,
  clickableIcons: PropTypes.bool,
  disableDefaultUI: PropTypes.bool,
  zoomControl: PropTypes.bool,
  mapTypeControl: PropTypes.bool,
  scaleControl: PropTypes.bool,
  streetViewControl: PropTypes.bool,
  panControl: PropTypes.bool,
  rotateControl: PropTypes.bool,
  scrollwheel: PropTypes.bool,
  draggable: PropTypes.bool,
  keyboardShortcuts: PropTypes.bool,
  disableDoubleClickZoom: PropTypes.bool,
  noClear: PropTypes.bool,
  styles: PropTypes.array,
  gestureHandling: PropTypes.string
};

evtNames.forEach(e => (Map.propTypes[camelize(e)] = PropTypes.func));

Map.defaultProps = {
  zoom: 14,
  initialCenter: {
    lat: 37.774929,
    lng: -122.419416
  },
  center: {},
  centerAroundCurrentLocation: false,
  style: {},
  containerStyle: {},
  visible: true
};

export default Map;
<commit_msg>Revert change from PR #126 to fix (again) #110<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import {camelize} from './lib/String';
import {makeCancelable} from './lib/cancelablePromise';
import invariant from 'invariant';

const mapStyles = {
  container: {
    position: 'absolute',
    width: '100%',
    height: '100%'
  },
  map: {
    position: 'absolute',
    left: 0,
    right: 0,
    bottom: 0,
    top: 0
  }
};

const evtNames = [
  'ready',
  'click',
  'dragend',
  'recenter',
  'bounds_changed',
  'center_changed',
  'dblclick',
  'dragstart',
  'heading_change',
  'idle',
  'maptypeid_changed',
  'mousemove',
  'mouseout',
  'mouseover',
  'projection_changed',
  'resize',
  'rightclick',
  'tilesloaded',
  'tilt_changed',
  'zoom_changed'
];

export {wrapper as GoogleApiWrapper} from './GoogleApiComponent';
export {Marker} from './components/Marker';
export {InfoWindow} from './components/InfoWindow';
export {HeatMap} from './components/HeatMap';
export {Polygon} from './components/Polygon';

export class Map extends React.Component {
  constructor(props) {
    super(props);

    invariant(
      props.hasOwnProperty('google'),
      'You must include a `google` prop.'
    );

    this.listeners = {};
    this.state = {
      currentLocation: {
        lat: this.props.initialCenter.lat,
        lng: this.props.initialCenter.lng
      }
    };
  }

  componentDidMount() {
    if (this.props.centerAroundCurrentLocation) {
      if (navigator && navigator.geolocation) {
        this.geoPromise = makeCancelable(
          new Promise((resolve, reject) => {
            navigator.geolocation.getCurrentPosition(resolve, reject);
          })
        );

        this.geoPromise.promise
          .then(pos => {
            const coords = pos.coords;
            this.setState({
              currentLocation: {
                lat: coords.latitude,
                lng: coords.longitude
              }
            });
          })
          .catch(e => e);
      }
    }
    this.loadMap();
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevProps.google !== this.props.google) {
      this.loadMap();
    }
    if (this.props.visible !== prevProps.visible) {
      this.restyleMap();
    }
    if (this.props.zoom !== prevProps.zoom) {
      this.map.setZoom(this.props.zoom);
    }
    if (this.props.center !== prevProps.center) {
      this.setState({
        currentLocation: this.props.center
      });
    }
    if (prevState.currentLocation !== this.state.currentLocation) {
      this.recenterMap();
    }
  }

  componentWillUnmount() {
    const {google} = this.props;
    if (this.geoPromise) {
      this.geoPromise.cancel();
    }
    Object.keys(this.listeners).forEach(e => {
      google.maps.event.removeListener(this.listeners[e]);
    });
  }

  loadMap() {
    if (this.props && this.props.google) {
      const {google} = this.props;
      const maps = google.maps;

      const mapRef = this.refs.map;
      const node = ReactDOM.findDOMNode(mapRef);
      const curr = this.state.currentLocation;
      const center = new maps.LatLng(curr.lat, curr.lng);

      const mapTypeIds = this.props.google.maps.MapTypeId || {};
      const mapTypeFromProps = String(this.props.mapType).toUpperCase();

      const mapConfig = Object.assign(
        {},
        {
          mapTypeId: mapTypeIds[mapTypeFromProps],
          center: center,
          zoom: this.props.zoom,
          maxZoom: this.props.maxZoom,
          minZoom: this.props.minZoom,
          clickableIcons: !!this.props.clickableIcons,
          disableDefaultUI: this.props.disableDefaultUI,
          zoomControl: this.props.zoomControl,
          mapTypeControl: this.props.mapTypeControl,
          scaleControl: this.props.scaleControl,
          streetViewControl: this.props.streetViewControl,
          panControl: this.props.panControl,
          rotateControl: this.props.rotateControl,
          scrollwheel: this.props.scrollwheel,
          draggable: this.props.draggable,
          keyboardShortcuts: this.props.keyboardShortcuts,
          disableDoubleClickZoom: this.props.disableDoubleClickZoom,
          noClear: this.props.noClear,
          styles: this.props.styles,
          gestureHandling: this.props.gestureHandling
        }
      );

      Object.keys(mapConfig).forEach(key => {
        // Allow to configure mapConfig with 'false'
        if (mapConfig[key] === null) {
          delete mapConfig[key];
        }
      });

      this.map = new maps.Map(node, mapConfig);

      evtNames.forEach(e => {
        this.listeners[e] = this.map.addListener(e, this.handleEvent(e));
      });
      maps.event.trigger(this.map, 'ready');
      this.forceUpdate();
    }
  }

  handleEvent(evtName) {
    let timeout;
    const handlerName = `on${camelize(evtName)}`;

    return e => {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      timeout = setTimeout(() => {
        if (this.props[handlerName]) {
          this.props[handlerName](this.props, this.map, e);
        }
      }, 0);
    };
  }

  recenterMap() {
    const map = this.map;

    const {google} = this.props;

    if (!google) return;
    const maps = google.maps;

    if (map) {
      let center = this.state.currentLocation;
      if (!(center instanceof google.maps.LatLng)) {
        center = new google.maps.LatLng(center.lat, center.lng);
      }
      // map.panTo(center)
      map.setCenter(center);
      maps.event.trigger(map, 'recenter');
    }
  }

  restyleMap() {
    if (this.map) {
      const {google} = this.props;
      google.maps.event.trigger(this.map, 'resize');
    }
  }

  renderChildren() {
    const {children} = this.props;

    if (!children) return;

    return React.Children.map(children, c => {
      if (!c) return;
      return React.cloneElement(c, {
        map: this.map,
        google: this.props.google,
        mapCenter: this.state.currentLocation
      });
    });
  }

  render() {
    const style = Object.assign({}, mapStyles.map, this.props.style, {
      display: this.props.visible ? 'inherit' : 'none'
    });

    const containerStyles = Object.assign(
      {},
      mapStyles.container,
      this.props.containerStyle
    );

    return (

          Loading map...

        {this.renderChildren()}

    );
  }
}

Map.propTypes = {
  google: PropTypes.object,
  zoom: PropTypes.number,
  centerAroundCurrentLocation: PropTypes.bool,
  center: PropTypes.object,
  initialCenter: PropTypes.object,
  className: PropTypes.string,
  style: PropTypes.object,
  containerStyle: PropTypes.object,
  visible: PropTypes.bool,
  mapType: PropTypes.string,
  maxZoom: PropTypes.number,
  minZoom: PropTypes.number,
  clickableIcons: PropTypes.bool,
  disableDefaultUI: PropTypes.bool,
  zoomControl: PropTypes.bool,
  mapTypeControl: PropTypes.bool,
  scaleControl: PropTypes.bool,
  streetViewControl: PropTypes.bool,
  panControl: PropTypes.bool,
  rotateControl: PropTypes.bool,
  scrollwheel: PropTypes.bool,
  draggable: PropTypes.bool,
  keyboardShortcuts: PropTypes.bool,
  disableDoubleClickZoom: PropTypes.bool,
  noClear: PropTypes.bool,
  styles: PropTypes.array,
  gestureHandling: PropTypes.string
};

evtNames.forEach(e => (Map.propTypes[camelize(e)] = PropTypes.func));

Map.defaultProps = {
  zoom: 14,
  initialCenter: {
    lat: 37.774929,
    lng: -122.419416
  },
  center: {},
  centerAroundCurrentLocation: false,
  style: {},
  containerStyle: {},
  visible: true
};

export default Map;
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'

export default class PieChart {
  static propTypes = {
    data: PropTypes.arrayOf(PropTypes.shape({
      value: PropTypes.number,
      color: PropTypes.string,
    })),
    palette: PropTypes.arrayOf(PropTypes.string),
    sectorStrokeWidth: PropTypes.number,
    expandOnHover: PropTypes.bool,
    expandedSector: PropTypes.number,
    onSectorHover: PropTypes.func,
    expandPx: PropTypes.number,
    viewBoxWidth: PropTypes.number,
  }

  static defaultProps = {
    data: [],
    palette: [
      '#2ecc71',
      '#3498db',
      '#9b59b6',
      '#f1c40f',
      '#e67e22',
      '#e74c3c',
      '#1abc9c',
    ],
    sectorStrokeWidth: 3,
    expandOnHover: true,
    expandedSector: null,
    expandPx: 10,
    viewBoxWidth: 300,
  }

  handleMouseEnterOnSector(i) {
    const { onMouseEnterOnSector } = this.props

    if (onMouseEnterOnSector) {
      onMouseEnterOnSector(i)
    }
  }

  handleMouseLeaveFromSector() {
    const { onMouseLeaveFromSector } = this.props

    if (onMouseLeaveFromSector) {
      onMouseLeaveFromSector(null)
    }
  }

  getSectors() {
    const { data, palette, sectorStrokeWidth, expandOnHover, expandedSector, expandPx, viewBoxWidth } = this.props
    const total = Math.ceil(data.reduce((n, d) => d.value + n, 0))
    const center = viewBoxWidth / 2
    let startAngle = 0
    let endAngle = 0

    return (
      data.map((d, i) => {
        const expandVal = expandOnHover && expandedSector === i ? expandPx : 0
        const angle = 360 * d.value / total
        const largeArc = (d.value / total) <= 0.5 ? 0 : 1

        startAngle = endAngle
        endAngle = startAngle + angle

        const x1 = Math.round(center + (center + expandVal) * Math.cos(Math.PI * startAngle / 180))
        const y1 = Math.round(center + (center + expandVal) * Math.sin(Math.PI * startAngle / 180))

        const x2 = Math.round(center + (center + expandVal) * Math.cos(Math.PI * endAngle / 180))
        const y2 = Math.round(center + (center + expandVal) * Math.sin(Math.PI * endAngle / 180))

        const dPath =
          'M' + center + ',' + center + ' ' +
          'L' + x1 + ',' + y1 + ' ' +
          'A' + (center + expandVal) + ',' + (center + expandVal) + ' 0 ' + largeArc + ',1 ' + x2 + ',' + y2 + ' ' +
          'z'

        return (
          <path
            key={ 'sector' + i }
            d={ dPath }
            fill={ d.color || palette[i % palette.length] }
            stroke="#fff"
            strokeWidth={ sectorStrokeWidth }
            onMouseEnter={ () => this.handleMouseEnterOnSector(i) }
            onMouseLeave={ () => this.handleMouseLeaveFromSector() } />
        )
      })
    )
  }

  render() {
    const { expandPx, viewBoxWidth, props } = this.props
    return (
      <svg viewBox={ `0 0 ${viewBoxWidth + expandPx * 2} ${viewBoxWidth + expandPx * 2}` } { ...props }>
        <g transform={`translate(${expandPx}, ${expandPx})`}>
          { this.getSectors() }
        </g>
      </svg>
  )}
}
<commit_msg>fix: extends React.Component<commit_after>import React, { PropTypes } from 'react'

export default class PieChart extends React.Component {
  static propTypes = {
    data: PropTypes.arrayOf(PropTypes.shape({
      value: PropTypes.number,
      color: PropTypes.string,
    })),
    palette: PropTypes.arrayOf(PropTypes.string),
    sectorStrokeWidth: PropTypes.number,
    expandOnHover: PropTypes.bool,
    expandedSector: PropTypes.number,
    onSectorHover: PropTypes.func,
    expandPx: PropTypes.number,
    viewBoxWidth: PropTypes.number,
  }

  static defaultProps = {
    data: [],
    palette: [
      '#2ecc71',
      '#3498db',
      '#9b59b6',
      '#f1c40f',
      '#e67e22',
      '#e74c3c',
      '#1abc9c',
    ],
    sectorStrokeWidth: 3,
    expandOnHover: true,
    expandedSector: null,
    expandPx: 10,
    viewBoxWidth: 300,
  }

  handleMouseEnterOnSector(i) {
    const { onMouseEnterOnSector } = this.props

    if (onMouseEnterOnSector) {
      onMouseEnterOnSector(i)
    }
  }

  handleMouseLeaveFromSector() {
    const { onMouseLeaveFromSector } = this.props

    if (onMouseLeaveFromSector) {
      onMouseLeaveFromSector(null)
    }
  }

  getSectors() {
    const { data, palette, sectorStrokeWidth, expandOnHover, expandedSector, expandPx, viewBoxWidth } = this.props
    const total = Math.ceil(data.reduce((n, d) => d.value + n, 0))
    const center = viewBoxWidth / 2
    let startAngle = 0
    let endAngle = 0

    return (
      data.map((d, i) => {
        const expandVal = expandOnHover && expandedSector === i ? expandPx : 0
        const angle = 360 * d.value / total
        const largeArc = (d.value / total) <= 0.5 ? 0 : 1

        startAngle = endAngle
        endAngle = startAngle + angle

        const x1 = Math.round(center + (center + expandVal) * Math.cos(Math.PI * startAngle / 180))
        const y1 = Math.round(center + (center + expandVal) * Math.sin(Math.PI * startAngle / 180))

        const x2 = Math.round(center + (center + expandVal) * Math.cos(Math.PI * endAngle / 180))
        const y2 = Math.round(center + (center + expandVal) * Math.sin(Math.PI * endAngle / 180))

        const dPath =
          'M' + center + ',' + center + ' ' +
          'L' + x1 + ',' + y1 + ' ' +
          'A' + (center + expandVal) + ',' + (center + expandVal) + ' 0 ' + largeArc + ',1 ' + x2 + ',' + y2 + ' ' +
          'z'

        return (
          <path
            key={ 'sector' + i }
            d={ dPath }
            fill={ d.color || palette[i % palette.length] }
            stroke="#fff"
            strokeWidth={ sectorStrokeWidth }
            onMouseEnter={ () => this.handleMouseEnterOnSector(i) }
            onMouseLeave={ () => this.handleMouseLeaveFromSector() } />
        )
      })
    )
  }

  render() {
    const { expandPx, viewBoxWidth, props } = this.props
    return (
      <svg viewBox={ `0 0 ${viewBoxWidth + expandPx * 2} ${viewBoxWidth + expandPx * 2}` } { ...props }>
        <g transform={`translate(${expandPx}, ${expandPx})`}>
          { this.getSectors() }
        </g>
      </svg>
  )}
}
<|endoftext|>


<commit_before>import {
  error,
  parseToken
} from './util'

const identity = {
  defaults: {
    url: '/api',
    loginUrl: '/login',
    logoutUrl: '/logout',
    refreshUrl: '/refresh',
    accessToken: 'token',
    refreshToken: 'refresh',
    unauthorizedRedirect: null,
    redirect: null,
    scope: null
  },
  install(Vue, opts) {
    if (identity.installed) {
      return
    }
    // setup
    let vm = new Vue({
      data: {
        refreshToken: window.localStorage['vue-identity:refreshToken'],
        accessToken: null,
        expires: null,
        user: null,
        notBefore: null,
        issuedAt: null,
        loading: false,
        checking: false
      },
      computed: {
        expiresIn() {
          return this.expires ? (this.expires * 1000) - Date.now() : false
        }
      }
    })

    let self = Vue.prototype.$identity = vm
    let options = Object.assign(identity.defaults, opts)

    let http = Vue.http
    let router = opts.router

    if (!http) {
      console.error('VueIdentity requires vue-resource. Make sure you Vue.use(VueResource) before Vue.use(VueIdentity)')
    }
    Vue.http.interceptors.push(function(request, next) {
      if( self.tokenValid() ) {
        request.headers.set('Authorization', 'Bearer ' + self.accessToken)
      next()
      } else if ( self.refreshToken ) {
        self.refresh()
          .then(() => next())
          .catch(res => {
            if(res.status % 400 < 100) // in the 400-499 range
              return self
                .loginWithCredentials({ preventRedirect: true })
                .then(res => {
                  self.receivethMightyToken(res.data)
                  next()
                })
            else throw res.statusText
          })
      }
    })
    if (!router) {
      console.info('To use with vue-router, pass it to me Vue.use(VueIdentity, {router})')
    } else {
      router.beforeEach((to, from, next) => {
        let $identity = options.router.app.$identity
        if (to.meta.identity && $identity.user === null) {
          $identity.authenticate().then(function() {
            next()
          }, function() {
            if (options.unauthorizedRedirect)
              next({
                path: options.unauthorizedRedirect
              })
          })
        } else {
          next()
        }
      })
    }

    // methods
    self.uri = (endpoint) => {
      return options.url + options[endpoint + 'Url']
    }
    self.authenticate = () => {
      // I have a valid access token = good
      if (self.isLoggedIn()) return Promise.resolve()

      // Attempt to get an access token if I have a refresh token
      // If refresh comes back as invalid, logout and call again to attempt loginWithCredentials
      if (self.refreshToken) return self.refresh().catch(() => self.authenticate())

      // Attempt to get access token with credentials (Cookie based auth)
      return self.loginWithCredentials()
    }
    // Login with fresh token
    self.refresh = () => {
      return self.attachRequestQuarterback(http.post(self.uri('refresh'), {
        token: self.refreshToken
      }))
    }
    // Login with data (username, password)
    self.login = (data) => {
      return self.attachRequestQuarterback(http.post(self.uri('login'), data, {
        credentials: true,
        params: params
      }))
    }
    // Cookie based login
    self.loginWithCredentials = (options) => {
      let params = {}
      if (options.scope) params.scope = options.scope
      if (options.redirect) params.redirect = options.redirect
      return self.attachRequestQuarterback(http.get(self.uri('login'), {
        credentials: true,
        params: params
      }), options)
    }
    self.logout = () => {
      delete localStorage['vue-identity:refreshToken']
      self.refreshToken = null
      self.accessToken = null
      self.user = null
      self.expires = null
      self.issuedAt = null
      self.notBefore = null
      return Promise.resolve()
    }
    self.attachRequestQuarterback = (promise, { preventRedirect }) => {
      self.loading = true
      return promise.then((r) => {
        self.receivethMightyToken(r.data)
        return Promise.resolve()
      }).catch((e) => {
        self.logout()
        if (e.headers.get('X-Authentication-Location') && !preventRedirect)
          window.location.href = e.headers.get('X-Authentication-Location')
        return error(e)
      }).finally(() => {
        self.loading = false
      })
    }
    self.receivethMightyToken = (tokenIsMightier) => {
      let accessToken = tokenIsMightier[options.accessToken]
      let refreshToken = tokenIsMightier[options.refreshToken]
      if (accessToken == undefined) return error('No token received')
      let user = parseToken(accessToken)
      self.accessToken = accessToken
      self.refreshToken = localStorage['vue-identity:refreshToken'] = refreshToken
      self.user = user
      self.expires = user.exp
      self.issuedAt = user.iat
      self.notBefore = user.nbf
    }
    self.attemptRefresh = () => {
      let expiresIn = (self.expires * 1000) - Date.now()
      console.info("attemptRefresh", expiresIn)

      if (self.tokenValid() && expiresIn <= 300000) {
        console.info("attemptRefresh tokenValid expiresIn <= 300000", expiresIn)
        return self.refresh()
      }
    }
    self.isLoggedIn = () => {
      return self.tokenValid()
    }
    self.tokenValid = () => {
      return self.accessToken && ((self.expires * 1000) - Date.now()) > 0
    }
  }
}
export default identity
<commit_msg>Peer Programming<commit_after>import {
  error,
  parseToken
} from './util'

const identity = {
  defaults: {
    url: '/api',
    loginUrl: '/login',
    logoutUrl: '/logout',
    refreshUrl: '/refresh',
    accessToken: 'token',
    refreshToken: 'refresh',
    unauthorizedRedirect: null,
    redirect: null,
    scope: null
  },
  install(Vue, opts) {
    if (identity.installed) {
      return
    }
    // setup
    let vm = new Vue({
      data: {
        refreshToken: window.localStorage['vue-identity:refreshToken'],
        accessToken: null,
        expires: null,
        user: null,
        notBefore: null,
        issuedAt: null,
        loading: false,
        checking: false
      },
      computed: {
        expiresIn() {
          return this.expires ? (this.expires * 1000) - Date.now() : false
        }
      }
    })

    let self = Vue.prototype.$identity = vm
    let options = Object.assign(identity.defaults, opts)

    let http = Vue.http
    let router = opts.router

    if (!http) {
      console.error('VueIdentity requires vue-resource. Make sure you Vue.use(VueResource) before Vue.use(VueIdentity)')
    }
    Vue.http.interceptors.push(function(request, next) {
      self.authenticate({ preventRedirect: true }).then(() => {
        request.headers.set('Authorization', 'Bearer ' + self.accessToken)
        next()
      })
    })
    if (!router) {
      console.info('To use with vue-router, pass it to me Vue.use(VueIdentity, {router})')
    } else {
      router.beforeEach((to, from, next) => {
        if (to.meta.identity && self.isLoggedIn() === false) {
          self.authenticate().then(function() {
            next()
          }, function() {
            if (options.unauthorizedRedirect)
              next({
                path: options.unauthorizedRedirect
              })
          })
        } else {
          next()
        }
      })
    }

    // methods
    self.uri = (endpoint) => {
      return options.url + options[endpoint + 'Url']
    }
    self.authenticate = (options) => {
      // I have a valid access token = good
      if (self.isLoggedIn()) return Promise.resolve()

      // Attempt to get an access token if I have a refresh token
      // If refresh comes back as invalid, logout and call again to attempt loginWithCredentials
      if (self.refreshToken) return self.refresh().catch(() => self.authenticate())

      // Attempt to get access token with credentials (Cookie based auth)
      return self.loginWithCredentials(options)
    }
    // Login with fresh token
    self.refresh = () => {
      return self.attachRequestQuarterback(http.post(self.uri('refresh'), {
        token: self.refreshToken
      }))
    }
    // Login with data (username, password)
    self.login = (data) => {
      return self.attachRequestQuarterback(http.post(self.uri('login'), data, {
        credentials: true,
        params: params
      }))
    }
    // Cookie based login
    self.loginWithCredentials = (options) => {
      let params = {}
      if (options.scope) params.scope = options.scope
      if (options.redirect) params.redirect = options.redirect
      return self.attachRequestQuarterback(http.get(self.uri('login'), {
        credentials: true,
        params: params
      }), options)
    }
    self.logout = () => {
      delete localStorage['vue-identity:refreshToken']
      self.refreshToken = null
      self.accessToken = null
      self.user = null
      self.expires = null
      self.issuedAt = null
      self.notBefore = null
      return Promise.resolve()
    }
    self.attachRequestQuarterback = (promise, { preventRedirect }) => {
      self.loading = true
      return promise.then((r) => {
        self.receivethMightyToken(r.data)
        return Promise.resolve()
      }).catch((e) => {
        self.logout()
        if (e.headers.get('X-Authentication-Location') && !preventRedirect)
          window.location.href = e.headers.get('X-Authentication-Location')
        return error(e)
      }).finally(() => {
        self.loading = false
      })
    }
    self.receivethMightyToken = (tokenIsMightier) => {
      let accessToken = tokenIsMightier[options.accessToken]
      let refreshToken = tokenIsMightier[options.refreshToken]
      if (accessToken == undefined) return error('No token received')
      let user = parseToken(accessToken)
      self.accessToken = accessToken
      self.refreshToken = localStorage['vue-identity:refreshToken'] = refreshToken
      self.user = user
      self.expires = user.exp
      self.issuedAt = user.iat
      self.notBefore = user.nbf
    }
    self.attemptRefresh = () => {
      let expiresIn = (self.expires * 1000) - Date.now()
      console.info("attemptRefresh", expiresIn)

      if (self.tokenValid() && expiresIn <= 300000) {
        console.info("attemptRefresh tokenValid expiresIn <= 300000", expiresIn)
        return self.refresh()
      }
    }
    self.isLoggedIn = () => {
      return self.tokenValid()
    }
    self.tokenValid = () => {
      return self.accessToken && ((self.expires * 1000) - Date.now()) > 0
    }
  }
}
export default identity
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react'
import ix from 'imgix.js'

const roundToNearest = (size, precision) => precision * Math.ceil(size / precision)

const defaultMap = {
  width: 'defaultWidth',
  height: 'defaultHeight'
}

const findSizeForDimension = (dim, props = {}, state = {}) => {
  if (props[dim]) {
    return props[dim]
  } else if (props.fluid && state[dim]) {
    return roundToNearest(state[dim], props.precision)
  } else if (props[defaultMap[dim]]) {
    return props[defaultMap[dim]]
  } else {
    return 1
  }
}

export default class ReactImgix extends Component {
  static propTypes = {
    src: PropTypes.string.isRequired,
    className: PropTypes.string,
    bg: PropTypes.bool,
    component: PropTypes.string,
    fit: PropTypes.string,
    auto: PropTypes.array,
    faces: PropTypes.bool,
    aggresiveLoad: PropTypes.bool,
    fluid: PropTypes.bool,
    children: PropTypes.any
  }
  static defaultProps = {
    precision: 100,
    bg: false,
    fluid: true,
    aggresiveLoad: false,
    faces: true,
    fit: 'crop',
    auto: ['format']
  }
  state = {
    width: null,
    height: null,
    mounted: false
  }
  componentDidMount = () => {
    const node = React.findDOMNode(this)
    this.setState({
      width: node.scrollWidth,
      height: node.scrollHeight,
      mounted: true
    })
  }
  _findSizeForDimension = dim => findSizeForDimension(dim, this.props, this.state)

  render () {
    let src = new ix.URL(this.props.src)
    let component = this.props.component

    let width = this._findSizeForDimension('width')
    let height = this._findSizeForDimension('height')
    src.setParams({
      w: width,
      h: height,
      fit: this.props.fit,
      auto: this.props.auto
    })

    if (this.props.faces) {
      src.setCrop('faces')
    }

    src = src.getUrl()

    if (!this.state.mounted && !this.props.aggresiveLoad) {
      src = ''
    }

    let childProps = {...this.props}

    if (this.props.bg) {
      if (!this.props.component) {
        component = 'div'
      }
      childProps.style = {
        ...childProps.style,
        backgroundImage: `url(${src})`
      }
      delete childProps.src
    } else {
      if (!this.props.component) {
        component = 'img'
      }
      childProps.src = src
    }
    return React.createElement(component,
      childProps,
      this.props.children)
  }
}
<commit_msg>Set backgroundSize: cover on component when it's in background mode<commit_after>import React, {Component, PropTypes} from 'react'
import ix from 'imgix.js'

const roundToNearest = (size, precision) => precision * Math.ceil(size / precision)

const defaultMap = {
  width: 'defaultWidth',
  height: 'defaultHeight'
}

const findSizeForDimension = (dim, props = {}, state = {}) => {
  if (props[dim]) {
    return props[dim]
  } else if (props.fluid && state[dim]) {
    return roundToNearest(state[dim], props.precision)
  } else if (props[defaultMap[dim]]) {
    return props[defaultMap[dim]]
  } else {
    return 1
  }
}

export default class ReactImgix extends Component {
  static propTypes = {
    src: PropTypes.string.isRequired,
    className: PropTypes.string,
    bg: PropTypes.bool,
    component: PropTypes.string,
    fit: PropTypes.string,
    auto: PropTypes.array,
    faces: PropTypes.bool,
    aggresiveLoad: PropTypes.bool,
    fluid: PropTypes.bool,
    children: PropTypes.any
  }
  static defaultProps = {
    precision: 100,
    bg: false,
    fluid: true,
    aggresiveLoad: false,
    faces: true,
    fit: 'crop',
    auto: ['format']
  }
  state = {
    width: null,
    height: null,
    mounted: false
  }
  componentDidMount = () => {
    const node = React.findDOMNode(this)
    this.setState({
      width: node.scrollWidth,
      height: node.scrollHeight,
      mounted: true
    })
  }
  _findSizeForDimension = dim => findSizeForDimension(dim, this.props, this.state)

  render () {
    let src = new ix.URL(this.props.src)
    let component = this.props.component

    let width = this._findSizeForDimension('width')
    let height = this._findSizeForDimension('height')
    src.setParams({
      w: width,
      h: height,
      fit: this.props.fit,
      auto: this.props.auto
    })

    if (this.props.faces) {
      src.setCrop('faces')
    }

    src = src.getUrl()

    if (!this.state.mounted && !this.props.aggresiveLoad) {
      src = ''
    }

    let childProps = {...this.props}

    if (this.props.bg) {
      if (!this.props.component) {
        component = 'div'
      }
      childProps.style = {
        ...childProps.style,
        backgroundImage: `url(${src})`,
        backgroundSize: 'cover'
      }
      delete childProps.src
    } else {
      if (!this.props.component) {
        component = 'img'
      }
      childProps.src = src
    }
    return React.createElement(component,
      childProps,
      this.props.children)
  }
}
<|endoftext|>


<commit_before>import React, { Component, cloneElement } from 'react';
import PropTypes from 'prop-types';
import cloneDeep from 'lodash.clonedeep';
import cx from 'classnames';
import isUndefined from 'lodash.isundefined';
import set from 'lodash.set';
import './style/dat.scss';

export default class DatGui extends Component {
  static propTypes = {
    data: PropTypes.object.isRequired,
    children: PropTypes.node.isRequired,
    onUpdate: PropTypes.func.isRequired,
    liveUpdate: PropTypes.bool,
    labelWidth: PropTypes.string.isRequired,
    className: PropTypes.string,
    style: PropTypes.object
  };

  static defaultProps = {
    liveUpdate: true,
    className: null,
    style: null
  };

  handleUpdateValue = (path, value) => {
    const { data, onUpdate } = this.props;
    const dataUpdated = set(cloneDeep(data), path, value);

    onUpdate(dataUpdated);
  };

  renderChildren() {
    const { children, data } = this.props;

    return React.Children.toArray(children).map((child, i) => {
      const liveUpdate = isUndefined(child.props.liveUpdate)
        ? this.props.liveUpdate
        : child.props.liveUpdate;
      const labelWidth = isUndefined(child.props.labelWidth)
        ? this.props.labelWidth
        : child.props.labelWidth;

      return cloneElement(child, {
        key: i,
        data,
        liveUpdate,
        labelWidth,
        _onUpdateValue: this.handleUpdateValue
      });
    });
  }

  render() {
    const { style = {} } = this.props;
    const className = cx('react-dat-gui', this.props.className);

    return (

{this.renderChildren()}

    );
  }
}

export { default as DatString } from './components/DatString';
export { default as DatNumber } from './components/DatNumber';
export { default as DatBoolean } from './components/DatBoolean';
export { default as DatButton } from './components/DatButton';
export { default as DatFolder } from './components/DatFolder';
export { default as DatSelect } from './components/DatSelect';
export { default as DatColor } from './components/DatColor';
export { default as DatPresets } from './components/DatPresets';
<commit_msg>Small cleanup<commit_after>import React, { Component, cloneElement } from 'react';
import PropTypes from 'prop-types';
import cloneDeep from 'lodash.clonedeep';
import cx from 'classnames';
import isUndefined from 'lodash.isundefined';
import set from 'lodash.set';
import './style/dat.scss';

export default class DatGui extends Component {
  static propTypes = {
    data: PropTypes.object.isRequired,
    children: PropTypes.node.isRequired,
    onUpdate: PropTypes.func.isRequired,
    liveUpdate: PropTypes.bool,
    labelWidth: PropTypes.string.isRequired,
    className: PropTypes.string,
    style: PropTypes.object
  };

  static defaultProps = {
    liveUpdate: true,
    className: null,
    style: null
  };

  handleUpdateValue = (path, value) => {
    const { data, onUpdate } = this.props;
    const dataUpdated = set(cloneDeep(data), path, value);

    onUpdate(dataUpdated);
  };

  renderChildren() {
    const { children, data } = this.props;

    return React.Children.toArray(children).map((child, i) => {
      const liveUpdate = isUndefined(child.props.liveUpdate)
        ? this.props.liveUpdate
        : child.props.liveUpdate;
      const labelWidth = isUndefined(child.props.labelWidth)
        ? this.props.labelWidth
        : child.props.labelWidth;

      return cloneElement(child, {
        key: i,
        data,
        liveUpdate,
        labelWidth,
        _onUpdateValue: this.handleUpdateValue
      });
    });
  }

  render() {
    const { style, className } = this.props;
    const classNames = cx('react-dat-gui', className);

    return (

{this.renderChildren()}

    );
  }
}

export { default as DatString } from './components/DatString';
export { default as DatNumber } from './components/DatNumber';
export { default as DatBoolean } from './components/DatBoolean';
export { default as DatButton } from './components/DatButton';
export { default as DatFolder } from './components/DatFolder';
export { default as DatSelect } from './components/DatSelect';
export { default as DatColor } from './components/DatColor';
export { default as DatPresets } from './components/DatPresets';
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import './index.css';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
<commit_msg>Add hot module replacement<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import './index.css';

const rootEl = document.getElementById('root')

// regular imports
ReactDOM.render(<App /> , rootEl)

// Hot Module Replacement API
if (module.hot) {
  module.hot.accept('./App', () => {
    ReactDOM.render(<App />, rootEl)
  })
}

registerServiceWorker();
<|endoftext|>