// close dialog if !persistent, clicked outside and we're the topmost dialog.

// Since this should only be called in a capture event (bottom up), we shouldn't need to stop propagation

return getZIndex(this.$refs.content) >= this.getMaxZIndex()

!this.fullscreen && !this.hideOverlay && this.genOverlay()

keep keep keep keep keep replace keep keep keep keep keep

const overlayClass = this.hideOverlay ? 'v-overlay--transparent' : ''

!this.fullscreen && this.hasOverlay && this.genOverlay(overlayClass)

import '../stylus/components/_overlay.styl'

// Utils
import { keyCodes } from '../util/helpers'

/* @vue/component */
export default {
  name: 'overlayable',

  props: {
    hideOverlay: Boolean
  },

  data () {
    return {
      overlay: null,
      overlayOffset: 0,
      overlayTimeout: null,
      overlayTransitionDuration: 500 + 150 // transition + delay
    }
  },

  beforeDestroy () {
    this.removeOverlay()
  },

  methods: {
    genOverlay () {
      // If fn is called and timeout is active
      // or overlay already exists
      // cancel removal of overlay and re-add active
      if ((!this.isActive || this.hideOverlay) ||
        (this.isActive && this.overlayTimeout) ||
        this.overlay
      ) {
        clearTimeout(this.overlayTimeout)

        return this.overlay &&
          this.overlay.classList.add('v-overlay--active')
      }

      this.overlay = document.createElement('div')
      this.overlay.className = 'v-overlay'

      if (this.absolute) this.overlay.className += ' v-overlay--absolute'

      this.hideScroll()

      const parent = this.absolute
        ? this.$el.parentNode
        : document.querySelector('[data-app]')

      parent && parent.insertBefore(this.overlay, parent.firstChild)

      // eslint-disable-next-line no-unused-expressions
      this.overlay.clientHeight // Force repaint
      requestAnimationFrame(() => {
        this.overlay.className += ' v-overlay--active'

        if (this.activeZIndex !== undefined) {
          this.overlay.style.zIndex = this.activeZIndex - 1
        }
      })

      return true
    },
    removeOverlay () {
      if (!this.overlay) {
        return this.showScroll()
      }

      this.overlay.classList.remove('v-overlay--active')

      this.overlayTimeout = setTimeout(() => {
        // IE11 Fix
        try {
          if (this.overlay && this.overlay.parentNode) {
            this.overlay.parentNode.removeChild(this.overlay)
          }
          this.overlay = null
          this.showScroll()
        } catch (e) { console.log(e) }

        clearTimeout(this.overlayTimeout)
        this.overlayTimeout = null
      }, this.overlayTransitionDuration)
    },
    /**
     * @param {Event} e
     * @returns void
     */
    scrollListener (e) {
      if (e.type === 'keydown') {
        if (['INPUT', 'TEXTAREA', 'SELECT'].includes(e.target.tagName)) return

        const up = [keyCodes.up, keyCodes.pageup]
        const down = [keyCodes.down, keyCodes.pagedown]

        if (up.includes(e.keyCode)) {
          e.deltaY = -1
        } else if (down.includes(e.keyCode)) {
          e.deltaY = 1
        } else {
          return
        }
      }

      if (e.target === this.overlay ||
        (e.type !== 'keydown' && e.target === document.body) ||
        this.checkPath(e)) e.preventDefault()
    },
    hasScrollbar (el) {
      if (!el || el.nodeType !== Node.ELEMENT_NODE) return false

      const style = window.getComputedStyle(el)
      return ['auto', 'scroll'].includes(style['overflow-y']) && el.scrollHeight > el.clientHeight
    },
    shouldScroll (el, delta) {
      if (el.scrollTop === 0 && delta < 0) return true
      return el.scrollTop + el.clientHeight === el.scrollHeight && delta > 0
    },
    isInside (el, parent) {
      if (el === parent) {
        return true
      } else if (el === null || el === document.body) {
        return false
      } else {
        return this.isInside(el.parentNode, parent)
      }
    },
    /**
     * @param {Event} e
     * @returns boolean
     */
    checkPath (e) {
      const path = e.path || this.composedPath(e)
      const delta = e.deltaY || -e.wheelDelta

      if (e.type === 'keydown' && path[0] === document.body) {
        const dialog = this.$refs.dialog
        const selected = window.getSelection().anchorNode
        if (this.hasScrollbar(dialog) && this.isInside(selected, dialog)) {
          return this.shouldScroll(dialog, delta)
        }
        return true
      }

      for (let index = 0; index < path.length; index++) {
        const el = path[index]

        if (el === document) return true
        if (el === document.documentElement) return true
        if (el === this.$refs.content) return true

        if (this.hasScrollbar(el)) return this.shouldScroll(el, delta)
      }

      return true
    },
    /**
     * Polyfill for Event.prototype.composedPath
     * @param {Event} e
     * @returns Element[]
     */
    composedPath (e) {
      if (e.composedPath) return e.composedPath()

      const path = []
      let el = e.target

      while (el) {
        path.push(el)

        if (el.tagName === 'HTML') {
          path.push(document)
          path.push(window)

          return path
        }

        el = el.parentElement
      }
    },
    hideScroll () {
      if (this.$vuetify.breakpoint.smAndDown) {
        document.documentElement.classList.add('overflow-y-hidden')
      } else {
        window.addEventListener('wheel', this.scrollListener)
        window.addEventListener('keydown', this.scrollListener)
      }
    },
    showScroll () {
      document.documentElement.classList.remove('overflow-y-hidden')
      window.removeEventListener('wheel', this.scrollListener)
      window.removeEventListener('keydown', this.scrollListener)
    }
  }
}


const padStart = (string, targetLength, padString) => {
  targetLength = targetLength >> 0
  string = String(string)
  padString = String(padString)
  if (string.length > targetLength) {
    return String(string)
  }

  targetLength = targetLength - string.length
  if (targetLength > padString.length) {
    padString += padString.repeat(targetLength / padString.length)
  }
  return padString.slice(0, targetLength) + String(string)
}

export default (n, length = 2) => padStart(n, length, '0')


export interface VuetifyLanguage {
  locales: Record<string, VuetifyLocale>
  current: string
  t (key: string, ...params: Array<string | number>): string
}

// TODO: complete list of keys?
export interface VuetifyLocale {
  [key: string]: VuetifyLocale | string
}


>0.5%
last 2 versions
not dead
not op_mini all


}
},
beforeDestroy () {
this.removeOverlay()
},

computed: {
hasOverlay () {
return !this.hideOverlay
}
},


import Ripple from '../directives/ripple'

/* @vue/component */
export default {
  name: 'rippleable',

  directives: { Ripple },

  props: {
    ripple: {
      type: [Boolean, Object],
      default: true
    }
  },

  methods: {
    genRipple (data = {}) {
      if (!this.ripple) return null

      data.staticClass = 'v-input--selection-controls__ripple'

      if (this.rippleClasses) data.staticClass += ` ${this.rippleClasses}`

      data.directives = data.directives || []
      data.directives.push({
        name: 'ripple',
        value: { center: true }
      })
      data.on = Object.assign({
        click: this.onChange
      }, this.$listeners)

      return this.$createElement('div', data)
    },
    onChange () {}
  }
}


import { VNodeDirective } from 'vue'

function style (el: HTMLElement, value: string) {
  el.style['transform'] = value
  el.style['webkitTransform'] = value
}

declare global {
  interface Element {
    getElementsByClassName(classNames: string): NodeListOf<HTMLElement>
  }

  interface HTMLElement {
    _ripple: undefined | {
      enabled?: boolean
      centered?: boolean
      class?: string
    }
  }
}

interface RippleOptions {
  class?: string
  center?: boolean
}

const ripple = {
  show (e: MouseEvent, el: HTMLElement, value: RippleOptions = {}) {
    if (!el._ripple || !el._ripple.enabled) {
      return
    }

    const container = document.createElement('span')
    const animation = document.createElement('span')

    container.appendChild(animation)
    container.className = 'v-ripple__container'

    if (value.class) {
      container.className += ` ${value.class}`
    }

    const size = Math.max(el.clientWidth, el.clientHeight) * (value.center ? 1 : 2)
    const halfSize = size / 2
    animation.className = 'v-ripple__animation'
    animation.style.width = `${size}px`
    animation.style.height = `${size}px`

    el.appendChild(container)
    const computed = window.getComputedStyle(el)
    if (computed.position !== 'absolute' && computed.position !== 'fixed') el.style.position = 'relative'

    const offset = el.getBoundingClientRect()
    const x = value.center ? 0 : e.clientX - offset.left - halfSize
    const y = value.center ? 0 : e.clientY - offset.top - halfSize

    animation.classList.add('v-ripple__animation--enter')
    animation.classList.add('v-ripple__animation--visible')
    style(animation, `translate(${x}px, ${y}px) scale3d(0, 0, 0)`)
    animation.dataset.activated = String(performance.now())

    setTimeout(() => {
      animation.classList.remove('v-ripple__animation--enter')
      style(animation, `translate(${x}px, ${y}px)  scale3d(1, 1, 1)`)
    }, 0)
  },

  hide (el: HTMLElement | null) {
    if (!el || !el._ripple || !el._ripple.enabled) return

    const ripples = el.getElementsByClassName('v-ripple__animation')

    if (ripples.length === 0) return
    const animation = ripples[ripples.length - 1]

    if (animation.dataset.isHiding) return
    else animation.dataset.isHiding = 'true'

    const diff = performance.now() - Number(animation.dataset.activated)
    let delay = Math.max(300 - diff, 0)

    setTimeout(() => {
      animation.classList.remove('v-ripple__animation--visible')

      setTimeout(() => {
        const ripples = el.getElementsByClassName('v-ripple__animation')
        if (ripples.length === 0) el.style.position = null
        animation.parentNode && el.removeChild(animation.parentNode)
      }, 300)
    }, delay)
  }
}

function isRippleEnabled (value: any): value is true {
  return typeof value === 'undefined' || !!value
}

function rippleShow (e: MouseEvent) {
  const value: RippleOptions = {}
  const element = e.currentTarget as HTMLElement
  if (!element) return
  value.center = element._ripple!.centered
  if (element._ripple!.class) {
    value.class = element._ripple!.class
  }
  ripple.show(e, element, value)
}

function rippleHide (e: Event) {
  ripple.hide(e.currentTarget as HTMLElement | null)
}

function updateRipple (el: HTMLElement, binding: VNodeDirective, wasEnabled: boolean) {
  const enabled = isRippleEnabled(binding.value)
  if (!enabled) {
    ripple.hide(el)
  }
  el._ripple = el._ripple || {}
  el._ripple.enabled = enabled
  const value = binding.value || {}
  if (value.center) {
    el._ripple.centered = true
  }
  if (value.class) {
    el._ripple.class = binding.value.class
  }
  if (enabled && !wasEnabled) {
    if ('ontouchstart' in window) {
      el.addEventListener('touchend', rippleHide, false)
      el.addEventListener('touchcancel', rippleHide, false)
    }

    el.addEventListener('mousedown', rippleShow, false)
    el.addEventListener('mouseup', rippleHide, false)
    el.addEventListener('mouseleave', rippleHide, false)
    // Anchor tags can be dragged, causes other hides to fail - #1537
    el.addEventListener('dragstart', rippleHide, false)
  } else if (!enabled && wasEnabled) {
    removeListeners(el)
  }
}

function removeListeners (el: HTMLElement) {
  el.removeEventListener('mousedown', rippleShow, false)
  el.removeEventListener('touchend', rippleHide, false)
  el.removeEventListener('touchcancel', rippleHide, false)
  el.removeEventListener('mouseup', rippleHide, false)
  el.removeEventListener('mouseleave', rippleHide, false)
  el.removeEventListener('dragstart', rippleHide, false)
}

function directive (el: HTMLElement, binding: VNodeDirective) {
  updateRipple(el, binding, false)
}

function unbind (el: HTMLElement) {
  delete el._ripple
  removeListeners(el)
}

function update (el: HTMLElement, binding: VNodeDirective) {
  if (binding.value === binding.oldValue) {
    return
  }

  const wasEnabled = isRippleEnabled(binding.oldValue)
  updateRipple(el, binding, wasEnabled)
}

export default {
  name: 'ripple',
  bind: directive,
  unbind,
  update
}


@import '../bootstrap'
@import '../theme'

v-text-field($material)
  .v-input__slot:before
    background-color: $material.input-bottom-line

  &:not(.v-input--has-state)
    .v-input__slot:hover:before
      background-color: $material.text.primary

  &.v-input--is-disabled
    .v-input__slot:before
      background-color: transparent
      background-image: linear-gradient(
        to right,
        $material.text.disabled 0,
        $material.text.disabled 33%,
        transparent 0
      )

  &__prefix,
  &__suffix
    color: $material.text.secondary

  &--solo
    .v-input__slot
      border-radius: 2px
      background: $material.cards

  &--solo-inverted.v-text-field--solo
    .v-input__slot
      background: rgba($material.inputs.solo-inverted)

    &.v-input--is-focused
      .v-input__slot
        background: rgba($material.inputs.solo-inverted-focused)

        .v-label,
        input
          color: $material.inputs.solo-inverted-focused-text

  &--box
    .v-input__slot
      background: $material.text-fields.box

    &:not(.v-input--is-focused)
      .v-input__slot:hover
        background: $material.text-fields.box-hover

  &--outline
    .v-input__slot
      border: 2px solid $material.text.secondary

    &:not(.v-input--is-focused)
      .v-input__slot:hover
        border: 2px solid $material.text.primary

v-text-field-rtl()
  .v-label
    transform-origin: top right

  .v-counter
    margin-left: 0
    margin-right: 8px

  &--enclosed
    .v-input__append-outer
      margin-left: 0
      margin-right: 16px

    .v-input__prepend-outer
      margin-left: 16px
      margin-right: 0

  &--reverse
    input
      text-align: left

    .v-label
      transform-origin: top left

  &__prefix
    text-align: left
    padding-right: 0
    padding-left: 4px

  &__suffix
    padding-left: 0
    padding-right: 4px

  &--reverse
    .v-text-field__prefix
      text-align: right
      padding-left: 0
      padding-right: 4px

    .v-text-field__suffix
      padding-left: 0
      padding-right: 4px

theme(v-text-field, "v-text-field")
rtl(v-text-field-rtl, "v-text-field")

.v-text-field
  input
    flex: 1 1 auto
    line-height: 20px
    padding: 8px 0 8px
    max-width: 100%
    width: 100%

  .v-input__prepend-inner,
  .v-input__append-inner
    align-self: flex-start
    display: inline-flex
    margin-top: 4px
    line-height: 1
    user-select: none

  .v-input__prepend-inner
    margin-right: auto
    padding-right: 4px

  .v-input__append-inner
    margin-left: auto
    padding-left: 4px

  .v-counter
    margin-left: 8px
    white-space: nowrap

  .v-label
    max-width: 90%
    overflow: hidden
    text-overflow: ellipsis
    top: 6px // equal to the margin top of icons
    transform-origin: top left
    white-space: nowrap

    &--active
      max-width: 100%
      transform: translateY(-18px) scale(.75)

  .v-input__slot
    transition: background $primary-transition

    &:before,
    &:after
      bottom: -1px // Needed for browser autocomplete styles
      content: ''
      left: 0
      position: absolute
      transition: $primary-transition
      width: 100%

    &:before
      background-color: transparent
      background-position: bottom
      background-size: 3px 1px
      background-repeat: repeat-x
      height: 1px

    &:after
      background-color: currentColor
      height: 2px
      transform: scaleX(0)

  &__details
    display: flex
    flex: 1 0 auto
    max-width: 100%
    overflow: hidden

  &__prefix,
  &__suffix
    align-self: center
    cursor: default

  &__prefix
    width: 16px
    text-align: right
    padding-right: 4px

  &__suffix
    padding-left: 4px
    white-space: nowrap

  &--reverse
    .v-text-field__prefix
      text-align: left
      padding-right: 0
      padding-left: 4px

    .v-text-field__suffix
      padding-left: 0
      padding-right: 4px

  &__slot
    display: flex
    flex: 1 1 auto
    height: 100%
    position: relative

  &--box,
  &--outline
    position: relative

    .v-input__slot
      align-items: stretch

    input
      margin-top: 22px

    &.v-text-field--single-line
      input
        margin-top: 12px

    .v-label
      top: 18px

      &--active
        transform: translateY(-6px) scale(.75)

    .v-input__slot
      min-height: 56px

  &--box
    .v-input__slot
      border-top-left-radius: 4px
      border-top-right-radius: 4px

      &:before
        height: 2px

  &.v-text-field--enclosed
    margin: 0

    &:not(.v-text-field--box)
      .v-progress-linear__background
        display: none

    .v-input__prepend-outer,
    .v-input__prepend-inner,
    .v-input__append-inner,
    .v-input__append-outer
      margin-top: 16px

    .v-text-field__details,
    .v-input__slot
      padding: 0 12px

    .v-text-field__details
      margin-bottom: 8px

  &--full-width
    &.v-input
      margin-bottom: 0
      margin-top: 0

    .v-label
      top: calc(50% - 10px)

    .v-input__slot
      padding: 16px 0

    .v-input__prepend-outer,
    .v-input__append-outer
      margin-top: 4px

    .v-input__append-inner
      align-self: center
      margin-top: 0

  &--reverse
    input
      text-align: right

    .v-label
      transform-origin: top right

    .v-input__slot,
    .v-text-field__slot
      flex-direction: row-reverse

  &--solo,
  &--outline,
  &--full-width
    .v-input__slot
      &:before,
      &:after
        display: none

  &--outline
    margin-bottom: 16px
    transition: border $primary-transition

    .v-input__slot
      background: transparent !important
      border-radius: 4px

    .v-input__prepend-outer,
    .v-input__append-outer
      margin-top: 18px // 2px for border

    &.v-input--is-focused
      .v-input__slot
        border: 2px solid currentColor
        transition: border $primary-transition

  &.v-text-field--solo
    .v-label
      top: calc(50% - 10px)

    .v-input__control
      min-height: 48px
      padding: 0

    &:not(.v-text-field--solo-flat)
      .v-input__slot
        elevation(2)

    .v-text-field__slot
      align-items: center

    .v-input__append-inner,
    .v-input__prepend-inner
      align-self: center
      margin-top: 0

    .v-input__prepend-outer,
    .v-input__append-outer
      margin-top: 12px

  &.v-input--is-focused
    .v-input__slot:after
      transform: scaleX(1)

  &.v-input--has-state
    .v-input__slot:before
      background-color: currentColor


// If fn is called and timeout is active

// cancel removal of overlay and re-add active

keep keep keep keep keep replace keep keep keep

@import '../bootstrap'

.v-overlay
  position: fixed
  top: 0
  left: 0
  right: 0
  bottom: 0
  pointer-events: none
  // The overlay has a dynamically set
  // z-index, we want the transition
  // timing to affect its changing
  // https://github.com/vuetifyjs/vuetify/issues/2146
  transition: .3s $transition.swing
  // This is the standard index
  z-index: 5

  &--absolute
    position: absolute

  &:before
    background-color: rgba(33, 33, 33, 1)
    bottom: 0
    content: ''
    height: 100%
    left: 0
    opacity: 0
    position: absolute
    right: 0
    top: 0
    transition: inherit
    // Delay the transition to avoid a
    // rendering bug that is visible
    // within Edge and Firefox
    // https://github.com/vuetifyjs/vuetify/issues/2146
    transition-delay: 150ms
    width: 100%

  &--active
    pointer-events: auto
    touch-action: none

    &:before
      opacity: .46


require('dotenv').config()

const os = require('os')
const HappyPack = require('happypack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')

const isProd = process.env.NODE_ENV === 'production'
const extractCSS = isProd || process.env.TARGET === 'development'

exports.happyThreadPool = HappyPack.ThreadPool({
  size: Math.min(os.cpus().length, 4)
})

const cssLoaders = [
  // https://github.com/webpack-contrib/mini-css-extract-plugin#user-content-advanced-configuration-example
  // TODO: remove style-loader: https://github.com/webpack-contrib/mini-css-extract-plugin/issues/34
  extractCSS ? MiniCssExtractPlugin.loader : 'style-loader',
  { loader: 'css-loader', options: { sourceMap: !isProd } },
  { loader: 'postcss-loader', options: { sourceMap: !isProd } },
  { loader: 'stylus-loader', options: { sourceMap: !isProd } }
]

const plugins = [
  new FriendlyErrorsWebpackPlugin({
    clearConsole: true
  })
]

extractCSS || plugins.push(
  new HappyPack({
    id: 'stylus',
    threadPool: exports.happyThreadPool,
    loaders: cssLoaders
  })
)

exports.config = {
  mode: isProd ? 'production' : 'development',
  resolve: {
    extensions: ['*', '.js', '.json', '.vue', '.ts']
  },
  node: {
    fs: 'empty'
  },
  module: {
    rules: [
      {
        test: /\.styl$/,
        use: extractCSS ? cssLoaders : 'happypack/loader?id=stylus'
      }
    ]
  },
  plugins,
  performance: {
    hints: false
  },
  stats: { children: false }
}


import VBtnToggle from './VBtnToggle'

/* istanbul ignore next */
VBtnToggle.install = function install (Vue) {
  Vue.component(VBtnToggle.options.name, VBtnToggle)
}

export { VBtnToggle }
export default VBtnToggle


import { test } from '@/test'
import VSystemBar from '@/components/VSystemBar'

test('VSystemBar.vue', ({ mount }) => {
  it('should render a colored system bar', () => {
    const wrapper = mount(VSystemBar, {
      propsData: {
        color: 'blue lighten-1'
      }
    })

    expect(wrapper.element.classList).toContain('blue')
    expect(wrapper.element.classList).toContain('lighten-1')
  })

  it('should render system bar with fixed prop', () => {
    const wrapper = mount(VSystemBar, {
      propsData: {
        fixed: true
      }
    })

    expect(wrapper.element.classList).toContain('v-system-bar--fixed')
  })

  it('should render system bar with absolute prop', () => {
    const wrapper = mount(VSystemBar, {
      propsData: {
        absolute: true
      }
    })

    expect(wrapper.element.classList).toContain('v-system-bar--absolute')
  })

  it('should update height when window prop change', async () => {
    const wrapper = mount(VSystemBar, {
      propsData: {
        app: true
      }
    })

    expect(wrapper.vm.$vuetify.application.bar).toBe(24)

    wrapper.setProps({
      window: true
    })
    expect(wrapper.vm.$vuetify.application.bar).toBe(32)

    wrapper.setProps({
      height: 90
    })
    expect(wrapper.vm.$vuetify.application.bar).toBe(90)
  })

  it('should warn for improper height', () => {
    const wrapper = mount(VSystemBar, {
      propsData: {
        height: 'foo'
      }
    })

    expect('custom validator check failed for prop "height"').toHaveBeenWarned()
  })
})


if ((!this.isActive || this.hideOverlay) ||

(this.isActive && this.overlayTimeout) ||

if ((!this.isActive || !this.hasOverlay) ||


// Styles
import '../../stylus/components/_overflow-buttons.styl'

// Extensions
import VSelect from '../VSelect/VSelect'
import VAutocomplete from '../VAutocomplete'
import VTextField from '../VTextField/VTextField'

import VBtn from '../VBtn'

import { consoleWarn } from '../../util/console'

/* @vue/component */
export default {
  name: 'v-overflow-btn',

  extends: VAutocomplete,

  props: {
    segmented: Boolean,
    editable: Boolean,
    transition: VSelect.props.transition
  },

  computed: {
    classes () {
      return Object.assign(VAutocomplete.computed.classes.call(this), {
        'v-overflow-btn': true,
        'v-overflow-btn--segmented': this.segmented,
        'v-overflow-btn--editable': this.editable
      })
    },
    isAnyValueAllowed () {
      return this.editable ||
        VAutocomplete.computed.isAnyValueAllowed.call(this)
    },
    isSingle () {
      return true
    },
    computedItems () {
      return this.segmented ? this.allItems : this.filteredItems
    }
  },

  methods: {
    genSelections () {
      return this.editable
        ? VAutocomplete.methods.genSelections.call(this)
        : VSelect.methods.genSelections.call(this) // Override v-autocomplete's override
    },
    genCommaSelection (item, index, last) {
      return this.segmented
        ? this.genSegmentedBtn(item)
        : VSelect.methods.genCommaSelection.call(this, item, index, last)
    },
    genInput () {
      const input = VTextField.methods.genInput.call(this)

      input.data.domProps.value = this.editable ? this.internalSearch : ''
      input.data.attrs.readonly = !this.isAnyValueAllowed

      return input
    },
    genLabel () {
      if (this.editable && this.isFocused) return null

      const label = VTextField.methods.genLabel.call(this)

      if (!label) return label

      // Reset previously set styles from parent
      label.data.style = {}

      return label
    },
    genSegmentedBtn (item) {
      const itemValue = this.getValue(item)
      const itemObj = this.computedItems.find(i => this.getValue(i) === itemValue) || item

      if (!itemObj.text || !itemObj.callback) {
        consoleWarn('When using \'segmented\' prop without a selection slot, items must contain both a text and callback property', this)
        return null
      }

      return this.$createElement(VBtn, {
        props: { flat: true },
        on: {
          click (e) {
            e.stopPropagation()
            itemObj.callback(e)
          }
        }
      }, [itemObj.text])
    },
    setSelectedItems () {
      if (this.internalValue == null) {
        this.selectedItems = []
      } else {
        this.selectedItems = [this.internalValue]
      }
    }
  }
}


import { test } from '@/test'
import VAlert from '@/components/VAlert'
import VIcon from '@/components/VIcon'

test('VAlert.vue', ({ mount }) => {
  it('should be closed by default', async () => {
    const wrapper = mount(VAlert)

    expect(wrapper.vm.isActive).toBe(false)
    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should have a close icon', async () => {
    const wrapper = mount(VAlert, {
      propsData: { dismissible: true }
    })

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component with transition', async () => {
    const wrapper = mount(VAlert, {
      propsData: { transition: 'foo' }
    })

    wrapper.setProps({ value: true })
    await wrapper.vm.$nextTick()
    expect(wrapper.hasClass('foo-enter')).toBe(true)
  })

  it('should render component with outline prop', async () => {
    const wrapper = mount(VAlert, {
      propsData: { outline: true }
    })

    expect(wrapper.hasClass('v-alert--outline')).toBe(true)
  })

  it('should be dismissible', async () => {
    const wrapper = mount(VAlert, {
      propsData: {
        value: true,
        dismissible: true
      }
    })

    const icon = wrapper.find('.v-alert__dismissible')[0]

    const input = jest.fn(value => wrapper.setProps({ value }))
    wrapper.vm.$on('input', input)

    icon.trigger('click')

    await wrapper.vm.$nextTick()

    expect(input).toBeCalledWith(false)
    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should have a custom icon', async () => {
    const wrapper = mount(VAlert, {
      propsData: {
        value: true,
        icon: 'list'
      }
    })

    const icon = wrapper.find('.v-alert__icon')[0]

    expect(icon.text()).toBe('list')
  })

  it('should have no icon', () => {
    const wrapper = mount(VAlert)

    expect(wrapper.contains('.v-icon')).toBe(false)
  })

  it('should display contextual colors by type', async () => {
    const wrapper = mount(VAlert, {
      propsData: {
        type: 'error'
      }
    })

    expect(wrapper.vm.classes.error).toBe(true)

    wrapper.setProps({ 'type': 'success' })
    await wrapper.vm.$nextTick()
    expect(wrapper.vm.classes.success).toBe(true)

    wrapper.setProps({ 'type': 'warning' })
    await wrapper.vm.$nextTick()
    expect(wrapper.vm.classes.warning).toBe(true)

    wrapper.setProps({ 'type': 'info' })
    await wrapper.vm.$nextTick()
    expect(wrapper.vm.classes.info).toBe(true)
  })

  it('should allow overriding color for contextual alert', async () => {
    const wrapper = mount(VAlert, {
      propsData: {
        type: 'error',
        color: 'primary'
      }
    })

    expect(wrapper.vm.classes.primary).toBe(true)
  })

  it('should allow overriding icon for contextual alert', async () => {
    const wrapper = mount(VAlert, {
      propsData: {
        type: 'error',
        icon: 'block'
      }
    })

    const icon = wrapper.find('.v-alert__icon')[0]

    expect(icon.text()).toBe('block')
  })
})


import VCarousel from '@/components/VCarousel'
import VCarouselItem from '@/components/VCarousel/VCarouselItem'
import { test, touch } from '@/test'
import Vue from 'vue'

const create = (props = {}, slots = 3) => Vue.component('zxc', {
  functional: true,
  render (h) {
    const items = []
    for (let i = 0; i < slots; i++) {
      items.push(h(VCarouselItem, { props: { src: `${i + 1}` } }))
    }
    return h(VCarousel, { props }, items)
  }
})

test('VCarousel.js', ({ mount }) => {
  it('should render component and match snapshot', async () => {
    const wrapper = mount(VCarousel)
    await wrapper.vm.$nextTick()

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component in RTL mode and match snapshot', async () => {
    const wrapper = mount(VCarousel)
    wrapper.vm.$vuetify.rtl = true
    await wrapper.vm.$nextTick()

    expect(wrapper.html()).toMatchSnapshot()
    wrapper.vm.$vuetify.rtl = undefined
  })

  it('should render component with image cycling off and match snapshot', async () => {
    const wrapper = mount(VCarousel, {
      propsData: {
        cycle: false
      }
    })
    await wrapper.vm.$nextTick()

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component with custom icon and match snapshot', async () => {
    const component = create({
      delimiterIcon: 'stop'
    })
    const wrapper = mount(component)
    await wrapper.vm.$nextTick()

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component with custom duration between image cycles and match snapshot', async () => {
    const wrapper = mount(VCarousel, {
      propsData: {
        interval: 1000
      }
    })
    await wrapper.vm.$nextTick()

    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component with custom prev icon and match snapshot', async () => {
    const wrapper = mount(VCarousel, {
      propsData: {
        prevIcon: 'stop'
      }
    })
    await wrapper.vm.$nextTick()

    expect(wrapper.find('.v-carousel__prev .v-icon')[0].text()).toBe('stop')
    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component without prev icon and match snapshot', async () => {
    const wrapper = mount(VCarousel, {
      propsData: {
        prevIcon: false
      }
    })
    await wrapper.vm.$nextTick()

    expect(wrapper.contains('.v-carousel__prev')).toBe(false)
    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component with custom next icon and match snapshot', async () => {
    const wrapper = mount(VCarousel, {
      propsData: {
        nextIcon: 'stop'
      }
    })
    await wrapper.vm.$nextTick()

    expect(wrapper.find('.v-carousel__next .v-icon')[0].text()).toBe('stop')
    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component without next icon and match snapshot', async () => {
    const wrapper = mount(VCarousel, {
      propsData: {
        nextIcon: false
      }
    })
    await wrapper.vm.$nextTick()

    expect(wrapper.contains('.v-carousel__next')).toBe(false)
    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component with selected active item', async () => {
    const component = create({ value: 1 })
    const wrapper = mount(component)
    await wrapper.vm.$nextTick()

    expect(wrapper.html()).toMatchSnapshot()
  })

  // TODO: Use jest's fake timers
  it('should emit input event after interval', async () => {
    const vm = mount(VCarousel).vm
    const wrapper = mount(VCarousel, {
      propsData: {
        value: 1,
        interval: 1
      },
      slots: {
        default: [1, 2, 3].map(i => {
          return {
            vNode: vm.$createElement(VCarouselItem, { attrs: { src: i.toString() } })
          }
        })
      }
    })

    const input = jest.fn()
    await new Promise(resolve => {
      wrapper.vm.$on('input', value => {
        input(value)
        input.mock.calls.length === 3 && resolve()
      })
    })

    expect([].concat(...input.mock.calls)).toEqual([1, 2, 0])
  })

  it('should render component without delimiters', async () => {
    const component = create({ hideDelimiters: true })
    const wrapper = mount(component)
    await wrapper.vm.$nextTick()

    expect(wrapper.contains('carousel__controls')).toBe(false)
    expect(wrapper.html()).toMatchSnapshot()
  })

  it('should render component without controls', async () => {
    const component = create({ hideControls: true })
    const wrapper = mount(component)
    await wrapper.vm.$nextTick()

    expect(wrapper.find('.v-carousel__prev')).toHaveLength(0)
    expect(wrapper.find('.v-carousel__next')).toHaveLength(0)
  })

  it('should change item on swipe', async () => {
    const wrapper = mount(create())
    await wrapper.vm.$nextTick()

    const input = jest.fn()
    wrapper.vm.$children[0].$on('input', input)

    touch(wrapper).start(0, 0).end(-20, 0)
    await wrapper.vm.$nextTick()
    expect(input).toBeCalledWith(1)
    touch(wrapper).start(0, 0).end(20, 0)
    await wrapper.vm.$nextTick()
    expect(input).toBeCalledWith(0)
  })

  it('should change item on controls click', async () => {
    const wrapper = mount(create())
    await wrapper.vm.$nextTick()

    const input = jest.fn()
    wrapper.vm.$children[0].$on('input', input)

    wrapper.find('.v-carousel__controls__item')[2].trigger('click')
    await wrapper.vm.$nextTick()
    expect(input).toBeCalledWith(2)
  })
})


if (this.absolute) this.overlay.className += ' v-overlay--absolute'

keep keep keep keep replace keep keep keep keep

this.overlay.className = `v-overlay ${overlayClass}`


import Vue from 'vue'

import Vuetify from 'vuetify/es5/components/Vuetify'
import VBtn from 'vuetify/es5/components/VBtn'
import * as VCard from 'vuetify/es5/components/VCard'
import { Ripple } from 'vuetify/es5/directives'
import * as directives from 'vuetify/es5/directives'
import directivesPlugin from 'vuetify/es5/directives'

Vue.use(directivesPlugin)

Vuetify.install(Vue, {
  components: {
    VBtn,
    ...VCard
  },
  directives: {
    Ripple,
    ...directives
  }
})

Vue.extend({
  components: {
    VBtn,
    ...VCard
  },
  directives: {
    Ripple
  }
})


/**
 * Menu generators
 *
 * @mixin
 *
 * Used for creating the DOM elements for VMenu
 */
/* @vue/component */
export default {
  methods: {
    genActivator () {
      if (!this.$slots.activator) return null

      const options = {
        staticClass: 'v-menu__activator',
        'class': {
          'v-menu__activator--active': this.hasJustFocused || this.isActive,
          'v-menu__activator--disabled': this.disabled
        },
        ref: 'activator',
        on: {}
      }

      if (this.openOnHover) {
        options.on['mouseenter'] = this.mouseEnterHandler
        options.on['mouseleave'] = this.mouseLeaveHandler
      } else if (this.openOnClick) {
        options.on['click'] = this.activatorClickHandler
      }

      return this.$createElement('div', options, this.$slots.activator)
    },

    genTransition () {
      if (!this.transition) return this.genContent()

      return this.$createElement('transition', {
        props: {
          name: this.transition
        }
      }, [this.genContent()])
    },

    genDirectives () {
      // Do not add click outside for hover menu
      const directives = !this.openOnHover && this.closeOnClick ? [{
        name: 'click-outside',
        value: () => (this.isActive = false),
        args: {
          closeConditional: this.closeConditional,
          include: () => [this.$el, ...this.getOpenDependentElements()]
        }
      }] : []

      directives.push({
        name: 'show',
        value: this.isContentActive
      })

      return directives
    },

    genContent () {
      const options = {
        attrs: this.getScopeIdAttrs(),
        staticClass: 'v-menu__content',
        'class': {
          [this.contentClass.trim()]: true,
          'v-menu__content--auto': this.auto,
          'menuable__content__active': this.isActive,
          'theme--dark': this.dark,
          'theme--light': this.light
        },
        style: this.styles,
        directives: this.genDirectives(),
        ref: 'content',
        on: {
          click: e => {
            e.stopPropagation()
            if (e.target.getAttribute('disabled')) return
            if (this.closeOnContentClick) this.isActive = false
          }
        }
      }

      !this.disabled && this.openOnHover && (options.on.mouseenter = this.mouseEnterHandler)
      this.openOnHover && (options.on.mouseleave = this.mouseLeaveHandler)

      return this.$createElement('div', options, this.showLazyContent(this.$slots.default))
    }
  }
}


import { inject as RegistrableInject } from './registrable'
import { consoleError } from '../util/console'

// Mixins
import Colorable from './colorable'

/* @vue/component */
export default {
  name: 'validatable',

  mixins: [
    Colorable,
    RegistrableInject('form')
  ],

  props: {
    error: Boolean,
    errorCount: {
      type: [Number, String],
      default: 1
    },
    errorMessages: {
      type: [String, Array],
      default: () => []
    },
    messages: {
      type: [String, Array],
      default: () => []
    },
    rules: {
      type: Array,
      default: () => []
    },
    success: Boolean,
    successMessages: {
      type: [String, Array],
      default: () => []
    },
    validateOnBlur: Boolean
  },

  data: () => ({
    errorBucket: [],
    hasColor: false,
    hasFocused: false,
    hasInput: false,
    isResetting: false,
    valid: false
  }),

  computed: {
    hasError () {
      return this.internalErrorMessages.length > 0 ||
        this.errorBucket.length > 0 ||
        this.error
    },
    externalError () {
      return this.internalErrorMessages.length > 0 || this.error
    },
    // TODO: Add logic that allows the user to enable based
    // upon a good validation
    hasSuccess () {
      return this.successMessages.length > 0 ||
        this.success
    },
    hasMessages () {
      return this.validations.length > 0
    },
    hasState () {
      return this.shouldValidate && (this.hasError || this.hasSuccess)
    },
    internalErrorMessages () {
      return this.errorMessages || ''
    },
    shouldValidate () {
      return this.externalError || (!this.isResetting && (
        this.validateOnBlur
          ? this.hasFocused && !this.isFocused
          : (this.hasInput || this.hasFocused)
      ))
    },
    validations () {
      return this.validationTarget.slice(0, this.errorCount)
    },
    validationState () {
      if (this.hasError && this.shouldValidate) return 'error'
      if (this.hasSuccess && this.shouldValidate) return 'success'
      if (this.hasColor) return this.color
      return null
    },
    validationTarget () {
      const target = this.internalErrorMessages.length > 0
        ? this.errorMessages
        : this.successMessages.length > 0
          ? this.successMessages
          : this.messages

      // String
      if (!Array.isArray(target)) {
        return [target]
      // Array with items
      } else if (target.length > 0) {
        return target
      // Currently has validation
      } else if (this.shouldValidate) {
        return this.errorBucket
      } else {
        return []
      }
    }
  },

  watch: {
    rules: {
      handler (newVal, oldVal) {
        // TODO: This handler seems to trigger when input changes, even though
        // rules array stays the same? Solved it like this for now
        if (newVal.length === oldVal.length) return

        this.validate()
      },
      deep: true
    },
    internalValue () {
      // If it's the first time we're setting input,
      // mark it with hasInput
      this.hasInput = true
      this.$nextTick(this.validate)
    },
    isFocused (val) {
      if (!val) this.hasFocused = true
      // If we're not focused, and it's the first time
      // we're defocusing, set shouldValidate to true
      if (!val && !this.hasFocused) {
        this.$emit('update:error', this.errorBucket.length > 0)
      }
    },
    isResetting () {
      setTimeout(() => {
        this.hasInput = false
        this.hasFocused = false
        this.isResetting = false
      }, 0)
    },
    hasError (val) {
      if (this.shouldValidate) {
        this.$emit('update:error', val)
      }
    }
  },

  beforeMount () {
    this.validate()
  },

  created () {
    this.form && this.form.register(this)
  },

  beforeDestroy () {
    this.form && this.form.unregister(this)
  },

  methods: {
    reset () {
      this.isResetting = true
      this.internalValue = Array.isArray(this.internalValue)
        ? []
        : undefined
    },
    validate (force = false, value = this.internalValue) {
      const errorBucket = []

      if (force) this.hasInput = this.hasFocused = true

      for (let index = 0; index < this.rules.length; index++) {
        const rule = this.rules[index]
        const valid = typeof rule === 'function' ? rule(value) : rule

        if (valid === false || typeof valid === 'string') {
          errorBucket.push(valid)
        } else if (valid !== true) {
          consoleError(`Rules should return a string or boolean, received '${typeof valid}' instead`, this)
        }
      }

      this.errorBucket = errorBucket
      this.valid = errorBucket.length === 0

      return this.valid
    }
  }
}


pointer-events: auto
touch-action: none
&:before
opacity: .46

import '../../stylus/components/_dialogs.styl'

// Mixins
import Dependent from '../../mixins/dependent'
import Detachable from '../../mixins/detachable'
import Overlayable from '../../mixins/overlayable'
import Returnable from '../../mixins/returnable'
import Stackable from '../../mixins/stackable'
import Toggleable from '../../mixins/toggleable'

// Directives
import ClickOutside from '../../directives/click-outside'

// Helpers
import { getZIndex, convertToUnit } from '../../util/helpers'

/* @vue/component */
export default {
  name: 'v-dialog',

  directives: {
    ClickOutside
  },

  mixins: [
    Dependent,
    Detachable,
    Overlayable,
    Returnable,
    Stackable,
    Toggleable
  ],

  props: {
    disabled: Boolean,
    persistent: Boolean,
    fullscreen: Boolean,
    fullWidth: Boolean,
    noClickAnimation: Boolean,
    maxWidth: {
      type: [String, Number],
      default: 'none'
    },
    origin: {
      type: String,
      default: 'center center'
    },
    width: {
      type: [String, Number],
      default: 'auto'
    },
    scrollable: Boolean,
    transition: {
      type: [String, Boolean],
      default: 'dialog-transition'
    }
  },

  data () {
    return {
      animate: false,
      animateTimeout: null,
      isDependent: false,
      stackClass: 'v-dialog__content--active',
      stackMinZIndex: 200
    }
  },

  computed: {
    classes () {
      return {
        [(`v-dialog ${this.contentClass}`).trim()]: true,
        'v-dialog--active': this.isActive,
        'v-dialog--persistent': this.persistent,
        'v-dialog--fullscreen': this.fullscreen,
        'v-dialog--scrollable': this.scrollable,
        'v-dialog--animated': this.animate
      }
    },
    contentClasses () {
      return {
        'v-dialog__content': true,
        'v-dialog__content--active': this.isActive
      }
    }
  },

  watch: {
    isActive (val) {
      if (val) {
        this.show()
      } else {
        this.removeOverlay()
        this.unbind()
      }
    }
  },

  mounted () {
    this.isBooted = this.isActive
    this.isActive && this.show()
  },

  beforeDestroy () {
    if (typeof window !== 'undefined') this.unbind()
  },

  methods: {
    animateClick () {
      this.animate = false
      // Needed for when clicking very fast
      // outside of the dialog
      this.$nextTick(() => {
        this.animate = true
        clearTimeout(this.animateTimeout)
        this.animateTimeout = setTimeout(() => (this.animate = false), 150)
      })
    },
    closeConditional (e) {
      // If the dialog content contains
      // the click event, or if the
      // dialog is not active
      if (this.$refs.content.contains(e.target) ||
        !this.isActive
      ) return false

      // If we made it here, the click is outside
      // and is active. If persistent, and the
      // click is on the overlay, animate
      if (this.persistent) {
        if (!this.noClickAnimation &&
          this.overlay === e.target
        ) this.animateClick()

        return false
      }

      // close dialog if !persistent, clicked outside and we're the topmost dialog.
      // Since this should only be called in a capture event (bottom up), we shouldn't need to stop propagation
      return getZIndex(this.$refs.content) >= this.getMaxZIndex()
    },
    show () {
      !this.fullscreen && !this.hideOverlay && this.genOverlay()
      this.fullscreen && this.hideScroll()
      this.$refs.content.focus()
      this.$listeners.keydown && this.bind()
    },
    bind () {
      window.addEventListener('keydown', this.onKeydown)
    },
    unbind () {
      window.removeEventListener('keydown', this.onKeydown)
    },
    onKeydown (e) {
      this.$emit('keydown', e)
    }
  },

  render (h) {
    const children = []
    const data = {
      'class': this.classes,
      ref: 'dialog',
      directives: [
        {
          name: 'click-outside',
          value: () => (this.isActive = false),
          args: {
            closeConditional: this.closeConditional,
            include: this.getOpenDependentElements
          }
        },
        { name: 'show', value: this.isActive }
      ],
      on: {
        click: e => { e.stopPropagation() }
      }
    }

    if (!this.fullscreen) {
      data.style = {
        maxWidth: this.maxWidth === 'none' ? undefined : convertToUnit(this.maxWidth),
        width: this.width === 'auto' ? undefined : convertToUnit(this.width)
      }
    }

    if (this.$slots.activator) {
      children.push(h('div', {
        staticClass: 'v-dialog__activator',
        'class': {
          'v-dialog__activator--disabled': this.disabled
        },
        on: {
          click: e => {
            e.stopPropagation()
            if (!this.disabled) this.isActive = !this.isActive
          }
        }
      }, [this.$slots.activator]))
    }

    let dialog = h('div', data, this.showLazyContent(this.$slots.default))
    if (this.transition) {
      dialog = h('transition', {
        props: {
          name: this.transition,
          origin: this.origin
        }
      }, [dialog])
    }

    children.push(h('div', {
      'class': this.contentClasses,
      attrs: {
        tabIndex: '-1',
        ...this.getScopeIdAttrs()
      },
      style: { zIndex: this.activeZIndex },
      ref: 'content'
    }, [dialog]))

    return h('div', {
      staticClass: 'v-dialog__container',
      style: {
        display: (!this.$slots.activator || this.fullWidth) ? 'block' : 'inline-block'
      }
    }, children)
  }
}


import { addOnceEventListener } from '../../util/helpers'

export default function (expandedParentClass = '') {
  return {
    enter (el, done) {
      el._parent = el.parentNode

      addOnceEventListener(el, 'transitionend', done)

      // Get height that is to be scrolled
      el.style.overflow = 'hidden'
      el.style.height = 0
      el.style.display = 'block'
      expandedParentClass && el._parent.classList.add(expandedParentClass)

      setTimeout(() => (el.style.height = `${el.scrollHeight}px`), 100)
    },

    afterEnter (el) {
      el.style.overflow = null
      el.style.height = null
    },

    leave (el, done) {
      // Remove initial transition
      addOnceEventListener(el, 'transitionend', done)

      // Set height before we transition to 0
      el.style.overflow = 'hidden'
      el.style.height = `${el.offsetHeight}px`

      setTimeout(() => (el.style.height = 0), 100)
    },

    afterLeave (el) {
      expandedParentClass && el._parent && el._parent.classList.remove(expandedParentClass)
    }
  }
}


import VPagination from './VPagination'

/* istanbul ignore next */
VPagination.install = function install (Vue) {
  Vue.component(VPagination.name, VPagination)
}

export { VPagination }
export default VPagination


@import '../bootstrap'
@import '../theme'

/** Themes */
v-time-picker-clock($material)
  background: $material.picker.clock

  > span.disabled
    color: $material.buttons.disabled

    &.active
      color: $material-dark.buttons.disabled

  &--indeterminate
    .v-time-picker-clock__hand
      background-color: $material.picker.indeterminateTime

      &:after
        color: $material.picker.indeterminateTime

    > span.active
      background-color: $material.picker.indeterminateTime

theme(v-time-picker-clock, "v-time-picker-clock")

.v-time-picker-clock
  border-radius: 100%
  position: relative
  transition: $primary-transition
  user-select: none

  &__container
    display: flex
    align-items: center
    justify-content: center
    padding: 10px

  &__hand
    height: calc(50% - 28px)
    width: 2px
    bottom: 50%
    left: calc(50% - 1px)
    transform-origin: center bottom
    position: absolute
    will-change: transform
    z-index: 1

    &:before
      background: transparent
      border-width: 2px
      border-style: solid
      border-color: inherit
      border-radius: 100%
      width: 10px
      height: 10px
      content: ''
      position: absolute
      top: -3%
      left: 50%
      transform: translate(-50%, -50%)

    &:after
      content: ''
      position: absolute
      height: 8px
      width: 8px
      top: 100%
      left: 50%
      border-radius: 100%
      border-style: solid
      border-color: inherit
      background-color: inherit
      transform: translate(calc(-50%, - 1px), -50%)

  > span
    align-items: center
    border-radius: 100%
    cursor: default
    display: flex
    font-size: $time-picker-number-font-size
    justify-content: center
    left: 'calc(50% - %s / 2)' % $time-picker-indicator-size
    height: $time-picker-indicator-size
    position: absolute
    text-align: center
    top: 'calc(50% - %s / 2)' % $time-picker-indicator-size
    width: $time-picker-indicator-size
    user-select: none

    > span
      z-index: 1

    &:before, &:after
      content: ''
      border-radius: 100%
      position: absolute
      top: 50%
      left: 50%
      height: 14px
      width: 14px
      transform: translate(-50%, -50%)

    &:after, &:before
      height: $time-picker-indicator-size
      width: $time-picker-indicator-size

    &.active
      color: #fff
      cursor: default
      z-index: 2

    &.disabled
      pointer-events: none


const getCommitMessage = require("@lerna-test/get-commit-message");

"use strict";

// we're actually testing integration with git
jest.unmock("@lerna/collect-updates");
jest.unmock("@lerna/conventional-commits");

// local modules _must_ be explicitly mocked
jest.mock("../lib/git-push");
jest.mock("../lib/is-anything-committed");
jest.mock("../lib/is-behind-upstream");

const fs = require("fs-extra");
const path = require("path");

// helpers
const initFixture = require("@lerna-test/init-fixture")(path.resolve(__dirname, "../../publish/__tests__"));
const showCommit = require("@lerna-test/show-commit");
const gitAdd = require("@lerna-test/git-add");
const gitTag = require("@lerna-test/git-tag");
const gitCommit = require("@lerna-test/git-commit");

// test command
const lernaVersion = require("@lerna-test/command-runner")(require("../command"));

// remove quotes around top-level strings
expect.addSnapshotSerializer({
  test(val) {
    return typeof val === "string";
  },
  serialize(val, config, indentation, depth) {
    // top-level strings don't need quotes, but nested ones do (object properties, etc)
    return depth ? `"${val}"` : val;
  },
});

// stabilize commit SHA
expect.addSnapshotSerializer(require("@lerna-test/serialize-changelog"));

const setupChanges = async cwd => {
  await gitTag(cwd, "v1.0.1-beta.3");
  await fs.outputFile(path.join(cwd, "packages/package-3/hello.js"), "world");
  await gitAdd(cwd, ".");
  await gitCommit(cwd, "feat: setup");
};

test("version patch with previous prerelease also graduates prereleased", async () => {
  const testDir = await initFixture("republish-prereleased");
  // should republish 3, 4, and 5 because:
  // package 3 changed
  // package 5 has a prerelease version
  // package 4 depends on package 5

  await setupChanges(testDir);
  await lernaVersion(testDir)("patch");

  const patch = await showCommit(testDir);
  expect(patch).toMatchSnapshot();
});

test("version prerelease with previous prerelease bumps changed only", async () => {
  const testDir = await initFixture("republish-prereleased");
  // should republish only package 3, because only it changed

  await setupChanges(testDir);
  await lernaVersion(testDir)("prerelease");

  const patch = await showCommit(testDir);
  expect(patch).toMatchSnapshot();
});

test("version prerelease with previous prerelease supersedes --conventional-commits", async () => {
  const testDir = await initFixture("republish-prereleased");
  // version bump should stay prepatch --preid beta because ---conventional-commits is ignored

  await setupChanges(testDir);
  await lernaVersion(testDir)("prerelease", "--conventional-commits");

  const patch = await showCommit(testDir);
  expect(patch).toMatchSnapshot();
});


# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [3.0.5](https://github.com/lerna/lerna/compare/v3.0.4...v3.0.5) (2018-08-15)

**Note:** Version bump only for package @lerna/changed

## [3.0.2](https://github.com/lerna/lerna/compare/v3.0.1...v3.0.2) (2018-08-11)

**Note:** Version bump only for package @lerna/changed

# [3.0.0](https://github.com/lerna/lerna/compare/v3.0.0-rc.0...v3.0.0) (2018-08-10)

### Features

* Split `lerna version` from of `lerna publish` ([#1522](https://github.com/lerna/lerna/issues/1522)) ([8b97394](https://github.com/lerna/lerna/commit/8b97394)), closes [#277](https://github.com/lerna/lerna/issues/277) [#936](https://github.com/lerna/lerna/issues/936) [#956](https://github.com/lerna/lerna/issues/956) [#961](https://github.com/lerna/lerna/issues/961) [#1056](https://github.com/lerna/lerna/issues/1056) [#1118](https://github.com/lerna/lerna/issues/1118) [#1385](https://github.com/lerna/lerna/issues/1385) [#1483](https://github.com/lerna/lerna/issues/1483) [#1494](https://github.com/lerna/lerna/issues/1494)
* **changed:** Support list output options ([6ecdd83](https://github.com/lerna/lerna/commit/6ecdd83))

### BREAKING CHANGES

* **changed:** The package names emitted to stdout are no longer prefixed by a "- ", and private packages are no longer displayed by default.
* * `--preid` now defaults to "alpha" during prereleases:

  The previous default for this option was undefined, which led to an awkward "1.0.1-0" result when passed to `semver.inc()`.

  The new default "alpha" yields a much more useful "1.0.1-alpha.0" result. Any previous prerelease ID will be preserved, just as it was before.

* `--no-verify` is no longer passed to `git commit` by default, but controlled by the new `--commit-hooks` option:

  The previous behavior was too overzealous, and the new option operates exactly like the corresponding [npm version](https://docs.npmjs.com/cli/version#commit-hooks) option of the same name.

  As long as your pre-commit hooks are properly scoped to ignore changes in package.json files, this change should not affect you. If that is not the case, you may pass `--no-commit-hooks` to restore the previous behavior.

# [3.0.0-rc.0](https://github.com/lerna/lerna/compare/v3.0.0-beta.21...v3.0.0-rc.0) (2018-07-27)

### Bug Fixes

* **changed:** Clarify early exit log message ([b132c3a](https://github.com/lerna/lerna/commit/b132c3a))

### Code Refactoring

* **collect-updates:** Make argument signature explicit ([e6ba19f](https://github.com/lerna/lerna/commit/e6ba19f))

### Features

* Add description from --help summary [skip ci] ([9b65d8e](https://github.com/lerna/lerna/commit/9b65d8e))
* **cli:** Upgrade to Yargs 12 ([7899ab8](https://github.com/lerna/lerna/commit/7899ab8))
* **command:** Remove .defaultOptions() from option resolution stack ([2b27a54](https://github.com/lerna/lerna/commit/2b27a54))
* Count packages affected in command summary logging ([5f5e585](https://github.com/lerna/lerna/commit/5f5e585))

### BREAKING CHANGES

* **collect-updates:** Instead of an opaque command instance, distinct positional arguments are required.

# [3.0.0-beta.21](https://github.com/lerna/lerna/compare/v3.0.0-beta.20...v3.0.0-beta.21) (2018-05-12)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.20](https://github.com/lerna/lerna/compare/v3.0.0-beta.19...v3.0.0-beta.20) (2018-05-07)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.19](https://github.com/lerna/lerna/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2018-05-03)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.18](https://github.com/lerna/lerna/compare/v3.0.0-beta.17...v3.0.0-beta.18) (2018-04-24)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.17](https://github.com/lerna/lerna/compare/v3.0.0-beta.16...v3.0.0-beta.17) (2018-04-13)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.15](https://github.com/lerna/lerna/compare/v3.0.0-beta.14...v3.0.0-beta.15) (2018-04-09)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.14](https://github.com/lerna/lerna/compare/v3.0.0-beta.13...v3.0.0-beta.14) (2018-04-03)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.13](https://github.com/lerna/lerna/compare/v3.0.0-beta.12...v3.0.0-beta.13) (2018-03-31)

### Features

* Enable progress bars only when necessary ([b766c83](https://github.com/lerna/lerna/commit/b766c83))

# [3.0.0-beta.12](https://github.com/lerna/lerna/compare/v3.0.0-beta.11...v3.0.0-beta.12) (2018-03-30)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.11](https://github.com/lerna/lerna/compare/v3.0.0-beta.10...v3.0.0-beta.11) (2018-03-29)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.10](https://github.com/lerna/lerna/compare/v3.0.0-beta.9...v3.0.0-beta.10) (2018-03-27)

### Features

* **commands:** Delay require of command instantiation ([a1284f3](https://github.com/lerna/lerna/commit/a1284f3))

### BREAKING CHANGES

* **commands:** The default export of command packages is now a factory, not the subclass (which is now a named export).

# [3.0.0-beta.9](https://github.com/lerna/lerna/compare/v3.0.0-beta.8...v3.0.0-beta.9) (2018-03-24)

### Features

* **project:** Normalize config.commands -> config.command ([24e55e3](https://github.com/lerna/lerna/commit/24e55e3))

# [3.0.0-beta.8](https://github.com/lerna/lerna/compare/v3.0.0-beta.7...v3.0.0-beta.8) (2018-03-22)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.7](https://github.com/lerna/lerna/compare/v3.0.0-beta.6...v3.0.0-beta.7) (2018-03-20)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.4](https://github.com/lerna/lerna/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2018-03-19)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.3](https://github.com/lerna/lerna/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2018-03-15)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.2](https://github.com/lerna/lerna/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2018-03-10)

**Note:** Version bump only for package @lerna/changed

# [3.0.0-beta.1](https://github.com/lerna/lerna/compare/v3.0.0-beta.0...v3.0.0-beta.1) (2018-03-09)

**Note:** Version bump only for package @lerna/changed


# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [3.0.0](https://github.com/lerna/lerna/compare/v3.0.0-rc.0...v3.0.0) (2018-08-10)

**Note:** Version bump only for package @lerna/resolve-symlink

# [3.0.0-rc.0](https://github.com/lerna/lerna/compare/v3.0.0-beta.21...v3.0.0-rc.0) (2018-07-27)

### Features

* Upgrade to fs-extra 6 ([079d873](https://github.com/lerna/lerna/commit/079d873))


const patch = await showCommit(testDir);

test("version prerelease with existing preid bumps with the preid provide as argument", async () => {

const testDir = await initFixture("republish-prereleased");

// Version bump should have the new rc preid

await lernaVersion(testDir)("prerelease", "--preid", "rc");

const message = await getCommitMessage(testDir);


// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`conventional-commits updateChangelog() appends version bump message if no commits have been recorded 1`] = `
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## 1.0.1 (YYYY-MM-DD)

**Note:** Version bump only for package package-2

# 1.0.0 (YYYY-MM-DD)

### Features

* I should be placed in the CHANGELOG

`;

exports[`conventional-commits updateChangelog() creates files if they do not exist: leaf 1`] = `
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# 1.1.0 (YYYY-MM-DD)

### Features

* I should be placed in the CHANGELOG ([SHA](https://github.com/lerna/changelog-missing/commit/SHA))

`;

exports[`conventional-commits updateChangelog() creates files if they do not exist: root 1`] = `
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# 1.1.0 (YYYY-MM-DD)

### Features

* I should be placed in the CHANGELOG ([SHA](https://github.com/lerna/changelog-missing/commit/SHA))

`;

exports[`conventional-commits updateChangelog() supports old preset API 1`] = `
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## 1.0.1 (YYYY-MM-DD)
* fix(pkg1): A commit using the old preset API

# 1.0.0 (YYYY-MM-DD)

### Features

* I should be placed in the CHANGELOG

`;

exports[`conventional-commits updateChangelog() updates fixed changelogs: leaf 1`] = `
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [1.0.1](https://github.com/lerna/conventional-commits-fixed/compare/v1.0.0...v1.0.1) (YYYY-MM-DD)

### Bug Fixes

* A second commit for our CHANGELOG ([SHA](https://github.com/lerna/conventional-commits-fixed/commit/SHA))

# 1.0.0 (YYYY-MM-DD)

### Features

* I should be placed in the CHANGELOG

`;

exports[`conventional-commits updateChangelog() updates fixed changelogs: root 1`] = `
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [1.0.1](https://github.com/lerna/conventional-commits-fixed/compare/v1.0.0...v1.0.1) (YYYY-MM-DD)

### Bug Fixes

* A second commit for our CHANGELOG ([SHA](https://github.com/lerna/conventional-commits-fixed/commit/SHA))

# 1.0.0 (YYYY-MM-DD)

### Features

* I should be placed in the CHANGELOG

`;

exports[`conventional-commits updateChangelog() updates independent changelogs 1`] = `
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [1.0.1](https://github.com/lerna/conventional-commits-independent/compare/package-1@1.0.0...package-1@1.0.1) (YYYY-MM-DD)

### Bug Fixes

* **stuff:** changed ([SHA](https://github.com/lerna/conventional-commits-independent/commit/SHA))

`;

exports[`conventional-commits updateChangelog() updates independent changelogs 2`] = `
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [1.1.0](https://github.com/lerna/conventional-commits-independent/compare/package-2@1.0.0...package-2@1.1.0) (YYYY-MM-DD)

### Features

* **thing:** added ([SHA](https://github.com/lerna/conventional-commits-independent/commit/SHA))

`;


@lerna-test/copy-fixture

A local test helper


const { bump, conventionalCommits, preid } = this.options;

const repoVersion = bump ? semver.clean(bump) : "";

const increment = bump && !semver.valid(bump) ? bump : "";

const isPrerelease = increment.startsWith("pre");

const resolvePrereleaseId = existingPreid => (isPrerelease && existingPreid) || preid || "alpha";

const makeGlobalVersionPredicate = nextVersion => {

const resolvePrereleaseId = existingPreid => preid || (isPrerelease && existingPreid) || "alpha";


"use strict";

const path = require("path");
const pMap = require("p-map");

const Command = require("@lerna/command");
const rimrafDir = require("@lerna/rimraf-dir");
const PromptUtilities = require("@lerna/prompt");

module.exports = factory;

function factory(argv) {
  return new CleanCommand(argv);
}

class CleanCommand extends Command {
  get requiresGit() {
    return false;
  }

  initialize() {
    this.directoriesToDelete = this.filteredPackages.map(pkg => pkg.nodeModulesLocation);

    if (this.options.yes) {
      return true;
    }

    this.logger.info("", "Removing the following directories:");
    this.logger.info(
      "clean",
      this.directoriesToDelete.map(dir => path.relative(this.project.rootPath, dir)).join("\n")
    );

    return PromptUtilities.confirm("Proceed?");
  }

  execute() {
    this.enableProgressBar();

    const tracker = this.logger.newItem("clean");
    const mapper = dirPath => {
      tracker.info("clean", "removing", dirPath);

      return rimrafDir(dirPath).then(() => {
        tracker.completeWork(1);
      });
    };

    tracker.addWork(this.directoriesToDelete.length);

    return pMap(this.directoriesToDelete, mapper, { concurrency: this.concurrency }).then(() => {
      tracker.finish();
      this.logger.success("clean", "finished");
    });
  }
}

module.exports.CleanCommand = CleanCommand;


"use strict";

// mocked modules
const output = require("@lerna/output");

// helpers
const initFixture = require("@lerna-test/init-fixture")(__dirname);

// file under test
const lernaLs = require("@lerna-test/command-runner")(require("../command"));

// remove quotes around top-level strings
expect.addSnapshotSerializer({
  test(val) {
    return typeof val === "string";
  },
  serialize(val, config, indentation, depth) {
    // top-level strings don't need quotes, but nested ones do (object properties, etc)
    return depth ? `"${val}"` : val;
  },
});

// normalize temp directory paths in snapshots
expect.addSnapshotSerializer(require("@lerna-test/serialize-windows-paths"));
expect.addSnapshotSerializer(require("@lerna-test/serialize-tempdir"));

describe("lerna ls", () => {
  describe("in a basic repo", () => {
    let testDir;

    beforeAll(async () => {
      testDir = await initFixture("basic");
    });

    it("should list public packages", async () => {
      await lernaLs(testDir)();
      expect(output.logged()).toMatchInlineSnapshot(`
package-1
package-2
package-3
package-4
`);
    });

    it("should also list private packages with --all", async () => {
      await lernaLs(testDir)("--all");
      expect(output.logged()).toMatchInlineSnapshot(`
package-1
package-2
package-3
package-4
package-5 (PRIVATE)
`);
    });

    it("lists public package versions and relative paths with --long", async () => {
      await lernaLs(testDir)("--long");
      expect(output.logged()).toMatchInlineSnapshot(`
package-1 v1.0.0 packages/package-1
package-2 v1.0.0 packages/package-2
package-3 v1.0.0 packages/package-3
package-4 v1.0.0 packages/package-4
`);
    });

    it("lists all package versions and relative paths with --long --all", async () => {
      await lernaLs(testDir)("-la");
      expect(output.logged()).toMatchInlineSnapshot(`
package-1 v1.0.0 packages/package-1
package-2 v1.0.0 packages/package-2
package-3 v1.0.0 packages/package-3
package-4 v1.0.0 packages/package-4
package-5 v1.0.0 packages/package-5 (PRIVATE)
`);
    });

    it("lists public package locations with --parseable", async () => {
      await lernaLs(testDir)("--parseable");
      expect(output.logged()).toMatchInlineSnapshot(`
<PROJECT_ROOT>/packages/package-1
<PROJECT_ROOT>/packages/package-2
<PROJECT_ROOT>/packages/package-3
<PROJECT_ROOT>/packages/package-4
`);
    });

    it("lists all package locations with --parseable --all", async () => {
      await lernaLs(testDir)("-pa");
      expect(output.logged()).toMatchInlineSnapshot(`
<PROJECT_ROOT>/packages/package-1
<PROJECT_ROOT>/packages/package-2
<PROJECT_ROOT>/packages/package-3
<PROJECT_ROOT>/packages/package-4
<PROJECT_ROOT>/packages/package-5
`);
    });

    it("lists public package locations with --parseable --long", async () => {
      await lernaLs(testDir)("--parseable", "--long");
      expect(output.logged()).toMatchInlineSnapshot(`
<PROJECT_ROOT>/packages/package-1:package-1:1.0.0
<PROJECT_ROOT>/packages/package-2:package-2:1.0.0
<PROJECT_ROOT>/packages/package-3:package-3:1.0.0
<PROJECT_ROOT>/packages/package-4:package-4:1.0.0
`);
    });

    it("lists all package locations with --parseable --long --all", async () => {
      await lernaLs(testDir)("-pal");
      expect(output.logged()).toMatchInlineSnapshot(`
<PROJECT_ROOT>/packages/package-1:package-1:1.0.0
<PROJECT_ROOT>/packages/package-2:package-2:1.0.0
<PROJECT_ROOT>/packages/package-3:package-3:1.0.0
<PROJECT_ROOT>/packages/package-4:package-4:1.0.0
<PROJECT_ROOT>/packages/package-5:package-5:1.0.0:PRIVATE
`);
    });

    it("lists packages matching --scope", async () => {
      await lernaLs(testDir)("--scope", "package-1");
      expect(output.logged()).toMatchInlineSnapshot(`package-1`);
    });

    it("does not list packages matching --ignore", async () => {
      await lernaLs(testDir)("--ignore", "package-@(2|3|4|5)");
      expect(output.logged()).toMatchInlineSnapshot(`package-1`);
    });

    it("does not list private packages with --no-private", async () => {
      await lernaLs(testDir)("--no-private");
      expect(output.logged()).not.toMatch("package-5 v1.0.0 (private)");
    });
  });

  describe("in a repo with packages outside of packages/", () => {
    it("should list packages", async () => {
      const testDir = await initFixture("extra");
      await lernaLs(testDir)();
      expect(output.logged()).toMatchInlineSnapshot(`
package-3
package-1
package-2
`);
    });
  });

  describe("--include-filtered-dependencies", () => {
    it("should list packages, including filtered ones", async () => {
      const testDir = await initFixture("include-filtered-dependencies");
      await lernaLs(testDir)("--scope", "@test/package-2", "--include-filtered-dependencies");
      expect(output.logged()).toMatchInlineSnapshot(`
@test/package-2
@test/package-1
`);
    });
  });

  describe("--include-filtered-dependents", () => {
    it("should list packages, including filtered ones", async () => {
      const testDir = await initFixture("include-filtered-dependencies");
      await lernaLs(testDir)("--scope", "@test/package-1", "--include-filtered-dependents");
      expect(output.logged()).toMatchInlineSnapshot(`
@test/package-1
@test/package-2
`);
    });
  });

  describe("with an undefined version", () => {
    it("replaces version with MISSING", async () => {
      const testDir = await initFixture("undefined-version");
      await lernaLs(testDir)("--long");
      expect(output.logged()).toMatchInlineSnapshot(`package-1 MISSING packages/package-1`);
    });

    it("appends MISSING flag to long parseable output", async () => {
      const testDir = await initFixture("undefined-version");
      await lernaLs(testDir)("--long", "--parseable");
      expect(output.logged()).toMatchInlineSnapshot(`<PROJECT_ROOT>/packages/package-1:package-1:MISSING`);
    });
  });

  describe("--json", () => {
    it("should list packages as json objects", async () => {
      const testDir = await initFixture("basic");
      await lernaLs(testDir)("--json", "-a");

      // Output should be a parseable string
      const jsonOutput = JSON.parse(output.logged());
      expect(jsonOutput).toEqual([
        {
          location: expect.stringContaining("package-1"),
          name: "package-1",
          private: false,
          version: "1.0.0",
        },
        {
          location: expect.stringContaining("package-2"),
          name: "package-2",
          private: false,
          version: "1.0.0",
        },
        {
          location: expect.stringContaining("package-3"),
          name: "package-3",
          private: false,
          version: "1.0.0",
        },
        {
          location: expect.stringContaining("package-4"),
          name: "package-4",
          private: false,
          version: "1.0.0",
        },
        {
          location: expect.stringContaining("package-5"),
          name: "package-5",
          private: true,
          version: "1.0.0",
        },
      ]);
    });
  });

  describe("in a Yarn workspace", () => {
    it("should use package.json/workspaces setting", async () => {
      const testDir = await initFixture("yarn-workspaces");
      await lernaLs(testDir)();
      expect(output.logged()).toMatchInlineSnapshot(`
package-1
package-2
`);
    });
  });

  describe("with terribly complicated dependency cycles", () => {
    // for reference: 1->2, 1->3, 1->4, 2->4, 2->5, 3->4, 3->6, 4->1, 4->4,  5->4, 6->4, 7->4
    // We design the package tree in a very specific way. We want to test several different things
    // * A package depending on itself isn't added twice (package 4)
    // * A package being added twice in the same stage of the expansion isn't added twice (package 4)
    // * A package that has already been processed wont get added twice (package 1)
    it("should list all packages with no repeats", async () => {
      const testDir = await initFixture("cycles-and-repeated-deps");
      await lernaLs(testDir)("--scope", "package-1", "--include-filtered-dependencies");

      // should follow all transitive deps and pass all packages except 7 with no repeats
      expect(output.logged()).toMatchInlineSnapshot(`
package-1
package-2
package-3
package-4
package-5
package-6
`);
    });
  });

  describe("with fancy 'packages' configuration", () => {
    it("lists globstar-nested packages", async () => {
      const testDir = await initFixture("globstar");
      await lernaLs(testDir)();
      expect(output.logged()).toMatchInlineSnapshot(`
globstar
package-2
package-4
package-1
package-3
package-5
`);
    });

    it("lists packages under explicitly configured node_modules directories", async () => {
      const testDir = await initFixture("explicit-node-modules");
      await lernaLs(testDir)();
      expect(output.logged()).toMatchInlineSnapshot(`
alle-pattern-root
package-1
package-2
package-3
package-4
@scoped/package-5
`);
    });

    it("throws an error when globstars and explicit node_modules configs are mixed", async () => {
      expect.assertions(1);

      const testDir = await initFixture("mixed-globstar");

      try {
        await lernaLs(testDir)();
      } catch (err) {
        expect(err.message).toMatch("An explicit node_modules package path does not allow globstars");
      }
    });
  });

  describe("filtering", () => {
    let testDir;

    beforeAll(async () => {
      testDir = await initFixture("filtering");
    });

    it("includes all packages when --scope is omitted", async () => {
      await lernaLs(testDir)();
      expect(output.logged()).toMatchInlineSnapshot(`
package-3
package-4
package-a-1
package-a-2
`);
    });

    it("includes packages when --scope is a package name", async () => {
      await lernaLs(testDir)("--scope", "package-3");
      expect(output.logged()).toMatchInlineSnapshot(`package-3`);
    });

    it("excludes packages when --ignore is a package name", async () => {
      await lernaLs(testDir)("--ignore", "package-3");
      expect(output.logged()).toMatchInlineSnapshot(`
package-4
package-a-1
package-a-2
`);
    });

    it("includes packages when --scope is a glob", async () => {
      await lernaLs(testDir)("--scope", "package-a-*");
      expect(output.logged()).toMatchInlineSnapshot(`
package-a-1
package-a-2
`);
    });

    it("excludes packages when --ignore is a glob", async () => {
      await lernaLs(testDir)("--ignore", "package-@(2|3|4)");
      expect(output.logged()).toMatchInlineSnapshot(`
package-a-1
package-a-2
`);
    });

    it("excludes packages when --ignore is a brace-expanded list", async () => {
      await lernaLs(testDir)("--ignore", "package-{3,4}");
      expect(output.logged()).toMatchInlineSnapshot(`
package-a-1
package-a-2
`);
    });

    it("filters packages when both --scope and --ignore are passed", async () => {
      await lernaLs(testDir)("--scope", "package-a-*", "--ignore", "package-a-2");
      expect(output.logged()).toMatchInlineSnapshot(`package-a-1`);
    });

    it("throws an error when --scope is lacking an argument", async () => {
      try {
        await lernaLs(testDir)("--scope");
      } catch (err) {
        expect(err).toHaveProperty("message", expect.stringContaining("Not enough arguments"));
      }
    });

    it("throws an error when --scope glob excludes all packages", async () => {
      expect.assertions(1);

      try {
        await lernaLs(testDir)("--scope", "no-package-*");
      } catch (err) {
        expect(err.message).toBe("No packages remain after filtering [ 'no-package-*' ]");
      }
    });

    it("throws an error when --ignore glob excludes all packages", async () => {
      expect.assertions(1);

      try {
        await lernaLs(testDir)("--ignore", "package-*");
      } catch (err) {
        expect(err.message).toBe("No packages remain after filtering [ '**', '!package-*' ]");
      }
    });

    it("throws an error when --scope and --ignore globs exclude all packages", async () => {
      expect.assertions(1);

      try {
        await lernaLs(testDir)("--scope", "package-a-*", "--ignore", "package-a-@(1|2)");
      } catch (err) {
        expect(err.message).toBe("No packages remain after filtering [ 'package-a-*', '!package-a-@(1|2)' ]");
      }
    });
  });
});


Importer.CSV = class ImporterCSV extends Importer.Base {

constructor(name, descriptionI18N, fileTypeRegex) {

this.logger.debug('Constructed a new CSV Importer.');

keep keep keep replace replace keep keep keep

constructor(name, descriptionI18N, mimeType) {

import toastr from 'toastr'
Template.adminImportPrepare.helpers
	isAdmin: ->
		return RocketChat.authz.hasRole(Meteor.userId(), 'admin')
	importer: ->
		importerKey = FlowRouter.getParam('importer')
		importer = undefined
		_.each Importer.Importers, (i, key) ->
			i.key = key
			if key == importerKey
				importer = i

		return importer
	isLoaded: ->
		return Template.instance().loaded.get()
	isPreparing: ->
		return Template.instance().preparing.get()
	users: ->
		return Template.instance().users.get()
	channels: ->
		return Template.instance().channels.get()

Template.adminImportPrepare.events
	'change .import-file-input': (event, template) ->
		importer = @
		return if not importer.key

		e = event.originalEvent or event
		files = e.target.files
		if not files or files.length is 0
			files = e.dataTransfer?.files or []

		for blob in files
			template.preparing.set true

			reader = new FileReader()
			reader.readAsDataURL(blob)
			reader.onloadend = ->
				Meteor.call 'prepareImport', importer.key, reader.result, blob.type, blob.name, (error, data) ->
					if error
						console.warn 'Errored out preparing the import:', error
						handleError(error)
						return

					if !data
						console.warn 'The importer ' + importer.key + ' is not set up correctly, as it did not return any data.'
						toastr.error t('Importer_not_setup')
						template.preparing.set false
						return

					if data.step
						console.warn 'Invalid file, contains `data.step`.', data
						toastr.error t('Invalid_Export_File', importer.key)
						template.preparing.set false
						return

					template.users.set data.users
					template.channels.set data.channels
					template.loaded.set true
					template.preparing.set false

	'click .button.start': (event, template) ->
		btn = this
		$(btn).prop "disabled", true
		importer = @
		for user in template.users.get()
			user.do_import = $("[name=#{user.user_id}]").is(':checked')

		for channel in template.channels.get()
			channel.do_import = $("[name=#{channel.channel_id}]").is(':checked')

		Meteor.call 'startImport', FlowRouter.getParam('importer'), { users: template.users.get(), channels: template.channels.get() }, (error, data) ->
			if error
				console.warn 'Error on starting the import:', error
				return handleError(error)
			else
				FlowRouter.go '/admin/import/progress/' + FlowRouter.getParam('importer')

	'click .button.restart': (event, template) ->
		Meteor.call 'restartImport', FlowRouter.getParam('importer'), (error, data) ->
			if error
				console.warn 'Error while restarting the import:', error
				handleError(error)
				return

			template.users.set []
			template.channels.set []
			template.loaded.set false

	'click .button.uncheck-deleted-users': (event, template) ->
		for user in template.users.get() when user.is_deleted
			$("[name=#{user.user_id}]").attr('checked', false);

	'click .button.uncheck-archived-channels': (event, template) ->
		for channel in template.channels.get() when channel.is_archived
			$("[name=#{channel.channel_id}]").attr('checked', false);

Template.adminImportPrepare.onCreated ->
	instance = @
	@preparing = new ReactiveVar true
	@loaded = new ReactiveVar false
	@users = new ReactiveVar []
	@channels = new ReactiveVar []

	loadSelection = (progress) ->
		if progress?.step
			switch progress.step
				#When the import is running, take the user to the progress page
				when 'importer_importing_started', 'importer_importing_users', 'importer_importing_channels', 'importer_importing_messages', 'importer_finishing'
					FlowRouter.go '/admin/import/progress/' + FlowRouter.getParam('importer')
				# when the import is done, restart it (new instance)
				when 'importer_user_selection'
					Meteor.call 'getSelectionData', FlowRouter.getParam('importer'), (error, data) ->
						if error
							handleError error
						instance.users.set data.users
						instance.channels.set data.channels
						instance.loaded.set true
						instance.preparing.set false
				when 'importer_new'
					instance.preparing.set false
				else
					Meteor.call 'restartImport', FlowRouter.getParam('importer'), (error, progress) ->
						if error
							handleError(error)
						loadSelection(progress)
		else
			console.warn 'Invalid progress information.', progress

	# Load the initial progress to determine what we need to do
	if FlowRouter.getParam('importer')
		Meteor.call 'getImportProgress', FlowRouter.getParam('importer'), (error, progress) ->
			if error
				console.warn 'Error while getting the import progress:', error
				handleError error
				return

			# if the progress isnt defined, that means there currently isn't an instance
			# of the importer, so we need to create it
			if progress is undefined
				Meteor.call 'setupImporter', FlowRouter.getParam('importer'), (err, data) ->
					if err
						handleError(err)
					instance.preparing.set false
					loadSelection(data)
			else
				# Otherwise, we might need to do something based upon the current step
				# of the import
				loadSelection(progress)
	else
		FlowRouter.go '/admin/import'


/* globals RocketChatFileEmojiCustomInstance */
Meteor.methods({
	uploadEmojiCustom(binaryContent, contentType, emojiData) {
		if (!RocketChat.authz.hasPermission(this.userId, 'manage-emoji')) {
			throw new Meteor.Error('not_authorized');
		}

		//delete aliases for notification purposes. here, it is a string rather than an array
		delete emojiData.aliases;
		let file = new Buffer(binaryContent, 'binary');

		let rs = RocketChatFile.bufferToStream(file);
		RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${emojiData.name}.${emojiData.extension}`));
		let ws = RocketChatFileEmojiCustomInstance.createWriteStream(encodeURIComponent(`${emojiData.name}.${emojiData.extension}`), contentType);
		ws.on('end', Meteor.bindEnvironment(() =>
			Meteor.setTimeout(() => RocketChat.Notifications.notifyAll('updateEmojiCustom', {emojiData})
			, 500)
		));

		rs.pipe(ws);
	}
});


This directory and the files immediately inside it are automatically generated
when you change this package's NPM dependencies. Commit the files in this
directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
so that others run the same versions of sub-dependencies.

You should NOT check in the node_modules directory that Meteor automatically
creates; if you are using git, the .gitignore file tells git to ignore it.


/* globals UserPresence, fireGlobalEvent, isRtl */

import moment from 'moment';
import toastr from 'toastr';

if (window.DISABLE_ANIMATION) {
	toastr.options.timeOut = 1;
	toastr.options.showDuration = 0;
	toastr.options.hideDuration = 0;
	toastr.options.extendedTimeOut = 0;
}

Meteor.startup(function() {
	TimeSync.loggingEnabled = false;

	UserPresence.awayTime = 300000;
	UserPresence.start();
	Meteor.subscribe('activeUsers');

	Session.setDefault('AvatarRandom', 0);

	window.lastMessageWindow = {};
	window.lastMessageWindowHistory = {};

	TAPi18n.conf.i18n_files_route = Meteor._relativeToSiteRootUrl('/tap-i18n');

	const defaultAppLanguage = function() {
		let lng = window.navigator.userLanguage || window.navigator.language || 'en';
		// Fix browsers having all-lowercase language settings eg. pt-br, en-us
		const re = /([a-z]{2}-)([a-z]{2})/;
		if (re.test(lng)) {
			lng = lng.replace(re, (match, ...parts) => {
				return parts[0] + parts[1].toUpperCase();
			});
		}
		return lng;
	};

	window.defaultUserLanguage = function() {
		return RocketChat.settings.get('Language') || defaultAppLanguage();
	};

	const loadedLanguages = [];

	window.setLanguage = function(language) {
		if (!language) {
			return;
		}

		if (loadedLanguages.indexOf(language) > -1) {
			return;
		}

		loadedLanguages.push(language);

		if (isRtl(language)) {
			$('html').addClass('rtl');
		} else {
			$('html').removeClass('rtl');
		}

		language = language.split('-').shift();
		TAPi18n.setLanguage(language);

		language = language.toLowerCase();
		if (language !== 'en') {
			Meteor.call('loadLocale', language, (err, localeFn) => {
				Function(localeFn).call({moment: moment});
				moment.locale(language);
			});
		}
	};

	Meteor.subscribe('userData', function() {
		const userLanguage = Meteor.user() ? Meteor.user().language : window.defaultUserLanguage();

		if (localStorage.getItem('userLanguage') !== userLanguage) {
			localStorage.setItem('userLanguage', userLanguage);
		}

		window.setLanguage(userLanguage);

		let status = undefined;
		Tracker.autorun(function() {
			if (!Meteor.userId()) {
				return;
			}

			if (Meteor.user() && Meteor.user().status !== status) {
				status = Meteor.user().status;
				fireGlobalEvent('status-changed', status);
			}
		});
	});
});