diff --git a/package.json b/package.json index 666000ae34..70398b3916 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "fs-admin": "0.19.0", "fs-plus": "^3.1.1", "fstream": "1.0.12", - "fuzzy-finder": "https://codeload.github.com/atom/fuzzy-finder/legacy.tar.gz/refs/tags/v1.14.3", + "fuzzy-finder": "file:packages/fuzzy-finder", "git-diff": "file:packages/git-diff", "git-utils": "5.7.1", "github": "https://codeload.github.com/pulsar-edit/github/tar.gz/refs/tags/v0.36.15-pretranspiled", @@ -204,7 +204,7 @@ "encoding-selector": "file:./packages/encoding-selector", "exception-reporting": "file:./packages/exception-reporting", "find-and-replace": "file:./packages/find-and-replace", - "fuzzy-finder": "1.14.3", + "fuzzy-finder": "file:packages/fuzzy-finder", "github": "0.36.14", "git-diff": "file:./packages/git-diff", "go-to-line": "file:./packages/go-to-line", diff --git a/packages/README.md b/packages/README.md index df27d4052c..9677d61cae 100644 --- a/packages/README.md +++ b/packages/README.md @@ -32,7 +32,7 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate | **encoding-selector** | [`./encoding-selector`](./encoding-selector) | | | **exception-reporting** | [`./exception-reporting`](./exception-reporting) | | | **find-and-replace** | [`./find-and-replace`][find-and-replace] | | -| **fuzzy-finder** | [`pulsar-edit/fuzzy-finder`][fuzzy-finder] | | +| **fuzzy-finder** | [`./fuzzy-finder`][fuzzy-finder] | | | **github** | [`pulsar-edit/github`][github] | | | **git-diff** | [`./git-diff`](./git-diff) | | | **go-to-line** | [`./go-to-line`](./go-to-line) | | diff --git a/packages/fuzzy-finder/.gitignore b/packages/fuzzy-finder/.gitignore new file mode 100644 index 0000000000..3c3629e647 --- /dev/null +++ b/packages/fuzzy-finder/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/fuzzy-finder/CONTRIBUTING.md b/packages/fuzzy-finder/CONTRIBUTING.md new file mode 100644 index 0000000000..9c8ac3e5b5 --- /dev/null +++ b/packages/fuzzy-finder/CONTRIBUTING.md @@ -0,0 +1 @@ +[See how you can contribute](https://github.com/pulsar-edit/.github/blob/main/CONTRIBUTING.md) diff --git a/packages/fuzzy-finder/LICENSE.md b/packages/fuzzy-finder/LICENSE.md new file mode 100644 index 0000000000..4d231b4563 --- /dev/null +++ b/packages/fuzzy-finder/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/fuzzy-finder/README.md b/packages/fuzzy-finder/README.md new file mode 100644 index 0000000000..85191752e1 --- /dev/null +++ b/packages/fuzzy-finder/README.md @@ -0,0 +1,22 @@ +# Fuzzy Finder package + +Quickly find and open files using cmd-t. + + * cmd-t or cmd-p to open the file finder + * cmd-b to open the list of open buffers + * cmd-shift-b to open the list of Git modified and untracked files + +When opening a file, you can control the behavior. + + * enter defaults to opening the selected file without leaving the current pane + * shift-enter defaults to switching to another pane if the file is already open there + * cmd-k right (or any other directional arrow) will open the highlighted file in a new pane on the side indicated by the arrow + * Adding `:` to the end of your search will go directly to the line number you specify, or the last line if the number is larger + +Turning on the "Search All Panes" setting reverses the behavior of enter and shift-enter so enter opens the file in any pane and shift-enter creates a new tab in the current pane. + +This package uses both the `core.ignoredNames` and `fuzzy-finder.ignoredNames` config settings to filter out files and folders that will not be shown. Both of those config settings are interpreted as arrays of [minimatch](https://github.com/isaacs/minimatch) glob patterns. + +This package also will also not show Git ignored files when the `core.excludeVcsIgnoredPaths` is enabled. + +![](https://f.cloud.github.com/assets/671378/2241456/100db6b8-9cd3-11e3-9b3a-569c6b50cc60.png) diff --git a/packages/fuzzy-finder/docs/events.md b/packages/fuzzy-finder/docs/events.md new file mode 100644 index 0000000000..cbd75be3cf --- /dev/null +++ b/packages/fuzzy-finder/docs/events.md @@ -0,0 +1,44 @@ +# Events specification + +This document specifies all the data (along with the format) which gets sent from the Fuzzy Finder package to the GitHub analytics pipeline. This document follows the same format and nomenclature as the [Atom Core Events spec](https://github.com/atom/metrics/blob/master/docs/events.md). + +## Counters + +| counter name | description | +|-------|-------| +| `show-enable-prompt` | Number of times the prompt to enable fast mode is shown | +| `click-enable-prompt` | Number of clicks on the "enable fast mode" prompt | +| `confirm-enable-prompt` | Number of confirmations on the "enable fast mode" notification | +| `cancel-enable-prompt` | Number of cancels on the "enable fast mode" notification | +| `show-disable-prompt` | Number of times the prompt to disable fast mode is shown | +| `click-disable-prompt` | Number of clicks on the "disable fast mode" prompt | +| `confirm-disable-prompt` | Number of confirmations on the "disable fast mode" notification | +| `cancel-disable-prompt` | Number of cancels on the "disable fast mode" notification | + +## Timing events + +#### Time to crawl the project + +* **eventType**: `fuzzy-finder-v1` +* **metadata** + + | field | value | + |-------|-------| + | `ec` | `time-to-crawl` + | `el` | Crawler type (`ripgrep` or `fs`) + | `ev` | Number of crawled files + +#### Time to filter results + +* **eventType**: `fuzzy-finder-v1` +* **metadata** + + | field | value | + |-------|-------| + | `ec` | `time-to-filter` + | `el` | Scoring system (`alternate` or `fast`) + | `ev` | Number of items in the list + +## Standard events + +Currently the Fuzzy Finder does not log any standard events. diff --git a/packages/fuzzy-finder/keymaps/fuzzy-finder.cson b/packages/fuzzy-finder/keymaps/fuzzy-finder.cson new file mode 100644 index 0000000000..e0f627b093 --- /dev/null +++ b/packages/fuzzy-finder/keymaps/fuzzy-finder.cson @@ -0,0 +1,20 @@ +'.platform-darwin': + 'cmd-t': 'fuzzy-finder:toggle-file-finder' + 'cmd-p': 'fuzzy-finder:toggle-file-finder' + 'cmd-b': 'fuzzy-finder:toggle-buffer-finder' + 'cmd-B': 'fuzzy-finder:toggle-git-status-finder' + +'.platform-win32': + 'ctrl-t': 'fuzzy-finder:toggle-file-finder' + 'ctrl-p': 'fuzzy-finder:toggle-file-finder' + 'ctrl-b': 'fuzzy-finder:toggle-buffer-finder' + 'ctrl-B': 'fuzzy-finder:toggle-git-status-finder' + +'.platform-linux': + 'ctrl-t': 'fuzzy-finder:toggle-file-finder' + 'ctrl-p': 'fuzzy-finder:toggle-file-finder' + 'ctrl-b': 'fuzzy-finder:toggle-buffer-finder' + 'ctrl-B': 'fuzzy-finder:toggle-git-status-finder' + +'.fuzzy-finder atom-text-editor[mini]': + 'shift-enter': 'fuzzy-finder:invert-confirm' diff --git a/packages/fuzzy-finder/lib/buffer-view.js b/packages/fuzzy-finder/lib/buffer-view.js new file mode 100644 index 0000000000..85f8c0f556 --- /dev/null +++ b/packages/fuzzy-finder/lib/buffer-view.js @@ -0,0 +1,89 @@ +const FuzzyFinderView = require('./fuzzy-finder-view') +const path = require('path') + +module.exports = +class BufferView extends FuzzyFinderView { + setTeletypeService (teletypeService) { + this.teletypeService = teletypeService + } + + getEmptyMessage () { + return 'No open editors' + } + + async toggle () { + if (this.panel && this.panel.isVisible()) { + this.cancel() + } else { + const items = this.sortItems(await this.buildItems()) + if (items.length > 0) { + this.show() + await this.setItems(items) + } + } + } + + async buildItems () { + const itemsByURI = new Map() + + const remoteEditorsByURI = await this.getRemoteEditorsByURI() + const projectHasMultipleDirectories = atom.project.getDirectories().length > 1 + const localEditors = atom.workspace.getTextEditors() + for (let i = 0; i < localEditors.length; i++) { + const localEditor = localEditors[i] + const localEditorURI = localEditor.getURI() + const localEditorPath = localEditor.getPath() + if (!localEditorURI) continue + if (itemsByURI.has(localEditorURI)) continue + + const item = {uri: localEditorURI} + + const remoteEditor = remoteEditorsByURI.get(localEditorURI) + if (remoteEditor) { + item.filePath = remoteEditor.path + item.label = `@${remoteEditor.hostGitHubUsername}: ${remoteEditor.path}` + item.ownerGitHubUsername = remoteEditor.hostGitHubUsername + } else { + const [projectRootPath, projectRelativePath] = atom.project.relativizePath(localEditorPath) + item.filePath = localEditorPath + item.label = + projectRootPath && projectHasMultipleDirectories + ? path.join(path.basename(projectRootPath), projectRelativePath) + : projectRelativePath + } + + if (localEditor.lastOpened != null) { + item.lastOpened = localEditor.lastOpened + } + + itemsByURI.set(localEditorURI, item) + } + + return Array.from(itemsByURI.values()) + } + + sortItems (items) { + const activeEditor = atom.workspace.getActiveTextEditor() + const activeEditorURI = activeEditor ? activeEditor.getURI() : null + items.sort((a, b) => { + if (a.uri === activeEditorURI) { + return 1 + } else if (b.uri === activeEditorURI) { + return -1 + } else { + return (b.lastOpened || 1) - (a.lastOpened || 1) + } + }) + return items + } + + async getRemoteEditorsByURI () { + const remoteEditorsByURI = new Map() + const remoteEditors = this.teletypeService ? await this.teletypeService.getRemoteEditors() : [] + for (var i = 0; i < remoteEditors.length; i++) { + const remoteEditor = remoteEditors[i] + remoteEditorsByURI.set(remoteEditor.uri, remoteEditor) + } + return remoteEditorsByURI + } +} diff --git a/packages/fuzzy-finder/lib/default-file-icons.js b/packages/fuzzy-finder/lib/default-file-icons.js new file mode 100644 index 0000000000..96c7a8d34a --- /dev/null +++ b/packages/fuzzy-finder/lib/default-file-icons.js @@ -0,0 +1,26 @@ +const fs = require('fs-plus') +const path = require('path') + +class DefaultFileIcons { + iconClassForPath (filePath) { + const extension = path.extname(filePath) + + if (fs.isSymbolicLinkSync(filePath)) { + return 'icon-file-symlink-file' + } else if (fs.isReadmePath(filePath)) { + return 'icon-book' + } else if (fs.isCompressedExtension(extension)) { + return 'icon-file-zip' + } else if (fs.isImageExtension(extension)) { + return 'icon-file-media' + } else if (fs.isPdfExtension(extension)) { + return 'icon-file-pdf' + } else if (fs.isBinaryExtension(extension)) { + return 'icon-file-binary' + } else { + return 'icon-file-text' + } + } +} + +module.exports = new DefaultFileIcons() diff --git a/packages/fuzzy-finder/lib/fuzzy-finder-view.js b/packages/fuzzy-finder/lib/fuzzy-finder-view.js new file mode 100644 index 0000000000..d34d80ac68 --- /dev/null +++ b/packages/fuzzy-finder/lib/fuzzy-finder-view.js @@ -0,0 +1,437 @@ +const {Point, CompositeDisposable} = require('atom') +const fs = require('fs') +const NativeFuzzy = require('@pulsar-edit/fuzzy-native') + +const path = require('path') +const SelectListView = require('atom-select-list') + +const {repositoryForPath} = require('./helpers') +const getIconServices = require('./get-icon-services') + +const MAX_RESULTS = 10 + +module.exports = class FuzzyFinderView { + constructor (metricsReporter) { + this.previousQueryWasLineJump = false + this.items = [] + this.metricsReporter = metricsReporter + this.filterFn = this.filterFn.bind(this) + + this.selectListView = new SelectListView({ + items: this.items, + maxResults: MAX_RESULTS, + emptyMessage: this.getEmptyMessage(), + filterKeyForItem: (item) => item.label, + filterQuery: (query) => { + const colon = query.indexOf(':') + if (colon !== -1) { + query = query.slice(0, colon) + } + // Normalize to backslashes on Windows + if (process.platform === 'win32') { + query = query.replace(/\//g, '\\') + } + + return query + }, + didCancelSelection: () => { this.cancel() }, + didConfirmSelection: (item) => { + this.confirm(item, {searchAllPanes: atom.config.get('fuzzy-finder.searchAllPanes')}) + }, + didConfirmEmptySelection: () => { + this.confirm() + }, + didChangeQuery: () => { + if (this.iconDisposables) { + this.iconDisposables.dispose() + this.iconDisposables = null + } + const isLineJump = this.isQueryALineJump() + if (isLineJump) { + this.previousQueryWasLineJump = true + const query = this.selectListView.getQuery() + let emptyMessage = null + let errorMessage = null + if (/^:\d+:\d*\D/.test(query)) { + errorMessage = 'Invalid column number' + } else if (/^:\d+:/.test(query)) { + emptyMessage = 'Jump to line and column in active editor' + } else if (/^:\d*\D/.test(query)) { + errorMessage = 'Invalid line number' + } else { + emptyMessage = 'Jump to line in active editor' + } + + this.selectListView.update({ + items: [], + emptyMessage: emptyMessage, + errorMessage: errorMessage + }) + } else if (this.previousQueryWasLineJump) { + this.previousQueryWasLineJump = false + this.selectListView.update({ + items: this.items, + emptyMessage: this.getEmptyMessage(), + errorMessage: null + }) + } + }, + elementForItem: ({filePath, label, ownerGitHubUsername}) => { + const filterQuery = this.selectListView.getFilterQuery() + + this.nativeFuzzyForResults.setCandidates([0], [label]) + const items = this.nativeFuzzyForResults.match( + filterQuery, + {maxResults: 1, recordMatchIndexes: true} + ) + const matches = items.length ? items[0].matchIndexes : [] + const repository = repositoryForPath(filePath) + + return new FuzzyFinderItem({ + filePath, + label, + ownerGitHubUsername, + filterQuery, + matches, + repository + }).element + } + }) + this.selectListView.element.classList.add('fuzzy-finder') + + const splitLeft = () => { this.splitOpenPath((pane) => pane.splitLeft.bind(pane)) } + const splitRight = () => { this.splitOpenPath((pane) => pane.splitRight.bind(pane)) } + const splitUp = () => { this.splitOpenPath((pane) => pane.splitUp.bind(pane)) } + const splitDown = () => { this.splitOpenPath((pane) => pane.splitDown.bind(pane)) } + atom.commands.add(this.selectListView.element, { + 'pane:split-left': splitLeft, + 'pane:split-left-and-copy-active-item': splitLeft, + 'pane:split-left-and-move-active-item': splitLeft, + 'pane:split-right': splitRight, + 'pane:split-right-and-copy-active-item': splitRight, + 'pane:split-right-and-move-active-item': splitRight, + 'pane:split-up': splitUp, + 'pane:split-up-and-copy-active-item': splitUp, + 'pane:split-up-and-move-active-item': splitUp, + 'pane:split-down': splitDown, + 'pane:split-down-and-copy-active-item': splitDown, + 'pane:split-down-and-move-active-item': splitDown, + 'fuzzy-finder:invert-confirm': () => { + this.confirm( + this.selectListView.getSelectedItem(), + {searchAllPanes: !atom.config.get('fuzzy-finder.searchAllPanes')} + ) + } + }) + + if (!this.nativeFuzzy) { + this.nativeFuzzy = new NativeFuzzy.Matcher( + indexArray(this.items.length), + this.items.map(el => el.label) + ) + // We need a separate instance of the fuzzy finder to calculate the + // matched paths only for the returned results. This speeds up considerably + // the filtering of items. + this.nativeFuzzyForResults = new NativeFuzzy.Matcher([], []) + } + this.selectListView.update({ filter: this.filterFn }) + } + + get element () { + return this.selectListView.element + } + + destroy () { + if (this.panel) { + this.panel.destroy() + } + + return this.selectListView.destroy() + } + + cancel () { + if (atom.config.get('fuzzy-finder.preserveLastSearch')) { + this.selectListView.refs.queryEditor.selectAll() + } else { + this.selectListView.reset() + } + + this.hide() + } + + confirm ({uri} = {}, openOptions) { + if (atom.workspace.getActiveTextEditor() && this.isQueryALineJump()) { + const caretPosition = this.getCaretPosition() + this.cancel() + this.moveToCaretPosition(caretPosition) + } else if (!uri) { + this.cancel() + } else if (fs.lstatSync(uri).isDirectory()) { + this.selectListView.update({errorMessage: 'Selected path is a directory'}) + setTimeout(() => { this.selectListView.update({errorMessage: null}) }, 2000) + } else { + const caretPosition = this.getCaretPosition() + this.cancel() + this.openURI(uri, caretPosition, openOptions) + } + } + + getEditorSelection () { + const editor = atom.workspace.getActiveTextEditor() + if (!editor) { + return + } + const selectedText = editor.getSelectedText() + if (/\n/m.test(selectedText)) { + return + } + return selectedText + } + + prefillQueryFromSelection () { + const selectedText = this.getEditorSelection() + if (selectedText) { + this.selectListView.refs.queryEditor.setText(selectedText) + const textLength = selectedText.length + this.selectListView.refs.queryEditor.setSelectedBufferRange([[0, 0], [0, textLength]]) + } + } + + show () { + this.previouslyFocusedElement = document.activeElement + if (!this.panel) { + this.panel = atom.workspace.addModalPanel({item: this}) + } + this.panel.show() + if (atom.config.get('fuzzy-finder.prefillFromSelection') === true) { + this.prefillQueryFromSelection() + } + this.selectListView.focus() + } + + hide () { + if (this.panel) { + this.panel.hide() + } + + if (this.previouslyFocusedElement) { + this.previouslyFocusedElement.focus() + this.previouslyFocusedElement = null + } + } + + async openURI (uri, caretPosition, openOptions) { + if (uri) { + await atom.workspace.open(uri, openOptions) + this.moveToCaretPosition(caretPosition) + } + } + + moveToCaretPosition (caretPosition) { + const editor = atom.workspace.getActiveTextEditor() + if (editor && caretPosition.row >= 0) { + editor.unfoldBufferRow(caretPosition.row) + editor.setCursorBufferPosition(caretPosition) + if (caretPosition.column === -1) { + editor.moveToFirstCharacterOfLine() + } + + editor.scrollToBufferPosition(caretPosition, {center: true}) + } + } + + splitOpenPath (splitFn) { + const {uri} = this.selectListView.getSelectedItem() || {} + const caretPosition = this.getCaretPosition() + const editor = atom.workspace.getActiveTextEditor() + const activePane = atom.workspace.getActivePane() + + if (this.isQueryALineJump() && editor) { + this.previouslyFocusedElement = null + splitFn(activePane)({copyActiveItem: true}) + this.moveToCaretPosition(caretPosition) + } else if (!uri) { + return // eslint-disable-line no-useless-return + } else if (activePane) { + this.previouslyFocusedElement = null + splitFn(activePane)() + this.openURI(uri, caretPosition) + } else { + this.previouslyFocusedElement = null + this.openURI(uri, caretPosition) + } + } + + isQueryALineJump () { + return ( + this.selectListView.getFilterQuery().trim() === '' && + this.selectListView.getQuery().includes(':') + ) + } + + getCaretPosition () { + const query = this.selectListView.getQuery() + const firstColon = query.indexOf(':') + const secondColon = query.indexOf(':', firstColon + 1) + let position = new Point(-1, -1) + + if (firstColon !== -1) { + if (secondColon !== -1) { + position.row = parseInt(query.slice(firstColon + 1, secondColon)) - 1 + const column = parseInt(query.slice(secondColon + 1)) + position.column = isNaN(column) ? -1 : column + } else { + position.row = parseInt(query.slice(firstColon + 1)) - 1 + } + } + + return position + } + + setItems (items) { + this.items = items + this.nativeFuzzy.setCandidates( + indexArray(this.items.length), + this.items.map(item => item.label) + ) + + if (this.isQueryALineJump()) { + this.selectListView.update({ + items: [], + infoMessage: null, + loadingMessage: null, + loadingBadge: null + }) + } else { + this.selectListView.update({ + items: this.items, + infoMessage: null, + loadingMessage: null, + loadingBadge: null + }) + } + } + + projectRelativePathsForFilePaths (filePaths) { + // Don't regenerate project relative paths unless the file paths have changed + if (filePaths !== this.filePaths) { + this.filePaths = filePaths + this.projectRelativePaths = this.filePaths.map( + (filePath) => this.convertPathToSelectViewObject(filePath) + ) + } + + return this.projectRelativePaths + } + + convertPathToSelectViewObject (filePath) { + const projectHasMultipleDirectories = atom.project.getDirectories().length > 1 + + const [rootPath, projectRelativePath] = atom.project.relativizePath(filePath) + const label = + rootPath && projectHasMultipleDirectories + ? path.join(path.basename(rootPath), projectRelativePath) + : projectRelativePath + + return {uri: filePath, filePath, label} + } + + filterFn(items, query) { + if (!query) return items + return this.nativeFuzzy.match(query, {maxResults: MAX_RESULTS}) + .map(({id}) => this.items[id]) + } +} + +function highlight (path, matches, offsetIndex) { + let lastIndex = 0 + let matchedChars = [] + const fragment = document.createDocumentFragment() + for (let matchIndex of matches) { + matchIndex -= offsetIndex + // If marking up the basename, omit path matches + if (matchIndex < 0) { + continue + } + const unmatched = path.substring(lastIndex, matchIndex) + if (unmatched) { + if (matchedChars.length > 0) { + const span = document.createElement('span') + span.classList.add('character-match') + span.textContent = matchedChars.join('') + fragment.appendChild(span) + matchedChars = [] + } + + fragment.appendChild(document.createTextNode(unmatched)) + } + + matchedChars.push(path[matchIndex]) + lastIndex = matchIndex + 1 + } + + if (matchedChars.length > 0) { + const span = document.createElement('span') + span.classList.add('character-match') + span.textContent = matchedChars.join('') + fragment.appendChild(span) + } + + // Remaining characters are plain text + fragment.appendChild(document.createTextNode(path.substring(lastIndex))) + return fragment +} + +function indexArray (length) { + const array = [] + for (let i = 0; i < length; i++) { + array[i] = i + } + return array +} + +class FuzzyFinderItem { + constructor ({filePath, label, ownerGitHubUsername, filterQuery, matches, repository}) { + this.filePath = filePath + this.label = label + this.element = document.createElement('li') + this.element.className = 'FuzzyFinderResult' + + if (repository) { + const status = repository.getCachedPathStatus(filePath) + if (repository.isStatusNew(status)) { + const div = document.createElement('div') + div.classList.add('status', 'status-added', 'icon', 'icon-diff-added') + this.element.appendChild(div) + } else if (repository.isStatusModified(status)) { + const div = document.createElement('div') + div.classList.add('status', 'status-modified', 'icon', 'icon-diff-modified') + this.element.appendChild(div) + } + } + + const fileBasename = path.basename(filePath) + const baseOffset = label.length - fileBasename.length + this.primaryLine = document.createElement('div') + this.primaryLine.dataset.name = fileBasename + this.primaryLine.dataset.path = label + this.primaryLine.classList.add('primary-line', 'file', 'icon') + this.primaryLine.appendChild(highlight(fileBasename, matches, baseOffset)) + this.element.appendChild(this.primaryLine) + + this.secondaryLine = document.createElement('div') + this.secondaryLine.classList.add('secondary-line', 'path', 'no-icon') + this.secondaryLine.appendChild(highlight(label, matches, 0)) + this.element.appendChild(this.secondaryLine) + + if (ownerGitHubUsername) { + this.element.classList.add('has-avatar') + const avatarElement = document.createElement('img') + avatarElement.className = 'FuzzyFinderResult-avatar' + avatarElement.src = `https://avatars.githubusercontent.com/${ownerGitHubUsername}?size=56` + this.element.appendChild(avatarElement) + } + + getIconServices().updateIcon(this) + } +} diff --git a/packages/fuzzy-finder/lib/get-icon-services.js b/packages/fuzzy-finder/lib/get-icon-services.js new file mode 100644 index 0000000000..d978189b85 --- /dev/null +++ b/packages/fuzzy-finder/lib/get-icon-services.js @@ -0,0 +1,63 @@ +const DefaultFileIcons = require('./default-file-icons') +const {Emitter, CompositeDisposable} = require('atom') + +let iconServices +module.exports = function () { + if (!iconServices) iconServices = new IconServices() + return iconServices +} + +class IconServices { + constructor () { + this.emitter = new Emitter() + this.elementIcons = null + this.elementIconDisposables = new CompositeDisposable() + this.fileIcons = DefaultFileIcons + } + + onDidChange (callback) { + return this.emitter.on('did-change', callback) + } + + resetElementIcons () { + this.setElementIcons(null) + } + + resetFileIcons () { + this.setFileIcons(DefaultFileIcons) + } + + setElementIcons (service) { + if (service !== this.elementIcons) { + if (this.elementIconDisposables != null) { + this.elementIconDisposables.dispose() + } + if (service) { this.elementIconDisposables = new CompositeDisposable() } + this.elementIcons = service + return this.emitter.emit('did-change') + } + } + + setFileIcons (service) { + if (service !== this.fileIcons) { + this.fileIcons = service + return this.emitter.emit('did-change') + } + } + + updateIcon (view) { + if (this.elementIcons) { + const disposable = this.elementIcons(view.primaryLine, view.filePath) + this.elementIconDisposables.add(disposable) + } else { + let classList = [] + const iconClasses = this.fileIcons.iconClassForPath(view.filePath, 'fuzzy-finder') + if (Array.isArray(iconClasses)) { + classList = iconClasses + } else if (iconClasses) { + classList = iconClasses.toString().split(/\s+/g) + } + view.primaryLine.classList.add(...classList) + } + } +} diff --git a/packages/fuzzy-finder/lib/git-status-view.js b/packages/fuzzy-finder/lib/git-status-view.js new file mode 100644 index 0000000000..8876d17710 --- /dev/null +++ b/packages/fuzzy-finder/lib/git-status-view.js @@ -0,0 +1,32 @@ +const fs = require('fs') +const path = require('path') + +const FuzzyFinderView = require('./fuzzy-finder-view') + +module.exports = +class GitStatusView extends FuzzyFinderView { + async toggle () { + if (this.panel && this.panel.isVisible()) { + this.cancel() + } else if (atom.project.getRepositories().some((repo) => repo)) { + const paths = [] + for (const repo of atom.project.getRepositories()) { + if (repo) { + const workingDirectory = repo.getWorkingDirectory() + for (let filePath in repo.statuses) { + filePath = path.join(workingDirectory, filePath) + if (fs.lstatSync(filePath).isFile()) { + paths.push(filePath) + } + } + } + } + this.show() + await this.setItems(this.projectRelativePathsForFilePaths(paths)) + } + } + + getEmptyMessage () { + return 'Nothing to commit, working directory clean' + } +} diff --git a/packages/fuzzy-finder/lib/helpers.js b/packages/fuzzy-finder/lib/helpers.js new file mode 100644 index 0000000000..3a1c8744c3 --- /dev/null +++ b/packages/fuzzy-finder/lib/helpers.js @@ -0,0 +1,14 @@ +const path = require('path') + +module.exports = { + repositoryForPath (filePath) { + const paths = atom.project.getPaths() + for (let i = 0; i < paths.length; i++) { + const projectPath = paths[i] + if ((filePath === projectPath) || filePath.startsWith(projectPath + path.sep)) { + return atom.project.getRepositories()[i] + } + } + return null + } +} diff --git a/packages/fuzzy-finder/lib/load-paths-handler.js b/packages/fuzzy-finder/lib/load-paths-handler.js new file mode 100644 index 0000000000..95e72cc76d --- /dev/null +++ b/packages/fuzzy-finder/lib/load-paths-handler.js @@ -0,0 +1,203 @@ +/* global emit */ + +const async = require('async') +const fs = require('fs') +const os = require('os') +const path = require('path') +const {GitRepository} = require('atom') +const {Minimatch} = require('minimatch') +const childProcess = require('child_process') +const { rgPath } = require('vscode-ripgrep') + +const PathsChunkSize = 100 + +// Use the unpacked path if the ripgrep binary is in asar archive. +const realRgPath = rgPath.replace(/\bapp\.asar\b/, 'app.asar.unpacked') + +// Define the maximum number of concurrent crawling processes based on the number of CPUs +// with a maximum value of 8 and minimum of 1. +const MaxConcurrentCrawls = Math.min(Math.max(os.cpus().length - 1, 8), 1) + +const emittedPaths = new Set() + +class PathLoader { + constructor (rootPath, ignoreVcsIgnores, traverseSymlinkDirectories, ignoredNames, useRipGrep) { + this.rootPath = rootPath + this.ignoreVcsIgnores = ignoreVcsIgnores + this.traverseSymlinkDirectories = traverseSymlinkDirectories + this.ignoredNames = ignoredNames + this.useRipGrep = useRipGrep + this.paths = [] + this.inodes = new Set() + this.repo = null + if (ignoreVcsIgnores && !this.useRipGrep) { + const repo = GitRepository.open(this.rootPath, {refreshOnWindowFocus: false}) + if ((repo && repo.relativize(path.join(this.rootPath, 'test'))) === 'test') { + this.repo = repo + } + } + } + + load (done) { + if (this.useRipGrep) { + this.loadFromRipGrep().then(done) + + return + } + + this.loadPath(this.rootPath, true, () => { + this.flushPaths() + if (this.repo != null) this.repo.destroy() + done() + }) + } + + async loadFromRipGrep () { + return new Promise((resolve) => { + const args = ['--files', '--hidden', '--sort', 'path'] + + if (!this.ignoreVcsIgnores) { + args.push('--no-ignore') + } + + if (this.traverseSymlinkDirectories) { + args.push('--follow') + } + + for (let ignoredName of this.ignoredNames) { + args.push('-g', '!' + ignoredName.pattern) + } + + if (this.ignoreVcsIgnores) { + if (!args.includes('!.git')) args.push('-g', '!.git') + if (!args.includes('!.hg')) args.push('-g', '!.hg') + } + + let output = '' + const result = childProcess.spawn(realRgPath, args, {cwd: this.rootPath}) + + result.stdout.on('data', chunk => { + const files = (output + chunk).split('\n') + output = files.pop() + + for (const file of files) { + this.pathLoaded(path.join(this.rootPath, file)) + } + }) + result.stderr.on('data', () => { + // intentionally ignoring errors for now + }) + result.on('close', () => { + this.flushPaths() + resolve() + }) + }) + } + + isIgnored (loadedPath) { + const relativePath = path.relative(this.rootPath, loadedPath) + if (this.repo && this.repo.isPathIgnored(relativePath)) { + return true + } else { + for (let ignoredName of this.ignoredNames) { + if (ignoredName.match(relativePath)) return true + } + } + } + + pathLoaded (loadedPath, done) { + if (!emittedPaths.has(loadedPath)) { + this.paths.push(loadedPath) + emittedPaths.add(loadedPath) + } + + if (this.paths.length === PathsChunkSize) { + this.flushPaths() + } + done && done() + } + + flushPaths () { + emit('load-paths:paths-found', this.paths) + this.paths = [] + } + + loadPath (pathToLoad, root, done) { + if (this.isIgnored(pathToLoad) && !root) return done() + + fs.lstat(pathToLoad, (error, stats) => { + if (error != null) { return done() } + if (stats.isSymbolicLink()) { + fs.stat(pathToLoad, (error, stats) => { + if (error != null) return done() + if (this.inodes.has(stats.ino)) { + return done() + } else { + this.inodes.add(stats.ino) + } + + if (stats.isFile()) { + this.pathLoaded(pathToLoad, done) + } else if (stats.isDirectory()) { + if (this.traverseSymlinkDirectories) { + this.loadFolder(pathToLoad, done) + } else { + done() + } + } else { + done() + } + }) + } else { + this.inodes.add(stats.ino) + if (stats.isDirectory()) { + this.loadFolder(pathToLoad, done) + } else if (stats.isFile()) { + this.pathLoaded(pathToLoad, done) + } else { + done() + } + } + }) + } + + loadFolder (folderPath, done) { + fs.readdir(folderPath, (_, children = []) => { + async.each( + children, + (childName, next) => { + this.loadPath(path.join(folderPath, childName), false, next) + }, + done + ) + }) + } +} + +module.exports = function (rootPaths, followSymlinks, ignoreVcsIgnores, ignores, useRipGrep) { + const ignoredNames = [] + for (let ignore of ignores) { + if (ignore) { + try { + ignoredNames.push(new Minimatch(ignore, {matchBase: true, dot: true})) + } catch (error) { + console.warn(`Error parsing ignore pattern (${ignore}): ${error.message}`) + } + } + } + + async.eachLimit( + rootPaths, + MaxConcurrentCrawls, + (rootPath, next) => + new PathLoader( + rootPath, + ignoreVcsIgnores, + followSymlinks, + ignoredNames, + useRipGrep + ).load(next) + , + this.async() + ) +} diff --git a/packages/fuzzy-finder/lib/main.js b/packages/fuzzy-finder/lib/main.js new file mode 100644 index 0000000000..1a5aa055d1 --- /dev/null +++ b/packages/fuzzy-finder/lib/main.js @@ -0,0 +1,149 @@ +const {CompositeDisposable, Disposable} = require('atom') +const getIconServices = require('./get-icon-services') +const ReporterProxy = require('./reporter-proxy') + +const metricsReporter = new ReporterProxy() + +module.exports = { + activate (state) { + this.active = true + + this.disposables = new CompositeDisposable() + + this.disposables.add(atom.commands.add('atom-workspace', { + 'fuzzy-finder:toggle-file-finder': () => { + this.createProjectView().toggle() + }, + 'fuzzy-finder:toggle-buffer-finder': () => { + this.createBufferView().toggle() + }, + 'fuzzy-finder:toggle-git-status-finder': () => { + this.createGitStatusView().toggle() + } + })) + + process.nextTick(() => this.startLoadPathsTask()) + + for (let editor of atom.workspace.getTextEditors()) { + editor.lastOpened = state[editor.getPath()] + } + + this.disposables.add(atom.workspace.observePanes(pane => { + this.disposables.add(pane.observeActiveItem(item => { + if (item != null) item.lastOpened = Date.now() + })) + })) + }, + + deactivate () { + this.disposables.dispose() + + if (this.projectView != null) { + this.projectView.destroy() + this.projectView = null + } + if (this.bufferView != null) { + this.bufferView.destroy() + this.bufferView = null + } + if (this.gitStatusView != null) { + this.gitStatusView.destroy() + this.gitStatusView = null + } + this.projectPaths = null + this.stopLoadPathsTask() + this.active = false + }, + + consumeElementIcons (service) { + getIconServices().setElementIcons(service) + return new Disposable(() => getIconServices().resetElementIcons()) + }, + + consumeFileIcons (service) { + getIconServices().setFileIcons(service) + return new Disposable(() => getIconServices().resetFileIcons()) + }, + + consumeTeletype (teletypeService) { + this.teletypeService = teletypeService + if (this.bufferView) this.bufferView.setTeletypeService(teletypeService) + if (this.projectView) this.projectView.setTeletypeService(teletypeService) + }, + + consumeMetricsReporter (metricsReporterService) { + metricsReporter.setReporter(metricsReporterService) + + return new Disposable(() => metricsReporter.unsetReporter()) + }, + + serialize () { + const paths = {} + for (let editor of atom.workspace.getTextEditors()) { + const path = editor.getPath() + if (path != null) { paths[path] = editor.lastOpened } + } + return paths + }, + + createProjectView () { + this.stopLoadPathsTask() + + if (this.projectView == null) { + const ProjectView = require('./project-view') + this.projectView = new ProjectView(this.projectPaths, metricsReporter) + this.projectPaths = null + if (this.teletypeService) { + this.projectView.setTeletypeService(this.teletypeService) + } + } + return this.projectView + }, + + createGitStatusView () { + if (this.gitStatusView == null) { + const GitStatusView = require('./git-status-view') + this.gitStatusView = new GitStatusView(metricsReporter) + } + return this.gitStatusView + }, + + createBufferView () { + if (this.bufferView == null) { + const BufferView = require('./buffer-view') + this.bufferView = new BufferView(metricsReporter) + if (this.teletypeService) { + this.bufferView.setTeletypeService(this.teletypeService) + } + } + return this.bufferView + }, + + startLoadPathsTask () { + this.stopLoadPathsTask() + + if (!this.active) return + if (atom.project.getPaths().length === 0) return + + const PathLoader = require('./path-loader') + this.loadPathsTask = PathLoader.startTask((projectPaths) => { + this.projectPaths = projectPaths + }, metricsReporter) + this.projectPathsSubscription = atom.project.onDidChangePaths(() => { + this.projectPaths = null + this.stopLoadPathsTask() + }) + }, + + stopLoadPathsTask () { + if (this.projectPathsSubscription != null) { + this.projectPathsSubscription.dispose() + } + this.projectPathsSubscription = null + + if (this.loadPathsTask != null) { + this.loadPathsTask.terminate() + } + this.loadPathsTask = null + } +} diff --git a/packages/fuzzy-finder/lib/path-loader.js b/packages/fuzzy-finder/lib/path-loader.js new file mode 100644 index 0000000000..7a2e4bf84b --- /dev/null +++ b/packages/fuzzy-finder/lib/path-loader.js @@ -0,0 +1,44 @@ +const fs = require('fs') +const {Task} = require('atom') + +module.exports = { + startTask (callback, metricsReporter) { + const results = [] + const taskPath = require.resolve('./load-paths-handler') + const followSymlinks = atom.config.get('core.followSymlinks') + let ignoredNames = atom.config.get('fuzzy-finder.ignoredNames') || [] + ignoredNames = ignoredNames.concat(atom.config.get('core.ignoredNames') || []) + const ignoreVcsIgnores = atom.config.get('core.excludeVcsIgnoredPaths') + const projectPaths = atom.project.getPaths().map((path) => fs.realpathSync(path)) + const useRipGrep = atom.config.get('fuzzy-finder.useRipGrep') + + const startTime = performance.now() + + const task = Task.once( + taskPath, + projectPaths, + followSymlinks, + ignoreVcsIgnores, + ignoredNames, + useRipGrep, + () => { + callback(results) + + const duration = Math.round(performance.now() - startTime) + const numFiles = results.length + const crawlerType = useRipGrep ? 'ripgrep' : 'fs' + + metricsReporter.sendCrawlEvent(duration, numFiles, crawlerType) + } + ) + + task.on('load-paths:paths-found', + (paths) => { + paths = paths || [] + results.push(...paths) + } + ) + + return task + } +} diff --git a/packages/fuzzy-finder/lib/project-view.js b/packages/fuzzy-finder/lib/project-view.js new file mode 100644 index 0000000000..3d3d082817 --- /dev/null +++ b/packages/fuzzy-finder/lib/project-view.js @@ -0,0 +1,191 @@ +const {Disposable, CompositeDisposable} = require('atom') +const humanize = require('humanize-plus') + +const FuzzyFinderView = require('./fuzzy-finder-view') +const PathLoader = require('./path-loader') + +module.exports = +class ProjectView extends FuzzyFinderView { + constructor (paths, metricsReporter) { + super(metricsReporter) + this.disposables = new CompositeDisposable() + this.paths = paths + this.reloadPaths = !this.paths || this.paths.length === 0 + this.reloadAfterFirstLoad = false + + const windowFocused = () => { + if (this.paths) { + this.reloadPaths = true + } else { + // The window gained focused while the first task was still running + // so let it complete but reload the paths on the next populate call. + this.reloadAfterFirstLoad = true + } + } + window.addEventListener('focus', windowFocused) + this.disposables.add(new Disposable(() => { window.removeEventListener('focus', windowFocused) })) + + this.disposables.add(atom.config.onDidChange('fuzzy-finder.ignoredNames', () => { this.reloadPaths = true })) + this.disposables.add(atom.config.onDidChange('core.followSymlinks', () => { this.reloadPaths = true })) + this.disposables.add(atom.config.onDidChange('core.ignoredNames', () => { this.reloadPaths = true })) + this.disposables.add(atom.config.onDidChange('core.excludeVcsIgnoredPaths', () => { this.reloadPaths = true })) + this.disposables.add(atom.project.onDidChangePaths(() => { + this.reloadPaths = true + this.paths = null + })) + + if (!this.reloadPaths) { + this.populate() + } + } + + destroy () { + if (this.loadPathsTask) { + this.loadPathsTask.terminate() + } + + this.disposables.dispose() + return super.destroy() + } + + setTeletypeService (teletypeService) { + this.teletypeService = teletypeService + } + + async toggle () { + if (this.panel && this.panel.isVisible()) { + this.cancel() + } else { + this.show() + await this.reloadPathsIfNeeded() + } + } + + async populate () { + const remoteEditors = (this.teletypeService && await this.teletypeService.getRemoteEditors()) || [] + + const remoteItems = remoteEditors.map((remoteEditor) => { + return { + uri: remoteEditor.uri, + filePath: remoteEditor.path, + label: `@${remoteEditor.hostGitHubUsername}: ${remoteEditor.path}`, + ownerGitHubUsername: remoteEditor.hostGitHubUsername + } + }) + + const localItems = this.projectRelativePathsForFilePaths(this.paths || []) + await this.setItems(remoteItems.concat(localItems)) + } + + async reloadPathsIfNeeded () { + if (this.reloadPaths) { + this.reloadPaths = false + let task = null + + if (atom.project.getPaths().length === 0) { + return this.populate() + } + + try { + task = this.runLoadPathsTask(() => { + if (this.reloadAfterFirstLoad) { + this.reloadPaths = true + this.reloadAfterFirstLoad = false + } + + this.populate() + }) + } catch (error) { + // If, for example, a network drive is unmounted, @runLoadPathsTask will + // throw ENOENT when it tries to get the realpath of all the project paths. + // This catch block allows the file finder to still operate on the last + // set of paths and still let the user know that something is wrong. + if (error.code === 'ENOENT' || error.code === 'EPERM') { + atom.notifications.addError('Project path not found!', {detail: error.message}) + } else { + throw error + } + } + + if (this.paths) { + await this.selectListView.update({loadingMessage: 'Reindexing project\u2026', infoMessage: null}) + } else { + await this.selectListView.update({loadingMessage: 'Indexing project\u2026', infoMessage: null, loadingBadge: '0'}) + if (task) { + let pathsFound = 0 + task.on('load-paths:paths-found', (paths) => { + pathsFound += paths.length + this.selectListView.update({loadingMessage: 'Indexing project\u2026', infoMessage: null, loadingBadge: humanize.intComma(pathsFound)}) + }) + } + } + } + } + + getEmptyMessage () { + return 'Project is empty' + } + + projectRelativePathsForFilePaths (filePaths) { + const projectRelativePaths = super.projectRelativePathsForFilePaths(filePaths) + const lastOpenedPath = this.getLastOpenedPath() + if (lastOpenedPath) { + for (let i = 0; i < projectRelativePaths.length; i++) { + const {filePath} = projectRelativePaths[i] + if (filePath === lastOpenedPath) { + const [entry] = projectRelativePaths.splice(i, 1) + projectRelativePaths.unshift(entry) + break + } + } + } + + return projectRelativePaths + } + + getLastOpenedPath () { + let activePath = null + const activePaneItem = atom.workspace.getActivePaneItem() + if (activePaneItem && activePaneItem.getPath) { + activePath = activePaneItem.getPath() + } + + let lastOpenedEditor = null + for (const editor of atom.workspace.getTextEditors()) { + const filePath = editor.getPath() + if (!filePath) { + continue + } + + if (activePath === filePath) { + continue + } + + if (!lastOpenedEditor) { + lastOpenedEditor = editor + } + + if (editor.lastOpened > lastOpenedEditor.lastOpened) { + lastOpenedEditor = editor + } + } + + return lastOpenedEditor ? lastOpenedEditor.getPath() : null + } + + runLoadPathsTask (fn) { + if (this.loadPathsTask) { + this.loadPathsTask.terminate() + } + + this.loadPathsTask = PathLoader.startTask((paths) => { + this.paths = paths + this.reloadPaths = false + if (fn) { + fn() + } + }, this.metricsReporter) + + return this.loadPathsTask + } +} diff --git a/packages/fuzzy-finder/lib/reporter-proxy.js b/packages/fuzzy-finder/lib/reporter-proxy.js new file mode 100644 index 0000000000..d21e996de7 --- /dev/null +++ b/packages/fuzzy-finder/lib/reporter-proxy.js @@ -0,0 +1,69 @@ +const _ = require('underscore-plus') + +module.exports = class ReporterProxy { + constructor () { + this.reporter = null + this.timingsQueue = [] + this.countersQueue = [] + + this.eventType = 'fuzzy-finder-v1' + + this._addTimingThrottled = _.throttle(this._addTiming.bind(this), 60 * 1000) + } + + setReporter (reporter) { + this.reporter = reporter + let timingsEvent + let counterName + + while ((timingsEvent = this.timingsQueue.shift())) { + this.reporter.addTiming(this.eventType, timingsEvent[0], timingsEvent[1]) + } + + while ((counterName = this.countersQueue.shift())) { + this.reporter.incrementCounter(counterName) + } + } + + unsetReporter () { + this._addTimingThrottled.cancel() + + delete this.reporter + } + + sendCrawlEvent (duration, numFiles, crawlerType) { + const metadata = { + ec: 'time-to-crawl', + el: crawlerType, + ev: numFiles + } + + this._addTiming(duration, metadata) + } + + sendFilterEvent (duration, numFiles, scoringSystem) { + const metadata = { + ec: 'time-to-filter', + el: scoringSystem, + ev: numFiles + } + + this._addTimingThrottled(duration, metadata) + } + + incrementCounter (counterName) { + if (this.reporter) { + this.reporter.incrementCounter(counterName) + } else { + this.countersQueue.push(counterName) + } + } + + _addTiming (duration, metadata) { + if (this.reporter) { + this.reporter.addTiming(this.eventType, duration, metadata) + } else { + this.timingsQueue.push([duration, metadata]) + } + } +} diff --git a/packages/fuzzy-finder/menus/fuzzy-finder.cson b/packages/fuzzy-finder/menus/fuzzy-finder.cson new file mode 100644 index 0000000000..2ed30f59c0 --- /dev/null +++ b/packages/fuzzy-finder/menus/fuzzy-finder.cson @@ -0,0 +1,8 @@ +'menu': [ + 'label': 'Find' + 'submenu': [ + { 'label': 'Find Buffer', 'command': 'fuzzy-finder:toggle-buffer-finder' } + { 'label': 'Find File', 'command': 'fuzzy-finder:toggle-file-finder' } + { 'label': 'Find Modified File', 'command': 'fuzzy-finder:toggle-git-status-finder' } + ] +] diff --git a/packages/fuzzy-finder/package-lock.json b/packages/fuzzy-finder/package-lock.json new file mode 100644 index 0000000000..4cbac07352 --- /dev/null +++ b/packages/fuzzy-finder/package-lock.json @@ -0,0 +1,5342 @@ +{ + "name": "fuzzy-finder", + "version": "1.14.3", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "fuzzy-finder", + "version": "1.14.3", + "license": "MIT", + "dependencies": { + "@atom/fuzzy-native": "^1.1.2", + "async": "0.2.6", + "atom-select-list": "^0.7.0", + "fs-plus": "^3.0.0", + "fuzzaldrin": "^2.0", + "fuzzaldrin-plus": "^0.6.0", + "humanize-plus": "~1.8.2", + "minimatch": "~3.0.3", + "temp": "~0.8.1", + "underscore-plus": "^1.7.0", + "vscode-ripgrep": "^1.2.5", + "wrench": "^1.5" + }, + "devDependencies": { + "sinon": "9.0.3", + "standard": "^10.0.3" + }, + "engines": { + "atom": "*" + } + }, + "node_modules/@atom/fuzzy-native": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@atom/fuzzy-native/-/fuzzy-native-1.2.1.tgz", + "integrity": "sha512-ABUIbeQqfoA4WUK+PAsspM9jLaGlj0wjyIc9CIi1OMAHv71/vqrpJHPX2fHWiREEXYxwh/CBCshhkOWESbnNnQ==", + "hasInstallScript": true, + "dependencies": { + "nan": "^2.14.2" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", + "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha512-AU7pnZkguthwBjKgCg6998ByQNIMjbuDQZ8bb78QAFZwPfmKia8AIzgY/gWgqCjnht8JLdXmB4YxA0KaV60ncQ==", + "dev": true, + "dependencies": { + "acorn": "^3.0.4" + } + }, + "node_modules/acorn-jsx/node_modules/acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha512-OLUyIIZ7mF5oaAUT1w0TFqQS81q3saT46x8t7ukpPjMNk+nbs4ZHhs7ToV8EWnLYLepjETXd4XaCE4uxkMeqUw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha512-I/bSHSNEcFFqXLf91nchoNB9D1Kie3QKcWdchYUaoIg1+1bdWDkdfdlvdIOJbi9U8xR0y+MWc5D+won9v95WlQ==", + "dev": true, + "dependencies": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "node_modules/ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha512-vuBv+fm2s6cqUyey2A7qYcvsik+GMDJsw8BARP2sDE76cqmaZVarsvHf7Vx6VJ0Xk8gLl+u3MoAPf6gKzJefeA==", + "dev": true, + "peerDependencies": { + "ajv": ">=4.10.0" + } + }, + "node_modules/ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array.prototype.find": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.2.1.tgz", + "integrity": "sha512-I2ri5Z9uMpMvnsNrHre9l3PaX+z9D0/z6F7Yt2u15q7wt0I62g5kX6xUKR1SJiefgG+u2/gJUmM8B47XRvQR6w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.6.tgz", + "integrity": "sha512-LTdAJ0KBRK5o4BlBlUoGvfGNOMON+NLbONgDZk80SX0G8LQZyjN+74nNADIpQ/+rxun6+fYm7z4vIzAB51UKUA==" + }, + "node_modules/atom-select-list": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/atom-select-list/-/atom-select-list-0.7.2.tgz", + "integrity": "sha512-a707OB1DhLGjzqtFrtMQKH7BBxFuCh8UBoUWxgFOrLrSwVh3g+/TlVPVDOz12+U0mDu3mIrnYLqQyhywQOTxhw==", + "dependencies": { + "etch": "^0.12.6", + "fuzzaldrin": "^2.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha512-UJiE1otjXPF5/x+T3zTnSFiTOEmJoGTD9HmBoxnCUwho61a2eSNn/VwtwuIBDAo2SEOv1AJ7ARI5gCmohFLu/g==", + "dev": true, + "dependencies": { + "callsites": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha512-Zv4Dns9IbXXmPkgRRUjAaJQgfN4xX5p6+RQFhWUqscdvvK2xK/ZL8b3IXIJsj+4sD+f24NwnWy2BY8AJ82JB0A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "deprecated": "CircularJSON is in maintenance only, flatted is its successor.", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha512-25tABq090YNKkF6JH7lcwO0zFJTRke4Jcq9iX2nr/Sz0Cjjv4gckmwlW6Ty/aoyFd6z3ysR2hMGC2GFugmBo6A==", + "dev": true, + "dependencies": { + "restore-cursor": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha512-OKZnPGeMQy2RPaUIBPFFd71iNf4791H12MCRuVQDnzGRwCYNYmTDy5pdafo2SLAcEMKzTOQnLWG4QdcjeJUMEg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/debug-log": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "integrity": "sha512-gV/pe1YIaKNgLYnd1g9VNW80tcb7oV5qvNUxG7NM8rbDpnl6RGunzlAtlGSb0wEs3nesu2vHNiX9TSsZ+Y+RjA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", + "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", + "dev": true, + "dependencies": { + "find-root": "^1.0.0", + "glob": "^7.0.5", + "ignore": "^3.0.9", + "pkg-config": "^1.1.0", + "run-parallel": "^1.1.2", + "uniq": "^1.0.1" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "node_modules/es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-set/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", + "dev": true, + "dependencies": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha512-x6LJGXWCGB/4YOBhL48yeppZTo+YQUNC37N5qqCpC1b1kkNzydlQHQAtPuUSFoZSxgIadrysQoW2Hq602P+uEA==", + "dev": true, + "dependencies": { + "babel-code-frame": "^6.16.0", + "chalk": "^1.1.3", + "concat-stream": "^1.5.2", + "debug": "^2.1.1", + "doctrine": "^2.0.0", + "escope": "^3.6.0", + "espree": "^3.4.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "glob": "^7.0.3", + "globals": "^9.14.0", + "ignore": "^3.2.0", + "imurmurhash": "^0.1.4", + "inquirer": "^0.12.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.5.1", + "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", + "lodash": "^4.0.0", + "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.1", + "pluralize": "^1.2.1", + "progress": "^1.1.8", + "require-uncached": "^1.0.2", + "shelljs": "^0.7.5", + "strip-bom": "^3.0.0", + "strip-json-comments": "~2.0.1", + "table": "^3.7.8", + "text-table": "~0.2.0", + "user-home": "^2.0.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-standard": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", + "integrity": "sha512-UkFojTV1o0GOe1edOEiuI5ccYLJSuNngtqSeClNzhsmG8KPJ+7mRxgtp2oYhqZAK/brlXMoCd+VgXViE0AfyKw==", + "dev": true, + "peerDependencies": { + "eslint": ">=3.19.0", + "eslint-plugin-import": ">=2.2.0", + "eslint-plugin-node": ">=4.2.2", + "eslint-plugin-promise": ">=3.5.0", + "eslint-plugin-standard": ">=3.0.0" + } + }, + "node_modules/eslint-config-standard-jsx": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz", + "integrity": "sha512-F8fRh2WFnTek7dZH9ZaE0PCBwdVGkwVWZmizla/DDNOmg7Tx6B/IlK5+oYpiX29jpu73LszeJj5i1axEZv6VMw==", + "dev": true, + "peerDependencies": { + "eslint": ">=3.19.0", + "eslint-plugin-react": ">=6.10.3" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz", + "integrity": "sha512-HI8ShtDIy7gON76Nr3bu4zl0DuCLPo1Fud9P2lltOQKeiAS2r5/o/l3y+V8HJ1cDLFSz+tHu7/V9fI5jirwlbw==", + "dev": true, + "dependencies": { + "debug": "^2.2.0", + "object-assign": "^4.0.1", + "resolve": "^1.1.6" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz", + "integrity": "sha512-8HLeIYzOH4eltevxf+iC9Dtz/91yaeOqtlba5srcpQWLrv57F5NNG1RNLqAbpWJWDD4BxKuKjUveJY9W6Tbswg==", + "dev": true, + "dependencies": { + "builtin-modules": "^1.1.1", + "contains-path": "^0.1.0", + "debug": "^2.2.0", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.2.0", + "eslint-module-utils": "^2.0.0", + "has": "^1.0.1", + "lodash.cond": "^4.3.0", + "minimatch": "^3.0.3", + "pkg-up": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "2.x - 3.x" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/eslint-plugin-node": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz", + "integrity": "sha512-vIUQPuwbVYdz/CYnlTLsJrRy7iXHQjdEe5wz0XhhdTym3IInM/zZLlPf9nZ2mThsH0QcsieCOWs2vOeCy/22LQ==", + "dev": true, + "dependencies": { + "ignore": "^3.0.11", + "minimatch": "^3.0.2", + "object-assign": "^4.0.1", + "resolve": "^1.1.7", + "semver": "5.3.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": ">=3.1.0" + } + }, + "node_modules/eslint-plugin-promise": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz", + "integrity": "sha512-kqXN7i1wfx5j7XuFVzuX4W3XDCEyNDsbd+O5NXWIl+zTSP510rKn2Xk8OO6JhM1ivXbkse0tQf6jjSTLS58Prg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-react": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", + "integrity": "sha512-vFfMSxJynKlgOhIVjhlZyibVUg442Aiv3482XPkgdYV90T8nD2QvxGXILZGwZHYMQ/l+A/De14O9D0qjDelSrg==", + "dev": true, + "dependencies": { + "array.prototype.find": "^2.0.1", + "doctrine": "^1.2.2", + "has": "^1.0.1", + "jsx-ast-utils": "^1.3.4", + "object.assign": "^4.0.4" + }, + "engines": { + "node": ">=0.10" + }, + "peerDependencies": { + "eslint": "^2.0.0 || ^3.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/eslint-plugin-standard": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", + "integrity": "sha512-JyT7wqVYlaHxnljWMT7CKa0R1QDQqArTi6g8kYnexTHHuK7x3Vg//kCepnoTgdT9x/kDbSluXMhJgjBvgVRLlQ==", + "dev": true, + "peerDependencies": { + "eslint": ">=3.19.0" + } + }, + "node_modules/espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "dependencies": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etch": { + "version": "0.12.8", + "resolved": "https://registry.npmjs.org/etch/-/etch-0.12.8.tgz", + "integrity": "sha512-dFLRe4wLroVtwzyy1vGlE3BSDZHiL0kZME5XgNGzZIULcYTvVno8vbiIleAesoKJmwWaxDTzG+4eppg2zk14JQ==" + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha512-MsG3prOVw1WtLXAZbM3KiYtooKR1LvxHh3VHsVtIy0uiUu8usxgB/94DP2HxtD/661lLdB6yzQ09lGJSQr6nkg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha512-uXP/zGzxxFvFfcZGgBIwotm+Tdc55ddPAzF7iHshP4YGaXMww7rSF9peD9D1sui5ebONg5UobsZv+FfgEpGv/w==", + "dev": true, + "dependencies": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "dependencies": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs-plus": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", + "integrity": "sha512-Se2PJdOWXqos1qVTkvqqjb0CSnfBnwwD+pq+z4ksT+e97mEShod/hrNg0TRCCsXPbJzcIq+NuzQhigunMWMJUA==", + "dependencies": { + "async": "^1.5.2", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2", + "underscore-plus": "1.x" + } + }, + "node_modules/fs-plus/node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuzzaldrin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz", + "integrity": "sha512-zgllBYwfHR5P3CncJiGbGVPpa3iFYW1yuPaIv8DiTVRrcg5/6uETNL5zvIoKflG1aifXVUZTlIroDehw4WygGA==" + }, + "node_modules/fuzzaldrin-plus": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/fuzzaldrin-plus/-/fuzzaldrin-plus-0.6.0.tgz", + "integrity": "sha512-srIDThJHkdp3aPwJpR/HNzYZCRJwm07b/igxseoHSB7qR8e/gQp4F6lMGknE3TQI1Aq14TiFf/wzrHOp9LY/EA==" + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dev": true, + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", + "dev": true, + "dependencies": { + "is-property": "^1.0.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "dependencies": { + "agent-base": "5", + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/humanize-plus": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/humanize-plus/-/humanize-plus-1.8.2.tgz", + "integrity": "sha512-jaLeQyyzjjINGv7O9JJegjsaUcWjSj/1dcXvLEgU3pGdqCdP1PiC/uwr+saJXhTNBHZtmKnmpXyazgh+eceRxA==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha512-bOetEz5+/WpgaW4D1NYOk1aD+JCqRjqu/FwRFgnIfiP7FC/zinsrfyO1vlS3nyH/R7S0IH3BIHBu4DBIDSqiGQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "node_modules/internal-slot": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-my-ip-valid": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", + "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", + "dev": true + }, + "node_modules/is-my-json-valid": { + "version": "2.20.6", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", + "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", + "dev": true, + "dependencies": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^5.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-stable-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz", + "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==", + "dev": true, + "dependencies": { + "jsonify": "^0.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha512-0LwSmMlQjjUdXsdlyYhEfBJCn2Chm0zgUBmfmf1++KUULh+JOdlzrZfiwe2zmlVJx44UF+KX/B/odBoeK9hxmw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.cond": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", + "integrity": "sha512-RWjUhzGbzG/KfDwk+onqdXvrsNv47G9UCMJgSKalPTSqJQyxZhQophG9jgqLf+15TIbZ5a/yG2YKOWsH3dVy9A==", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha512-EbrziT4s8cWPmzr47eYVW3wimS4HsvlnV5ri1xw1aR6JQo/OrJX5rkl32K/QQHdxeabJETtfeaROGhd8W7uBgg==", + "dev": true + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/nise": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.1.0.tgz", + "integrity": "sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", + "integrity": "sha512-ft/WI9YK6FuTuw4Ql+QUaNXtm/ASQNqDUUsZEgFZKyFpW6amyP8Gx01xrRs8KdiNbbqXfYxkOXplpq1euWbOjw==", + "dev": true, + "dependencies": { + "debug-log": "^1.0.0", + "find-root": "^1.0.0", + "xtend": "^4.0.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha512-L+d849d9lz20hnRpUnWBRXOh+mAvygQpK7UuXiw+6QbPwL55RVgl+G+V936wCzs/6J7fj0pvgLY9OknZ+FqaNA==", + "dev": true, + "dependencies": { + "find-up": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha512-TH+BeeL6Ct98C7as35JbZLf8lgsRzlNJb5gklRIGHKaPkGl1esOKBc5ALUMd+q08Sr6tiEKM+Icbsxg5vuhMKQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha512-8/td4MmwUB6PkZUbV25uKz7dfrmjYWxsW8DVfibWdlHRk/l/DfHKn4pU+dfcoGLFgWOdyGCzINRQD7jn+Bv+/g==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "mute-stream": "0.0.5" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha512-Xct+41K3twrbBHdxAgMoOS+cNcoqIjfM2/VxBF4LL2hVph7YsF8VSKyQ3BDFZwEVbok9yeDl2le/qo0S77WG2w==", + "dev": true, + "dependencies": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha512-kT10v4dhrlLNcnO084hEjvXCI1wUG9qZLoz2RogxqDQQYy7IxjI/iMUkOtQTNEh6rzHxvdQWHsJyel1pKOVCxg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha512-reSjH4HuiFlxlaBaFCiS6O76ZGG2ygKoSlCsipKdaZuKSPx/+bt9mULkn4l0asVzbEfQQmXRg6Wp6gv6m0wElw==", + "dev": true, + "dependencies": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha512-qOX+w+IxFgpUpJfkv2oGN0+ExPs68F4sZHfaRRx4dDexAQkG83atugKVEylyT5ARees3HBbfmuvnjbrd8j9Wjw==", + "dev": true, + "dependencies": { + "once": "^1.3.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha512-1I1+G2gteLB8Tkt8YI1sJvSIfa0lWuRtC8GjvtyPBcLSF5jBCCJJqKrpER5JU5r6Bhe+i9/pK3VMuUcXu0kdwQ==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha512-mfmm3/H9+67MCVix1h+IXTpDwL6710LyHuk7+cWC9T1mE0qz4iHhh6r4hU2wrIT9iTsAAC2XQRvfblL028cpLw==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha512-/YF5Uk8hcwi7ima04ppkbA4RaRMdPMBfwAvAf8sufYOxsJRtbdoBsT8vGvlb+799BrlGdYrd+oczIA2eN2JdWA==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "iojs": "*", + "node": ">=0.11.0" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sinon": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.3.tgz", + "integrity": "sha512-IKo9MIM111+smz9JGwLmw5U1075n1YXeAq8YeSFlndCLhAL5KGn6bLgu7b/4AYHTV/LcEMcRm2wU2YiL55/6Pg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.2", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.1.0", + "diff": "^4.0.2", + "nise": "^4.0.4", + "supports-color": "^7.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/standard": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/standard/-/standard-10.0.3.tgz", + "integrity": "sha512-JURZ+85ExKLQULckDFijdX5WHzN6RC7fgiZNSV4jFQVo+3tPoQGHyBrGekye/yf0aOfb4210EM5qPNlc2cRh4w==", + "dev": true, + "dependencies": { + "eslint": "~3.19.0", + "eslint-config-standard": "10.2.1", + "eslint-config-standard-jsx": "4.0.2", + "eslint-plugin-import": "~2.2.0", + "eslint-plugin-node": "~4.2.2", + "eslint-plugin-promise": "~3.5.0", + "eslint-plugin-react": "~6.10.0", + "eslint-plugin-standard": "~3.0.1", + "standard-engine": "~7.0.0" + }, + "bin": { + "standard": "bin/cmd.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard-engine": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-7.0.0.tgz", + "integrity": "sha512-d/NYzmZxQRxbcoCqlbI9gEMPYq7TLsU6Ywpki54xhedEd0GC4G02j1B7mlexb7HovqRtAtcUPTLQx2MnCO/uyA==", + "dev": true, + "dependencies": { + "deglob": "^2.1.0", + "get-stdin": "^5.0.1", + "minimist": "^1.1.0", + "pkg-conf": "^2.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha512-RZuzIOtzFbprLCE0AXhkI0Xi42ZJLZhCC+qkwuMLf/Vjz3maWpA8gz1qMdbmNoI9cOROT2Am/DxeRyXenrL11g==", + "dev": true, + "dependencies": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "dependencies": { + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + }, + "node_modules/underscore-plus": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.7.0.tgz", + "integrity": "sha512-A3BEzkeicFLnr+U/Q3EyWwJAQPbA19mtZZ4h+lLq3ttm9kn8WC4R3YpuJZEXmWdLjYP47Zc8aLZm9kwdv+zzvA==", + "dependencies": { + "underscore": "^1.9.1" + } + }, + "node_modules/uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==", + "dev": true + }, + "node_modules/user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vscode-ripgrep": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/vscode-ripgrep/-/vscode-ripgrep-1.13.2.tgz", + "integrity": "sha512-RlK9U87EokgHfiOjDQ38ipQQX936gWOcWPQaJpYf+kAkz1PQ1pK2n7nhiscdOmLu6XGjTs7pWFJ/ckonpN7twQ==", + "deprecated": "This package has been renamed to @vscode/ripgrep, please update to the new name", + "hasInstallScript": true, + "dependencies": { + "https-proxy-agent": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/wrench": { + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/wrench/-/wrench-1.5.9.tgz", + "integrity": "sha512-QH+8W9n0UGDAxnRDOkQzG1N277GTaBgMDNdckluqnAY773njfs1gfo867IbMMbGjOZZof+zlRIUeQ9XN8VUHUQ==", + "deprecated": "wrench.js is deprecated! You should check out fs-extra (https://github.com/jprichardson/node-fs-extra) for any operations you were using wrench for. Thanks for all the usage over the years.", + "engines": { + "node": ">=0.1.97" + } + }, + "node_modules/write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha512-CJ17OoULEKXpA5pef3qLj5AxTJ6mSt7g84he2WIskKwqFO4T97d5V7Tadl0DYDk7qyUOQD5WlUlOMChaYrhxeA==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + } + }, + "dependencies": { + "@atom/fuzzy-native": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@atom/fuzzy-native/-/fuzzy-native-1.2.1.tgz", + "integrity": "sha512-ABUIbeQqfoA4WUK+PAsspM9jLaGlj0wjyIc9CIi1OMAHv71/vqrpJHPX2fHWiREEXYxwh/CBCshhkOWESbnNnQ==", + "requires": { + "nan": "^2.14.2" + } + }, + "@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", + "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha512-AU7pnZkguthwBjKgCg6998ByQNIMjbuDQZ8bb78QAFZwPfmKia8AIzgY/gWgqCjnht8JLdXmB4YxA0KaV60ncQ==", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha512-OLUyIIZ7mF5oaAUT1w0TFqQS81q3saT46x8t7ukpPjMNk+nbs4ZHhs7ToV8EWnLYLepjETXd4XaCE4uxkMeqUw==", + "dev": true + } + } + }, + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==" + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha512-I/bSHSNEcFFqXLf91nchoNB9D1Kie3QKcWdchYUaoIg1+1bdWDkdfdlvdIOJbi9U8xR0y+MWc5D+won9v95WlQ==", + "dev": true, + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha512-vuBv+fm2s6cqUyey2A7qYcvsik+GMDJsw8BARP2sDE76cqmaZVarsvHf7Vx6VJ0Xk8gLl+u3MoAPf6gKzJefeA==", + "dev": true, + "requires": {} + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array.prototype.find": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.2.1.tgz", + "integrity": "sha512-I2ri5Z9uMpMvnsNrHre9l3PaX+z9D0/z6F7Yt2u15q7wt0I62g5kX6xUKR1SJiefgG+u2/gJUmM8B47XRvQR6w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "async": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.6.tgz", + "integrity": "sha512-LTdAJ0KBRK5o4BlBlUoGvfGNOMON+NLbONgDZk80SX0G8LQZyjN+74nNADIpQ/+rxun6+fYm7z4vIzAB51UKUA==" + }, + "atom-select-list": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/atom-select-list/-/atom-select-list-0.7.2.tgz", + "integrity": "sha512-a707OB1DhLGjzqtFrtMQKH7BBxFuCh8UBoUWxgFOrLrSwVh3g+/TlVPVDOz12+U0mDu3mIrnYLqQyhywQOTxhw==", + "requires": { + "etch": "^0.12.6", + "fuzzaldrin": "^2.1.0" + } + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha512-UJiE1otjXPF5/x+T3zTnSFiTOEmJoGTD9HmBoxnCUwho61a2eSNn/VwtwuIBDAo2SEOv1AJ7ARI5gCmohFLu/g==", + "dev": true, + "requires": { + "callsites": "^0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha512-Zv4Dns9IbXXmPkgRRUjAaJQgfN4xX5p6+RQFhWUqscdvvK2xK/ZL8b3IXIJsj+4sD+f24NwnWy2BY8AJ82JB0A==", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true + } + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha512-25tABq090YNKkF6JH7lcwO0zFJTRke4Jcq9iX2nr/Sz0Cjjv4gckmwlW6Ty/aoyFd6z3ysR2hMGC2GFugmBo6A==", + "dev": true, + "requires": { + "restore-cursor": "^1.0.1" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha512-OKZnPGeMQy2RPaUIBPFFd71iNf4791H12MCRuVQDnzGRwCYNYmTDy5pdafo2SLAcEMKzTOQnLWG4QdcjeJUMEg==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debug-log": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "integrity": "sha512-gV/pe1YIaKNgLYnd1g9VNW80tcb7oV5qvNUxG7NM8rbDpnl6RGunzlAtlGSb0wEs3nesu2vHNiX9TSsZ+Y+RjA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "deglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", + "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", + "dev": true, + "requires": { + "find-root": "^1.0.0", + "glob": "^7.0.5", + "ignore": "^3.0.9", + "pkg-config": "^1.1.0", + "run-parallel": "^1.1.2", + "uniq": "^1.0.1" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + } + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", + "dev": true, + "requires": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha512-x6LJGXWCGB/4YOBhL48yeppZTo+YQUNC37N5qqCpC1b1kkNzydlQHQAtPuUSFoZSxgIadrysQoW2Hq602P+uEA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.16.0", + "chalk": "^1.1.3", + "concat-stream": "^1.5.2", + "debug": "^2.1.1", + "doctrine": "^2.0.0", + "escope": "^3.6.0", + "espree": "^3.4.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "glob": "^7.0.3", + "globals": "^9.14.0", + "ignore": "^3.2.0", + "imurmurhash": "^0.1.4", + "inquirer": "^0.12.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.5.1", + "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", + "lodash": "^4.0.0", + "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.1", + "pluralize": "^1.2.1", + "progress": "^1.1.8", + "require-uncached": "^1.0.2", + "shelljs": "^0.7.5", + "strip-bom": "^3.0.0", + "strip-json-comments": "~2.0.1", + "table": "^3.7.8", + "text-table": "~0.2.0", + "user-home": "^2.0.0" + } + }, + "eslint-config-standard": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", + "integrity": "sha512-UkFojTV1o0GOe1edOEiuI5ccYLJSuNngtqSeClNzhsmG8KPJ+7mRxgtp2oYhqZAK/brlXMoCd+VgXViE0AfyKw==", + "dev": true, + "requires": {} + }, + "eslint-config-standard-jsx": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz", + "integrity": "sha512-F8fRh2WFnTek7dZH9ZaE0PCBwdVGkwVWZmizla/DDNOmg7Tx6B/IlK5+oYpiX29jpu73LszeJj5i1axEZv6VMw==", + "dev": true, + "requires": {} + }, + "eslint-import-resolver-node": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz", + "integrity": "sha512-HI8ShtDIy7gON76Nr3bu4zl0DuCLPo1Fud9P2lltOQKeiAS2r5/o/l3y+V8HJ1cDLFSz+tHu7/V9fI5jirwlbw==", + "dev": true, + "requires": { + "debug": "^2.2.0", + "object-assign": "^4.0.1", + "resolve": "^1.1.6" + } + }, + "eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz", + "integrity": "sha512-8HLeIYzOH4eltevxf+iC9Dtz/91yaeOqtlba5srcpQWLrv57F5NNG1RNLqAbpWJWDD4BxKuKjUveJY9W6Tbswg==", + "dev": true, + "requires": { + "builtin-modules": "^1.1.1", + "contains-path": "^0.1.0", + "debug": "^2.2.0", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.2.0", + "eslint-module-utils": "^2.0.0", + "has": "^1.0.1", + "lodash.cond": "^4.3.0", + "minimatch": "^3.0.3", + "pkg-up": "^1.0.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz", + "integrity": "sha512-vIUQPuwbVYdz/CYnlTLsJrRy7iXHQjdEe5wz0XhhdTym3IInM/zZLlPf9nZ2mThsH0QcsieCOWs2vOeCy/22LQ==", + "dev": true, + "requires": { + "ignore": "^3.0.11", + "minimatch": "^3.0.2", + "object-assign": "^4.0.1", + "resolve": "^1.1.7", + "semver": "5.3.0" + } + }, + "eslint-plugin-promise": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz", + "integrity": "sha512-kqXN7i1wfx5j7XuFVzuX4W3XDCEyNDsbd+O5NXWIl+zTSP510rKn2Xk8OO6JhM1ivXbkse0tQf6jjSTLS58Prg==", + "dev": true + }, + "eslint-plugin-react": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", + "integrity": "sha512-vFfMSxJynKlgOhIVjhlZyibVUg442Aiv3482XPkgdYV90T8nD2QvxGXILZGwZHYMQ/l+A/De14O9D0qjDelSrg==", + "dev": true, + "requires": { + "array.prototype.find": "^2.0.1", + "doctrine": "^1.2.2", + "has": "^1.0.1", + "jsx-ast-utils": "^1.3.4", + "object.assign": "^4.0.4" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + } + } + }, + "eslint-plugin-standard": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", + "integrity": "sha512-JyT7wqVYlaHxnljWMT7CKa0R1QDQqArTi6g8kYnexTHHuK7x3Vg//kCepnoTgdT9x/kDbSluXMhJgjBvgVRLlQ==", + "dev": true, + "requires": {} + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etch": { + "version": "0.12.8", + "resolved": "https://registry.npmjs.org/etch/-/etch-0.12.8.tgz", + "integrity": "sha512-dFLRe4wLroVtwzyy1vGlE3BSDZHiL0kZME5XgNGzZIULcYTvVno8vbiIleAesoKJmwWaxDTzG+4eppg2zk14JQ==" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha512-MsG3prOVw1WtLXAZbM3KiYtooKR1LvxHh3VHsVtIy0uiUu8usxgB/94DP2HxtD/661lLdB6yzQ09lGJSQr6nkg==", + "dev": true + }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "requires": { + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + } + } + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha512-uXP/zGzxxFvFfcZGgBIwotm+Tdc55ddPAzF7iHshP4YGaXMww7rSF9peD9D1sui5ebONg5UobsZv+FfgEpGv/w==", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "fs-plus": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", + "integrity": "sha512-Se2PJdOWXqos1qVTkvqqjb0CSnfBnwwD+pq+z4ksT+e97mEShod/hrNg0TRCCsXPbJzcIq+NuzQhigunMWMJUA==", + "requires": { + "async": "^1.5.2", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2", + "underscore-plus": "1.x" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==" + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "fuzzaldrin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz", + "integrity": "sha512-zgllBYwfHR5P3CncJiGbGVPpa3iFYW1yuPaIv8DiTVRrcg5/6uETNL5zvIoKflG1aifXVUZTlIroDehw4WygGA==" + }, + "fuzzaldrin-plus": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/fuzzaldrin-plus/-/fuzzaldrin-plus-0.6.0.tgz", + "integrity": "sha512-srIDThJHkdp3aPwJpR/HNzYZCRJwm07b/igxseoHSB7qR8e/gQp4F6lMGknE3TQI1Aq14TiFf/wzrHOp9LY/EA==" + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dev": true, + "requires": { + "is-property": "^1.0.2" + } + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==", + "dev": true, + "requires": { + "is-property": "^1.0.0" + } + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "requires": { + "agent-base": "5", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "humanize-plus": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/humanize-plus/-/humanize-plus-1.8.2.tgz", + "integrity": "sha512-jaLeQyyzjjINGv7O9JJegjsaUcWjSj/1dcXvLEgU3pGdqCdP1PiC/uwr+saJXhTNBHZtmKnmpXyazgh+eceRxA==" + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha512-bOetEz5+/WpgaW4D1NYOk1aD+JCqRjqu/FwRFgnIfiP7FC/zinsrfyO1vlS3nyH/R7S0IH3BIHBu4DBIDSqiGQ==", + "dev": true, + "requires": { + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "internal-slot": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-my-ip-valid": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz", + "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==", + "dev": true + }, + "is-my-json-valid": { + "version": "2.20.6", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz", + "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==", + "dev": true, + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^5.0.0", + "xtend": "^4.0.0" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz", + "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==", + "dev": true, + "requires": { + "jsonify": "^0.0.1" + } + }, + "jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true + }, + "jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true + }, + "jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha512-0LwSmMlQjjUdXsdlyYhEfBJCn2Chm0zgUBmfmf1++KUULh+JOdlzrZfiwe2zmlVJx44UF+KX/B/odBoeK9hxmw==", + "dev": true + }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.cond": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", + "integrity": "sha512-RWjUhzGbzG/KfDwk+onqdXvrsNv47G9UCMJgSKalPTSqJQyxZhQophG9jgqLf+15TIbZ5a/yG2YKOWsH3dVy9A==", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha512-EbrziT4s8cWPmzr47eYVW3wimS4HsvlnV5ri1xw1aR6JQo/OrJX5rkl32K/QQHdxeabJETtfeaROGhd8W7uBgg==", + "dev": true + }, + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "nise": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.1.0.tgz", + "integrity": "sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A==", + "dev": true + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + } + } + }, + "pkg-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", + "integrity": "sha512-ft/WI9YK6FuTuw4Ql+QUaNXtm/ASQNqDUUsZEgFZKyFpW6amyP8Gx01xrRs8KdiNbbqXfYxkOXplpq1euWbOjw==", + "dev": true, + "requires": { + "debug-log": "^1.0.0", + "find-root": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha512-L+d849d9lz20hnRpUnWBRXOh+mAvygQpK7UuXiw+6QbPwL55RVgl+G+V936wCzs/6J7fj0pvgLY9OknZ+FqaNA==", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha512-TH+BeeL6Ct98C7as35JbZLf8lgsRzlNJb5gklRIGHKaPkGl1esOKBc5ALUMd+q08Sr6tiEKM+Icbsxg5vuhMKQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", + "dev": true + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + } + } + }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha512-8/td4MmwUB6PkZUbV25uKz7dfrmjYWxsW8DVfibWdlHRk/l/DfHKn4pU+dfcoGLFgWOdyGCzINRQD7jn+Bv+/g==", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "mute-stream": "0.0.5" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha512-Xct+41K3twrbBHdxAgMoOS+cNcoqIjfM2/VxBF4LL2hVph7YsF8VSKyQ3BDFZwEVbok9yeDl2le/qo0S77WG2w==", + "dev": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + } + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha512-kT10v4dhrlLNcnO084hEjvXCI1wUG9qZLoz2RogxqDQQYy7IxjI/iMUkOtQTNEh6rzHxvdQWHsJyel1pKOVCxg==", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha512-reSjH4HuiFlxlaBaFCiS6O76ZGG2ygKoSlCsipKdaZuKSPx/+bt9mULkn4l0asVzbEfQQmXRg6Wp6gv6m0wElw==", + "dev": true, + "requires": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha512-qOX+w+IxFgpUpJfkv2oGN0+ExPs68F4sZHfaRRx4dDexAQkG83atugKVEylyT5ARees3HBbfmuvnjbrd8j9Wjw==", + "dev": true, + "requires": { + "once": "^1.3.0" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha512-1I1+G2gteLB8Tkt8YI1sJvSIfa0lWuRtC8GjvtyPBcLSF5jBCCJJqKrpER5JU5r6Bhe+i9/pK3VMuUcXu0kdwQ==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha512-mfmm3/H9+67MCVix1h+IXTpDwL6710LyHuk7+cWC9T1mE0qz4iHhh6r4hU2wrIT9iTsAAC2XQRvfblL028cpLw==", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha512-/YF5Uk8hcwi7ima04ppkbA4RaRMdPMBfwAvAf8sufYOxsJRtbdoBsT8vGvlb+799BrlGdYrd+oczIA2eN2JdWA==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "sinon": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.3.tgz", + "integrity": "sha512-IKo9MIM111+smz9JGwLmw5U1075n1YXeAq8YeSFlndCLhAL5KGn6bLgu7b/4AYHTV/LcEMcRm2wU2YiL55/6Pg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.2", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.1.0", + "diff": "^4.0.2", + "nise": "^4.0.4", + "supports-color": "^7.1.0" + } + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "standard": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/standard/-/standard-10.0.3.tgz", + "integrity": "sha512-JURZ+85ExKLQULckDFijdX5WHzN6RC7fgiZNSV4jFQVo+3tPoQGHyBrGekye/yf0aOfb4210EM5qPNlc2cRh4w==", + "dev": true, + "requires": { + "eslint": "~3.19.0", + "eslint-config-standard": "10.2.1", + "eslint-config-standard-jsx": "4.0.2", + "eslint-plugin-import": "~2.2.0", + "eslint-plugin-node": "~4.2.2", + "eslint-plugin-promise": "~3.5.0", + "eslint-plugin-react": "~6.10.0", + "eslint-plugin-standard": "~3.0.1", + "standard-engine": "~7.0.0" + } + }, + "standard-engine": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-7.0.0.tgz", + "integrity": "sha512-d/NYzmZxQRxbcoCqlbI9gEMPYq7TLsU6Ywpki54xhedEd0GC4G02j1B7mlexb7HovqRtAtcUPTLQx2MnCO/uyA==", + "dev": true, + "requires": { + "deglob": "^2.1.0", + "get-stdin": "^5.0.1", + "minimist": "^1.1.0", + "pkg-conf": "^2.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha512-RZuzIOtzFbprLCE0AXhkI0Xi42ZJLZhCC+qkwuMLf/Vjz3maWpA8gz1qMdbmNoI9cOROT2Am/DxeRyXenrL11g==", + "dev": true, + "requires": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "requires": { + "rimraf": "~2.6.2" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + }, + "underscore-plus": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.7.0.tgz", + "integrity": "sha512-A3BEzkeicFLnr+U/Q3EyWwJAQPbA19mtZZ4h+lLq3ttm9kn8WC4R3YpuJZEXmWdLjYP47Zc8aLZm9kwdv+zzvA==", + "requires": { + "underscore": "^1.9.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==", + "dev": true + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "vscode-ripgrep": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/vscode-ripgrep/-/vscode-ripgrep-1.13.2.tgz", + "integrity": "sha512-RlK9U87EokgHfiOjDQ38ipQQX936gWOcWPQaJpYf+kAkz1PQ1pK2n7nhiscdOmLu6XGjTs7pWFJ/ckonpN7twQ==", + "requires": { + "https-proxy-agent": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "wrench": { + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/wrench/-/wrench-1.5.9.tgz", + "integrity": "sha512-QH+8W9n0UGDAxnRDOkQzG1N277GTaBgMDNdckluqnAY773njfs1gfo867IbMMbGjOZZof+zlRIUeQ9XN8VUHUQ==" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha512-CJ17OoULEKXpA5pef3qLj5AxTJ6mSt7g84he2WIskKwqFO4T97d5V7Tadl0DYDk7qyUOQD5WlUlOMChaYrhxeA==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + } + } +} diff --git a/packages/fuzzy-finder/package.json b/packages/fuzzy-finder/package.json new file mode 100644 index 0000000000..ff4b6b036e --- /dev/null +++ b/packages/fuzzy-finder/package.json @@ -0,0 +1,74 @@ +{ + "name": "fuzzy-finder", + "version": "1.14.3", + "main": "./lib/main", + "description": "Open an editor to a file in the project with `cmd-t`.", + "repository": "https://github.com/pulsar-edit/fuzzy-finder", + "license": "MIT", + "dependencies": { + "@pulsar-edit/fuzzy-native": "https://github.com/pulsar-edit/fuzzy-native.git#13d2e5f", + "atom-select-list": "^0.7.0", + "fs-plus": "^3.0.0", + "minimatch": "~3.0.3", + "underscore-plus": "^1.7.0", + "vscode-ripgrep": "^1.2.5", + "wrench": "^1.5" + }, + "devDependencies": { + "async": "0.2.6", + "temp": "~0.8.1", + "sinon": "9.0.3" + }, + "engines": { + "atom": "*" + }, + "consumedServices": { + "teletype": { + "versions": { + "0.0.1": "consumeTeletype" + } + }, + "atom.file-icons": { + "versions": { + "1.0.0": "consumeFileIcons" + } + }, + "file-icons.element-icons": { + "versions": { + "1.0.0": "consumeElementIcons" + } + }, + "metrics-reporter": { + "versions": { + "^1.1.0": "consumeMetricsReporter" + } + } + }, + "configSchema": { + "ignoredNames": { + "type": "array", + "default": [], + "description": "List of string glob patterns. Files and directories matching these patterns will be ignored. This list is merged with the list defined by the core `Ignored Names` config setting. Example: `.git, ._*, Thumbs.db`." + }, + "searchAllPanes": { + "type": "boolean", + "default": false, + "description": "Search all panes when opening files. If disabled, only the active pane is searched. Holding `shift` inverts this setting." + }, + "preserveLastSearch": { + "type": "boolean", + "default": false, + "description": "Remember the typed query when closing the fuzzy finder and use that as the starting query next time the fuzzy finder is opened." + }, + "useRipGrep": { + "type": "boolean", + "default": true, + "description": "Use the substantially faster `ripgrep` crawler." + }, + "prefillFromSelection": { + "type": "boolean", + "default": false, + "description": "Prefills search query with selected in current editor text" + } + } +} diff --git a/packages/fuzzy-finder/spec/async-spec-helpers.js b/packages/fuzzy-finder/spec/async-spec-helpers.js new file mode 100644 index 0000000000..8be55f49fc --- /dev/null +++ b/packages/fuzzy-finder/spec/async-spec-helpers.js @@ -0,0 +1,65 @@ +exports.beforeEach = function (fn) { + global.beforeEach(function () { + const result = fn() + if (result instanceof Promise) { + waitsForPromise(() => result) + } + }) +} + +exports.afterEach = function (fn) { + global.afterEach(function () { + const result = fn() + if (result instanceof Promise) { + waitsForPromise(() => result) + } + }) +} + +for (const name of ['it', 'fit', 'ffit', 'fffit']) { + module.exports[name] = function (description, fn) { + if (fn === undefined) { + global[name](description) + return + } + + global[name](description, function () { + const result = fn() + if (result instanceof Promise) { + waitsForPromise(() => result) + } + }) + } +} + +exports.conditionPromise = async function (condition, description = 'anonymous condition') { + const startTime = Date.now() + + while (true) { + await exports.timeoutPromise(100) + + if (await condition()) { + return + } + + if (Date.now() - startTime > 5000) { + throw new Error('Timed out waiting on ' + description) + } + } +} + +exports.timeoutPromise = function (timeout) { + return new Promise(function (resolve) { + global.setTimeout(resolve, timeout) + }) +} + +function waitsForPromise (fn) { + const promise = fn() + global.waitsFor('spec promise to resolve', function (done) { + promise.then(done, function (error) { + jasmine.getEnv().currentSpec.fail(error) + done() + }) + }) +} diff --git a/packages/fuzzy-finder/spec/buffer-view-spec.js b/packages/fuzzy-finder/spec/buffer-view-spec.js new file mode 100644 index 0000000000..45a870eae1 --- /dev/null +++ b/packages/fuzzy-finder/spec/buffer-view-spec.js @@ -0,0 +1,31 @@ +const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') // eslint-disable-line no-unused-vars +const path = require('path') +const temp = require('temp').track() +const BufferView = require('../lib/buffer-view') + +describe('BufferView', () => { + it('shows the avatar for editors that are remote', async () => { + const bufferView = new BufferView({incrementCounter: () => {}}) + + const localEditor1 = await atom.workspace.open(path.join(temp.path(), 'a')) + const localEditor2 = await atom.workspace.open(path.join(temp.path(), 'b')) + const remoteEditor1 = await atom.workspace.open(path.join(temp.path(), 'c')) + remoteEditor1.getURI = () => 'remote1-uri' + const fakeTeletypeService = { + async getRemoteEditors () { + return [ + {uri: 'remote1-uri', path: 'remote1-path', hostGitHubUsername: 'user-1'}, + {uri: 'remote2-uri', path: 'remote2-path', hostGitHubUsername: 'user-2'} + ] + } + } + bufferView.setTeletypeService(fakeTeletypeService) + await bufferView.toggle() + + expect(bufferView.items).toEqual([ + {uri: localEditor1.getURI(), filePath: localEditor1.getPath(), label: localEditor1.getPath()}, + {uri: localEditor2.getURI(), filePath: localEditor2.getPath(), label: localEditor2.getPath()}, + {uri: 'remote1-uri', filePath: 'remote1-path', label: '@user-1: remote1-path', ownerGitHubUsername: 'user-1'} + ]) + }) +}) diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/dir/a b/packages/fuzzy-finder/spec/fixtures/root-dir1/dir/a new file mode 100644 index 0000000000..2c0809b9dc --- /dev/null +++ b/packages/fuzzy-finder/spec/fixtures/root-dir1/dir/a @@ -0,0 +1,3 @@ +aaa bbb +cc aa cc +dollar$bill diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/a.txt b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/a.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/dir/b.txt b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/dir/b.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/file.txt b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/file.txt new file mode 100644 index 0000000000..66dc9051da --- /dev/null +++ b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/file.txt @@ -0,0 +1 @@ +undefined \ No newline at end of file diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/HEAD b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/HEAD new file mode 100644 index 0000000000..cb089cd89a --- /dev/null +++ b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/config b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/config new file mode 100644 index 0000000000..af107929f2 --- /dev/null +++ b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/index b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/index new file mode 100644 index 0000000000..67a98bd9f0 Binary files /dev/null and b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/index differ diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/28/569d0a51e27dd112c0d4994c1e2914dd0db754 b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/28/569d0a51e27dd112c0d4994c1e2914dd0db754 new file mode 100644 index 0000000000..169ad87fa4 Binary files /dev/null and b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/28/569d0a51e27dd112c0d4994c1e2914dd0db754 differ diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7 b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7 new file mode 100644 index 0000000000..ba1f06fc0e Binary files /dev/null and b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7 differ diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/97/ff2919c02606bcad55588f3fa723b5a357470f b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/97/ff2919c02606bcad55588f3fa723b5a357470f new file mode 100644 index 0000000000..b6cb9859fd Binary files /dev/null and b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/97/ff2919c02606bcad55588f3fa723b5a357470f differ diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 new file mode 100644 index 0000000000..7112238943 Binary files /dev/null and b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 differ diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/ec/5e386905ff2d36e291086a1207f2585aaa8920 b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/ec/5e386905ff2d36e291086a1207f2585aaa8920 new file mode 100644 index 0000000000..4010ee8c26 Binary files /dev/null and b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/ec/5e386905ff2d36e291086a1207f2585aaa8920 differ diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1 b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1 new file mode 100644 index 0000000000..eaf6eeff30 Binary files /dev/null and b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1 differ diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/refs/heads/master b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/refs/heads/master new file mode 100644 index 0000000000..99d7260057 --- /dev/null +++ b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/git.git/refs/heads/master @@ -0,0 +1 @@ +97ff2919c02606bcad55588f3fa723b5a357470f diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/other.txt b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/other.txt new file mode 100644 index 0000000000..ffc8218bd2 --- /dev/null +++ b/packages/fuzzy-finder/spec/fixtures/root-dir1/git/working-dir/other.txt @@ -0,0 +1 @@ +Full of text \ No newline at end of file diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/sample.gif b/packages/fuzzy-finder/spec/fixtures/root-dir1/sample.gif new file mode 100755 index 0000000000..9935f82104 Binary files /dev/null and b/packages/fuzzy-finder/spec/fixtures/root-dir1/sample.gif differ diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/sample.js b/packages/fuzzy-finder/spec/fixtures/root-dir1/sample.js new file mode 100644 index 0000000000..fb33b0b43b --- /dev/null +++ b/packages/fuzzy-finder/spec/fixtures/root-dir1/sample.js @@ -0,0 +1,13 @@ +var quicksort = function () { + var sort = function(items) { + if (items.length <= 1) return items; + var pivot = items.shift(), current, left = [], right = []; + while(items.length > 0) { + current = items.shift(); + current < pivot ? left.push(current) : right.push(current); + } + return sort(left).concat(pivot).concat(sort(right)); + }; + + return sort(Array.apply(this, arguments)); +}; \ No newline at end of file diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir1/sample.txt b/packages/fuzzy-finder/spec/fixtures/root-dir1/sample.txt new file mode 100644 index 0000000000..3e715502b9 --- /dev/null +++ b/packages/fuzzy-finder/spec/fixtures/root-dir1/sample.txt @@ -0,0 +1 @@ +Some text. diff --git a/packages/fuzzy-finder/spec/fixtures/root-dir2/sample.html b/packages/fuzzy-finder/spec/fixtures/root-dir2/sample.html new file mode 100644 index 0000000000..138906e71b --- /dev/null +++ b/packages/fuzzy-finder/spec/fixtures/root-dir2/sample.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/packages/fuzzy-finder/spec/fuzzy-finder-spec.js b/packages/fuzzy-finder/spec/fuzzy-finder-spec.js new file mode 100644 index 0000000000..652f2434ac --- /dev/null +++ b/packages/fuzzy-finder/spec/fuzzy-finder-spec.js @@ -0,0 +1,1795 @@ +const net = require('net') +const path = require('path') +const _ = require('underscore-plus') +const etch = require('etch') +const fs = require('fs') +const os = require('os') +const sinon = require('sinon') +const temp = require('temp') +const wrench = require('wrench') + +const fuzzyFinderPackage = require('..') +const PathLoader = require('../lib/path-loader') +const DefaultFileIcons = require('../lib/default-file-icons') +const getIconServices = require('../lib/get-icon-services') +const {Disposable} = require('atom') + +const {it, fit, ffit, afterEach, beforeEach, conditionPromise} = require('./async-spec-helpers') // eslint-disable-line no-unused-vars + +function rmrf (_path) { + if (fs.statSync(_path).isDirectory()) { + _.each(fs.readdirSync(_path), (child) => rmrf(path.join(_path, child))) + fs.rmdirSync(_path) + } else { + fs.unlinkSync(_path) + } +} + +function getOrScheduleUpdatePromise () { + return new Promise((resolve) => etch.getScheduler().updateDocument(resolve)) +} + +const genPromiseToCheck = fn => new Promise(resolve => { + const interval = setInterval(() => { if(fn()) resolve() }, 100) + setTimeout(() => clearInterval(interval), 4000) +}) + +describe('FuzzyFinder', () => { + let disposable, reporterStub + let rootDir1, rootDir2 + let fuzzyFinder, projectView, bufferView, gitStatusView, workspaceElement, fixturesPath + const filesPromise = () => genPromiseToCheck( () => + gitStatusView?.element?.querySelectorAll('.file')?.length || + bufferView?.element?.querySelectorAll('.file')?.length || + projectView?.element?.querySelectorAll('.file')?.length + ) + + beforeEach(async () => { + reporterStub = { + addTiming: sinon.spy(), + incrementCounter: () => {} + } + disposable = fuzzyFinderPackage.consumeMetricsReporter(reporterStub) + + const ancestorDir = fs.realpathSync(temp.mkdirSync()) + rootDir1 = path.join(ancestorDir, 'root-dir1') + rootDir2 = path.join(ancestorDir, 'root-dir2') + + fixturesPath = atom.project.getPaths()[0] + + wrench.copyDirSyncRecursive( + path.join(fixturesPath, 'root-dir1'), + rootDir1, + {forceDelete: true} + ) + + wrench.copyDirSyncRecursive( + path.join(fixturesPath, 'root-dir2'), + rootDir2, + {forceDelete: true} + ) + + atom.project.setPaths([rootDir1, rootDir2]) + + workspaceElement = atom.views.getView(atom.workspace) + + await atom.workspace.open(path.join(rootDir1, 'sample.js')) + + const pack = await atom.packages.activatePackage('fuzzy-finder') + fuzzyFinder = pack.mainModule + bufferView = fuzzyFinder.createBufferView() + gitStatusView = fuzzyFinder.createGitStatusView() + + jasmine.useRealClock() + }) + + afterEach(() => { + if (disposable) { + disposable.dispose() + } + }) + + async function waitForPathsToDisplay (fuzzyFinderView) { + return conditionPromise(() => fuzzyFinderView.element.querySelectorAll('li').length > 0) + } + + async function waitForReCrawlerToFinish (fuzzyFinderView) { + return conditionPromise( + () => !fuzzyFinderView.element.querySelector('.loading .loading-message') + ) + } + + function waitForInitialCrawlerToFinish (fuzzyFinder) { + return new Promise( + resolve => fuzzyFinder.loadPathsTask.on('task:completed', () => resolve()) + ) + } + + function eachFilePath (dirPaths, fn) { + for (let dirPath of dirPaths) { + wrench.readdirSyncRecursive(dirPath).filter((filePath) => { + const fullPath = path.join(dirPath, filePath) + if (fs.statSync(fullPath).isFile()) { + fn(filePath) + } + }) + } + } + + function parseResults (elementContainer) { + return Array.from(elementContainer.querySelectorAll('li')).map( + element => ({ + label: element.querySelector('.primary-line').textContent, + description: element.querySelector('.secondary-line').textContent + }) + ) + } + + for (const useRipGrep of [true, false]) { + describe(`file-finder behavior (ripgrep=${useRipGrep})`, () => { + beforeEach(async () => { + projectView = fuzzyFinder.createProjectView() + + atom.config.set('fuzzy-finder.useRipGrep', useRipGrep) + sinon.stub(os, 'cpus').returns({length: 1}) + + await projectView.selectListView.update({maxResults: null}) + }) + + afterEach(() => { + os.cpus.restore() + }) + + describe('toggling', () => { + describe('when the project has multiple paths', () => { + it('shows or hides the fuzzy-finder and returns focus to the active editor if it is already showing', async () => { + jasmine.attachToDOM(workspaceElement) + + expect(atom.workspace.panelForItem(projectView)).toBeNull() + atom.workspace.getActivePane().splitRight({copyActiveItem: true}) + const [editor1, editor2] = atom.workspace.getTextEditors() + + await projectView.toggle() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(true) + expect(projectView.selectListView.refs.queryEditor.element).toHaveFocus() + projectView.selectListView.refs.queryEditor.insertText('this should not show up next time we toggle') + + await projectView.toggle() + + expect(atom.views.getView(editor1)).not.toHaveFocus() + expect(atom.views.getView(editor2)).toHaveFocus() + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(false) + + await projectView.toggle() + + expect(projectView.selectListView.refs.queryEditor.getText()).toBe('') + }) + + it('shows all files for the current project and selects the first', async () => { + jasmine.attachToDOM(workspaceElement) + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + eachFilePath([rootDir1, rootDir2], (filePath) => { + const item = Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes(filePath)) + expect(item).toExist() + const nameDiv = item.querySelector('div:first-child') + expect(nameDiv.dataset.name).toBe(path.basename(filePath)) + expect(nameDiv.textContent).toBe(path.basename(filePath)) + }) + + expect(projectView.element.querySelector('.loading')).not.toBeVisible() + }) + + it("shows each file's path, including which root directory it's in", async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + eachFilePath([rootDir1], (filePath) => { + const item = Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes(filePath)) + expect(item).toExist() + expect(item.querySelectorAll('div')[1].textContent).toBe(path.join(path.basename(rootDir1), filePath)) + }) + + eachFilePath([rootDir2], (filePath) => { + const item = Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes(filePath)) + expect(item).toExist() + expect(item.querySelectorAll('div')[1].textContent).toBe(path.join(path.basename(rootDir2), filePath)) + }) + }) + + it('only creates a single path loader task', async () => { + spyOn(PathLoader, 'startTask').andCallThrough() + + await projectView.toggle() // Show + + await projectView.toggle() // Hide + + await projectView.toggle() // Show again + + expect(PathLoader.startTask.callCount).toBe(1) + }) + + it('puts the last opened path first', async () => { + await atom.workspace.open('sample.txt') + await atom.workspace.open('sample.js') + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + const results = projectView.element.querySelectorAll('li') + + expect(results[0].textContent).toContain('sample.txt') + expect(results[results.length - 1].textContent).toContain('sample.html') + }) + + it('displays paths correctly if the last-opened path is not part of the project (regression)', async () => { + await atom.workspace.open('foo.txt') + await atom.workspace.open('sample.js') + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + }) + + describe('symlinks on #darwin or #linux', () => { + let junkDirPath, junkFilePath + + beforeEach(() => { + junkDirPath = fs.realpathSync(temp.mkdirSync('junk-1')) + junkFilePath = path.join(junkDirPath, 'file.txt') + fs.writeFileSync(junkFilePath, 'txt') + fs.writeFileSync(path.join(junkDirPath, 'a'), 'txt') + + const brokenFilePath = path.join(junkDirPath, 'delete.txt') + fs.writeFileSync(brokenFilePath, 'delete-me') + + fs.symlinkSync(junkFilePath, atom.project.getDirectories()[0].resolve('symlink-to-file')) + fs.symlinkSync(junkDirPath, atom.project.getDirectories()[0].resolve('symlink-to-dir')) + fs.symlinkSync(brokenFilePath, atom.project.getDirectories()[0].resolve('broken-symlink')) + + fs.symlinkSync(atom.project.getDirectories()[0].resolve('sample.txt'), atom.project.getDirectories()[0].resolve('symlink-to-internal-file')) + fs.symlinkSync(atom.project.getDirectories()[0].resolve('dir'), atom.project.getDirectories()[0].resolve('symlink-to-internal-dir')) + fs.symlinkSync(atom.project.getDirectories()[0].resolve('..'), atom.project.getDirectories()[0].resolve('symlink-to-project-dir-ancestor')) + + fs.unlinkSync(brokenFilePath) + }) + + it('indexes project paths that are symlinks', async () => { + const symlinkProjectPath = path.join(junkDirPath, 'root-dir-symlink') + fs.symlinkSync(atom.project.getPaths()[0], symlinkProjectPath) + + atom.project.setPaths([symlinkProjectPath]) + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('sample.txt'))).toBeDefined() + }) + + it('includes symlinked file paths', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + const results = Array.from(projectView.element.querySelectorAll('li')) + const sourceSymlink = results.find(a => a.textContent.includes('symlink-to-internal-file')) + const destSymlink = results.find(a => a.textContent.includes('symlink-to-file')) + + expect(destSymlink).toBeDefined() + + // The behaviour when ripgrep is enabled is slightly different. + if (useRipGrep) { + expect(sourceSymlink).toBeDefined() + } else { + expect(sourceSymlink).not.toBeDefined() + } + }) + + it('excludes symlinked folder paths if followSymlinks is false', async () => { + atom.config.set('core.followSymlinks', false) + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + const results = Array.from(projectView.element.querySelectorAll('li')) + + expect(results.find(a => a.textContent.includes('symlink-to-dir'))).not.toBeDefined() + expect(results.find(a => a.textContent.includes('symlink-to-dir/a'))).not.toBeDefined() + expect(results.find(a => a.textContent.includes('symlink-to-internal-dir'))).not.toBeDefined() + expect(results.find(a => a.textContent.includes('symlink-to-internal-dir/a'))).not.toBeDefined() + }) + + it('includes symlinked folder paths if followSymlinks is true', async () => { + atom.config.set('core.followSymlinks', true) + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + const results = Array.from(projectView.element.querySelectorAll('li')) + const sourceSymlink = results.find(a => a.textContent.includes('symlink-to-internal-dir/a')) + const destSymlink = results.find(a => a.textContent.includes('symlink-to-dir/a')) + + expect(destSymlink).toBeDefined() + + // The behaviour when ripgrep is enabled is slightly different. + if (useRipGrep) { + expect(sourceSymlink).toBeDefined() + } else { + expect(sourceSymlink).not.toBeDefined() + } + }) + }) + + describe('socket files on #darwin or #linux', () => { + let socketServer, socketPath + + beforeEach(() => new Promise((resolve, reject) => { + socketServer = net.createServer(() => {}) + socketPath = path.join(rootDir1, 'some.sock') + socketServer.on('listening', resolve) + socketServer.on('error', reject) + socketServer.listen(socketPath) + })) + + afterEach(() => new Promise(resolve => socketServer.close(resolve))) + + it('does not interfere with ability to load files', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('a'))).toBeDefined() + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('some.sock'))).not.toBeDefined() + }) + }) + + it('ignores paths that match entries in config.fuzzy-finder.ignoredNames', async () => { + atom.config.set('fuzzy-finder.ignoredNames', ['sample.js', '*.txt']) + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('sample.js'))).not.toBeDefined() + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('sample.txt'))).not.toBeDefined() + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('a'))).toBeDefined() + }) + + it("only shows a given path once, even if it's within multiple root folders", async () => { + const childDir1 = path.join(rootDir1, 'a-child') + const childFile1 = path.join(childDir1, 'child-file.txt') + fs.mkdirSync(childDir1) + fs.writeFileSync(childFile1, 'stuff') + atom.project.addPath(childDir1) + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(Array.from(projectView.element.querySelectorAll('li')).filter(a => a.textContent.includes('child-file.txt')).length).toBe(1) + }) + + it('returns all the results if they have the same relative path across multiple root folders', async () => { + fs.writeFileSync(path.join(rootDir1, 'whatever.js'), 'stuff') + fs.writeFileSync(path.join(rootDir2, 'whatever.js'), 'stuff') + + await projectView.toggle() + await waitForPathsToDisplay(projectView) + + await projectView.selectListView.refs.queryEditor.setText('whatever.js') + await getOrScheduleUpdatePromise() + + // Sort results by path to ensure test is deterministic + const results = parseResults(projectView.element) + .sort((a, b) => a.description.localeCompare(b.description)) + expect(results).toEqual([ + {label: 'whatever.js', description: path.join('root-dir1', 'whatever.js')}, + {label: 'whatever.js', description: path.join('root-dir2', 'whatever.js')} + ]) + }) + + it('returns all the results if they have the same relative path across multiple root folders with the same name', async () => { + const ancestorDir = fs.realpathSync(temp.mkdirSync()) + const rootDir3 = path.join(ancestorDir, 'root-dir1') + fs.mkdirSync(rootDir3) + + fs.writeFileSync(path.join(rootDir1, 'whatever.js'), 'stuff') + fs.writeFileSync(path.join(rootDir3, 'whatever.js'), 'stuff') + + atom.project.addPath(rootDir3) + + await projectView.toggle() + await waitForPathsToDisplay(projectView) + + await projectView.selectListView.refs.queryEditor.setText('whatever.js') + await getOrScheduleUpdatePromise() + + expect(parseResults(projectView.element)).toEqual([ + {label: 'whatever.js', description: path.join('root-dir1', 'whatever.js')}, + {label: 'whatever.js', description: path.join('root-dir1', 'whatever.js')} + ]) + }) + }) + + describe('when the project only has one path', () => { + beforeEach(() => atom.project.setPaths([rootDir1])) + + it("doesn't show the name of each file's root directory", async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + const items = Array.from(projectView.element.querySelectorAll('li')) + eachFilePath([rootDir1], (filePath) => { + const item = items.find(a => a.textContent.includes(filePath)) + expect(item).toExist() + expect(item).not.toHaveText(path.basename(rootDir1)) + }) + }) + }) + + describe('when the project has no path', () => { + beforeEach(() => { + jasmine.attachToDOM(workspaceElement) + atom.project.setPaths([]) + }) + + it('shows an empty message with no files in the list', async () => { + await projectView.toggle() + + expect(projectView.selectListView.refs.emptyMessage).toBeVisible() + expect(projectView.selectListView.refs.emptyMessage.textContent).toBe('Project is empty') + expect(projectView.element.querySelectorAll('li').length).toBe(0) + }) + }) + }) + + describe("when a project's root path is unlinked", () => { + beforeEach(() => { + if (fs.existsSync(rootDir1)) { rmrf(rootDir1) } + if (fs.existsSync(rootDir2)) { rmrf(rootDir2) } + }) + + it('posts an error notification', async () => { + spyOn(atom.notifications, 'addError') + await projectView.toggle() + + await conditionPromise(() => atom.workspace.panelForItem(projectView).isVisible()) + expect(atom.notifications.addError).toHaveBeenCalled() + }) + }) + + describe('when a path selection is confirmed', () => { + it('opens the file associated with that path in that split', async () => { + jasmine.attachToDOM(workspaceElement) + const editor1 = atom.workspace.getActiveTextEditor() + atom.workspace.getActivePane().splitRight({copyActiveItem: true}) + const editor2 = atom.workspace.getActiveTextEditor() + const expectedPath = atom.project.getDirectories()[0].resolve('dir/a') + + await projectView.toggle() + + projectView.confirm({uri: expectedPath}) + + await conditionPromise(() => atom.workspace.getActivePane().getItems().length === 2) + + const editor3 = atom.workspace.getActiveTextEditor() + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(false) + expect(editor1.getPath()).not.toBe(expectedPath) + expect(editor2.getPath()).not.toBe(expectedPath) + expect(editor3.getPath()).toBe(expectedPath) + expect(atom.views.getView(editor3)).toHaveFocus() + }) + + describe('when the selected path is a directory', () => + it("leaves the the tree view open, doesn't open the path in the editor, and displays an error", async () => { + jasmine.attachToDOM(workspaceElement) + const editorPath = atom.workspace.getActiveTextEditor().getPath() + await projectView.toggle() + + projectView.confirm({uri: atom.project.getDirectories()[0].resolve('dir')}) + expect(projectView.element.parentElement).toBeDefined() + expect(atom.workspace.getActiveTextEditor().getPath()).toBe(editorPath) + + await conditionPromise(() => projectView.selectListView.refs.errorMessage) + + jasmine.useMockClock() + + advanceClock(2000) + + await conditionPromise(() => !projectView.selectListView.refs.errorMessage) + }) + ) + }) + + describe('buffer-finder behavior', () => { + describe('toggling', () => { + describe('when there are pane items with paths', () => { + beforeEach(async () => { + jasmine.attachToDOM(workspaceElement) + + await atom.workspace.open('sample.txt') + }) + + it("shows the FuzzyFinder if it isn't showing, or hides it and returns focus to the active editor", async () => { + expect(atom.workspace.panelForItem(bufferView)).toBeNull() + atom.workspace.getActivePane().splitRight({copyActiveItem: true}) + const [editor1, editor2, editor3] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + expect(atom.workspace.getActivePaneItem()).toBe(editor3) + + expect(atom.views.getView(editor3)).toHaveFocus() + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + expect(workspaceElement.querySelector('.fuzzy-finder')).toHaveFocus() + bufferView.selectListView.refs.queryEditor.insertText('this should not show up next time we toggle') + + await bufferView.toggle() + + expect(atom.views.getView(editor3)).toHaveFocus() + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(false) + + await bufferView.toggle() + + expect(bufferView.selectListView.refs.queryEditor.getText()).toBe('') + }) + + it('lists the paths of the current items, sorted by most recently opened but with the current item last', async () => { + await atom.workspace.open('sample-with-tabs.coffee') + + bufferView.toggle() + await filesPromise() + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + expect([...bufferView.element.querySelectorAll('li > div.file')] + .map(e => e.textContent)) + .toEqual(['sample.txt', 'sample.js', 'sample-with-tabs.coffee']) + + await bufferView.toggle() + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(false) + + await atom.workspace.open('sample.txt') + bufferView.toggle() + await genPromiseToCheck(() => + bufferView?.element?.querySelector('li > div.file') + ?.innerText?.match(/sample-with-tabs/) + ) + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + expect([...bufferView.element.querySelectorAll('li > div.file')] + .map(e => e.textContent)) + .toEqual(['sample-with-tabs.coffee', 'sample.js', 'sample.txt']) + expect(bufferView.element.querySelector('li')).toHaveClass('selected') + }) + + it('serializes the list of paths and their last opened time', async () => { + await atom.workspace.open('sample-with-tabs.coffee') + await bufferView.toggle() + await atom.workspace.open('sample.js') + await bufferView.toggle() + await atom.workspace.open() + await atom.packages.deactivatePackage('fuzzy-finder') + + let states = _.map(atom.packages.getPackageState('fuzzy-finder'), (path, time) => [path, time]) + expect(states.length).toBe(3) + states = _.sortBy(states, (path, time) => -time) + + const paths = ['sample-with-tabs.coffee', 'sample.txt', 'sample.js'] + for (let [time, bufferPath] of states) { + expect(_.last(bufferPath.split(path.sep))).toBe(paths.shift()) + expect(time).toBeGreaterThan(50000) + } + }) + }) + + describe('when there are only panes with anonymous items', () => + it('does not open', async () => { + atom.workspace.getActivePane().destroy() + await atom.workspace.open() + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView)).toBeNull() + }) + ) + + describe('when there are no pane items', () => + it('does not open', async () => { + atom.workspace.getActivePane().destroy() + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView)).toBeNull() + }) + ) + + describe('when multiple sessions are opened on the same path', () => + it('does not display duplicates for that path in the list', async () => { + await atom.workspace.open('sample.js') + + atom.workspace.getActivePane().splitRight({copyActiveItem: true}) + + bufferView.toggle() + await filesPromise() + expect(Array.from(bufferView.element.querySelectorAll('li > div.file')).map(e => e.textContent)).toEqual(['sample.js']) + }) + ) + }) + + describe('when a path selection is confirmed', () => { + let editor1, editor2, editor3 + + beforeEach(async () => { + jasmine.attachToDOM(workspaceElement) + atom.workspace.getActivePane().splitRight({copyActiveItem: true}) + + await atom.workspace.open('sample.txt'); + + [editor1, editor2, editor3] = atom.workspace.getTextEditors() + + expect(atom.workspace.getActiveTextEditor()).toBe(editor3) + + atom.commands.dispatch(atom.views.getView(editor2), 'pane:show-previous-item') + + await bufferView.toggle() + }) + + describe('when the active pane has an item for the selected path', () => + it('switches to the item for the selected path', async () => { + const expectedPath = atom.project.getDirectories()[0].resolve('sample.txt') + bufferView.confirm({uri: expectedPath}) + + await conditionPromise(() => atom.workspace.getActiveTextEditor().getPath() === expectedPath) + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(false) + expect(editor1.getPath()).not.toBe(expectedPath) + expect(editor2.getPath()).not.toBe(expectedPath) + expect(editor3.getPath()).toBe(expectedPath) + expect(atom.views.getView(editor3)).toHaveFocus() + }) + ) + + describe('when the active pane does not have an item for the selected path and fuzzy-finder.searchAllPanes is false', () => + it('adds a new item to the active pane for the selected path', async () => { + const expectedPath = atom.project.getDirectories()[0].resolve('sample.txt') + + await bufferView.toggle() + + atom.views.getView(editor1).focus() + + await bufferView.toggle() + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + bufferView.confirm({uri: expectedPath}, atom.config.get('fuzzy-finder.searchAllPanes')) + + await conditionPromise(() => atom.workspace.getActivePane().getItems().length === 2) + + const editor4 = atom.workspace.getActiveTextEditor() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(false) + + expect(editor4).not.toBe(editor1) + expect(editor4).not.toBe(editor2) + expect(editor4).not.toBe(editor3) + + expect(editor4.getPath()).toBe(expectedPath) + expect(atom.views.getView(editor4)).toHaveFocus() + }) + ) + + describe('when the active pane does not have an item for the selected path and fuzzy-finder.searchAllPanes is true', () => { + beforeEach(() => atom.config.set('fuzzy-finder.searchAllPanes', true)) + + it('switches to the pane with the item for the selected path', async () => { + const expectedPath = atom.project.getDirectories()[0].resolve('sample.txt') + let originalPane = null + + await bufferView.toggle() + + atom.views.getView(editor1).focus() + originalPane = atom.workspace.getActivePane() + + await bufferView.toggle() + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + bufferView.confirm({uri: expectedPath}, {searchAllPanes: atom.config.get('fuzzy-finder.searchAllPanes')}) + + await conditionPromise(() => atom.workspace.getActiveTextEditor().getPath() === expectedPath) + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(false) + expect(atom.workspace.getActivePane()).not.toBe(originalPane) + expect(atom.workspace.getActiveTextEditor()).toBe(editor3) + expect(atom.workspace.getPaneItems().length).toBe(3) + }) + }) + }) + }) + + describe('common behavior between file and buffer finder', () => + describe('when the fuzzy finder is cancelled', () => { + describe('when an editor is open', () => + it('detaches the finder and focuses the previously focused element', async () => { + jasmine.attachToDOM(workspaceElement) + const activeEditor = atom.workspace.getActiveTextEditor() + + await projectView.toggle() + + expect(projectView.element.parentElement).toBeDefined() + expect(projectView.selectListView.refs.queryEditor.element).toHaveFocus() + + projectView.cancel() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(false) + expect(atom.views.getView(activeEditor)).toHaveFocus() + }) + ) + + describe('when no editors are open', () => + it('detaches the finder and focuses the previously focused element', async () => { + jasmine.attachToDOM(workspaceElement) + atom.workspace.getActivePane().destroy() + + const inputView = document.createElement('input') + workspaceElement.appendChild(inputView) + inputView.focus() + + await projectView.toggle() + + expect(projectView.element.parentElement).toBeDefined() + expect(projectView.selectListView.refs.queryEditor.element).toHaveFocus() + projectView.cancel() + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(false) + expect(inputView).toHaveFocus() + }) + ) + }) + ) + + describe('cached file paths', () => { + beforeEach(() => { + spyOn(PathLoader, 'startTask').andCallThrough() + spyOn(atom.workspace, 'getTextEditors').andCallThrough() + }) + + it('caches file paths after first time', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(PathLoader.startTask).toHaveBeenCalled() + PathLoader.startTask.reset() + + await projectView.toggle() + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(PathLoader.startTask).not.toHaveBeenCalled() + }) + + it("doesn't cache buffer paths", async () => { + await bufferView.toggle() + + await waitForPathsToDisplay(bufferView) + + expect(atom.workspace.getTextEditors).toHaveBeenCalled() + atom.workspace.getTextEditors.reset() + + await bufferView.toggle() + + await bufferView.toggle() + + await waitForPathsToDisplay(bufferView) + + expect(atom.workspace.getTextEditors).toHaveBeenCalled() + }) + + it('busts the cache when the window gains focus', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(PathLoader.startTask).toHaveBeenCalled() + PathLoader.startTask.reset() + window.dispatchEvent(new CustomEvent('focus')) + await projectView.toggle() + + await projectView.toggle() + + expect(PathLoader.startTask).toHaveBeenCalled() + }) + + it('busts the cache when the project path changes', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(PathLoader.startTask).toHaveBeenCalled() + PathLoader.startTask.reset() + atom.project.setPaths([temp.mkdirSync('atom')]) + + await projectView.toggle() + + await projectView.toggle() + + expect(PathLoader.startTask).toHaveBeenCalled() + + await waitForReCrawlerToFinish(projectView) + + expect(projectView.element.querySelectorAll('li').length).toBe(0) + }) + + describe('the initial load paths task started during package activation', () => { + beforeEach(async () => { + fuzzyFinder.projectView.destroy() + fuzzyFinder.projectView = null + fuzzyFinder.startLoadPathsTask() + + await conditionPromise(() => fuzzyFinder.projectPaths) + }) + + it('passes the indexed paths into the project view when it is created', () => { + const {projectPaths} = fuzzyFinder + expect(projectPaths.length).toBe(19) + projectView = fuzzyFinder.createProjectView() + expect(projectView.paths).toBe(projectPaths) + expect(projectView.reloadPaths).toBe(false) + }) + + it('busts the cached paths when the project paths change', () => { + atom.project.setPaths([]) + + const {projectPaths} = fuzzyFinder + expect(projectPaths).toBe(null) + + projectView = fuzzyFinder.createProjectView() + expect(projectView.paths).toBe(null) + expect(projectView.reloadPaths).toBe(true) + }) + }) + }) + + describe('opening a path into a split', () => { + it('opens the path by splitting the active editor left', async () => { + expect(atom.workspace.getCenter().getPanes().length).toBe(1) + let filePath = null + + await bufferView.toggle(); + + ({filePath} = bufferView.selectListView.getSelectedItem()) + atom.commands.dispatch(bufferView.element, 'pane:split-left') + + await conditionPromise(() => atom.workspace.getCenter().getPanes().length === 2) + + await conditionPromise(() => atom.workspace.getActiveTextEditor()) + + const [leftPane, rightPane] = atom.workspace.getCenter().getPanes() // eslint-disable-line no-unused-vars + expect(atom.workspace.getActivePane()).toBe(leftPane) + expect(atom.workspace.getActiveTextEditor().getPath()).toBe(atom.project.getDirectories()[0].resolve(filePath)) + }) + + it('opens the path by splitting the active editor right', async () => { + expect(atom.workspace.getCenter().getPanes().length).toBe(1) + let filePath = null + + await bufferView.toggle(); + + ({filePath} = bufferView.selectListView.getSelectedItem()) + atom.commands.dispatch(bufferView.element, 'pane:split-right') + + await conditionPromise(() => atom.workspace.getCenter().getPanes().length === 2) + + await conditionPromise(() => atom.workspace.getActiveTextEditor()) + + const [leftPane, rightPane] = atom.workspace.getCenter().getPanes() // eslint-disable-line no-unused-vars + expect(atom.workspace.getActivePane()).toBe(rightPane) + expect(atom.workspace.getActiveTextEditor().getPath()).toBe(atom.project.getDirectories()[0].resolve(filePath)) + }) + + it('opens the path by splitting the active editor up', async () => { + expect(atom.workspace.getCenter().getPanes().length).toBe(1) + let filePath = null + + await bufferView.toggle(); + + ({filePath} = bufferView.selectListView.getSelectedItem()) + atom.commands.dispatch(bufferView.element, 'pane:split-up') + + await conditionPromise(() => atom.workspace.getCenter().getPanes().length === 2) + + await conditionPromise(() => atom.workspace.getActiveTextEditor()) + + const [topPane, bottomPane] = atom.workspace.getCenter().getPanes() // eslint-disable-line no-unused-vars + expect(atom.workspace.getActivePane()).toBe(topPane) + expect(atom.workspace.getActiveTextEditor().getPath()).toBe(atom.project.getDirectories()[0].resolve(filePath)) + }) + + it('opens the path by splitting the active editor down', async () => { + expect(atom.workspace.getCenter().getPanes().length).toBe(1) + let filePath = null + + await bufferView.toggle(); + + ({filePath} = bufferView.selectListView.getSelectedItem()) + atom.commands.dispatch(bufferView.element, 'pane:split-down') + + await conditionPromise(() => atom.workspace.getCenter().getPanes().length === 2) + + await conditionPromise(() => atom.workspace.getActiveTextEditor()) + + const [topPane, bottomPane] = atom.workspace.getCenter().getPanes() // eslint-disable-line no-unused-vars + expect(atom.workspace.getActivePane()).toBe(bottomPane) + expect(atom.workspace.getActiveTextEditor().getPath()).toBe(atom.project.getDirectories()[0].resolve(filePath)) + }) + }) + + describe('when the query contains a colon', () => { + beforeEach(async () => { + jasmine.attachToDOM(workspaceElement) + expect(atom.workspace.panelForItem(projectView)).toBeNull() + + await atom.workspace.open('sample.txt') + + const [editor1, editor2] = atom.workspace.getTextEditors() + editor1.setCursorBufferPosition([8, 3]) + expect(atom.workspace.getActiveTextEditor()).toBe(editor2) + expect(editor1.getCursorBufferPosition()).toEqual([8, 3]) + }) + + describe('when the colon is followed by numbers', () => { + describe('when the numbers are not followed by another colon', () => { + describe('when the filter text has a file path', () => { + it('opens the selected path to that line number', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.setText('sample.js:4') + + await getOrScheduleUpdatePromise() + + const {filePath} = bufferView.selectListView.getSelectedItem() + expect(atom.project.getDirectories()[0].resolve(filePath)).toBe(editor1.getPath()) + + spyOn(bufferView, 'moveToCaretPosition').andCallThrough() + atom.commands.dispatch(bufferView.element, 'core:confirm') + + await conditionPromise(() => bufferView.moveToCaretPosition.callCount > 0) + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + expect(editor1.getCursorBufferPosition()).toEqual([3, 4]) + }) + }) + + describe("when the filter text doesn't have a file path", () => { + it('moves the cursor in the active editor to that line number', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + await atom.workspace.open('sample.js') + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.insertText(':4') + + await getOrScheduleUpdatePromise() + + expect(bufferView.element.querySelectorAll('li').length).toBe(0) + spyOn(bufferView, 'moveToCaretPosition').andCallThrough() + atom.commands.dispatch(bufferView.element, 'core:confirm') + + await conditionPromise(() => bufferView.moveToCaretPosition.callCount > 0) + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + expect(editor1.getCursorBufferPosition()).toEqual([3, 4]) + }) + }) + }) + + describe('when the numbers are followed by another colon', () => { + describe('when the colon is followed by more numbers', () => { + describe('when the filter text has a file path', () => { + it('opens the selected path to that line number and column', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.setText('sample.js:4:6') + + await getOrScheduleUpdatePromise() + + const {filePath} = bufferView.selectListView.getSelectedItem() + expect(atom.project.getDirectories()[0].resolve(filePath)).toBe(editor1.getPath()) + + spyOn(bufferView, 'moveToCaretPosition').andCallThrough() + atom.commands.dispatch(bufferView.element, 'core:confirm') + + await conditionPromise(() => bufferView.moveToCaretPosition.callCount > 0) + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + expect(editor1.getCursorBufferPosition()).toEqual([3, 6]) + }) + }) + + describe("when the filter text doesn't have a file path", () => { + it('moves the cursor in the active editor to that line number and column', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + await atom.workspace.open('sample.js') + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.insertText(':4:6') + + await getOrScheduleUpdatePromise() + + expect(bufferView.selectListView.refs.emptyMessage.innerText).toEqual( + 'Jump to line and column in active editor' + ) + expect(bufferView.element.querySelectorAll('li').length).toBe(0) + spyOn(bufferView, 'moveToCaretPosition').andCallThrough() + atom.commands.dispatch(bufferView.element, 'core:confirm') + + await conditionPromise(() => bufferView.moveToCaretPosition.callCount > 0) + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + expect(editor1.getCursorBufferPosition()).toEqual([3, 6]) + }) + }) + }) + + describe('when the colon is not followed by more numbers', () => { + describe('when the filter text has a file path', () => { + it('opens the file, jumps to the first character of the line and does not throw an error', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.setText('sample.js:5:a') + + await getOrScheduleUpdatePromise() + + const {filePath} = bufferView.selectListView.getSelectedItem() + expect(atom.project.getDirectories()[0].resolve(filePath)).toBe(editor1.getPath()) + + spyOn(bufferView, 'moveToCaretPosition').andCallThrough() + atom.commands.dispatch(bufferView.element, 'core:confirm') + + await conditionPromise(() => bufferView.moveToCaretPosition.callCount > 0) + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + expect(editor1.getCursorBufferPosition()).toEqual([4, 4]) + }) + }) + + describe("when the filter text doesn't have a file path", () => { + it('jumps to the first character of the line and does not throw an error', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + await atom.workspace.open('sample.js') + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.setText(':5:a') + + await getOrScheduleUpdatePromise() + + spyOn(bufferView, 'moveToCaretPosition').andCallThrough() + atom.commands.dispatch(bufferView.element, 'core:confirm') + + await conditionPromise(() => bufferView.moveToCaretPosition.callCount > 0) + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + expect(editor1.getCursorBufferPosition()).toEqual([4, 4]) + }) + }) + }) + }) + }) + + describe('when the colon is not followed by numbers', () => { + describe('when the filter text has a file path', () => { + it('opens the file and does not throw an error', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.setText('sample.js:a') + + await getOrScheduleUpdatePromise() + + const {filePath} = bufferView.selectListView.getSelectedItem() + expect(atom.project.getDirectories()[0].resolve(filePath)).toBe(editor1.getPath()) + + spyOn(bufferView, 'moveToCaretPosition').andCallThrough() + atom.commands.dispatch(bufferView.element, 'core:confirm') + + await conditionPromise(() => bufferView.moveToCaretPosition.callCount > 0) + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + expect(editor1.getCursorBufferPosition()).toEqual([8, 3]) + }) + }) + + describe("when the filter text doesn't have a file path", () => { + it('shows an error and does not move the cursor', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + await atom.workspace.open('sample.js') + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.setText('::') + + await getOrScheduleUpdatePromise() + + expect(bufferView.selectListView.refs.errorMessage.innerText).toEqual('Invalid line number') + + expect(bufferView.element.querySelectorAll('li').length).toBe(0) + spyOn(bufferView, 'moveToCaretPosition').andCallThrough() + atom.commands.dispatch(bufferView.element, 'core:confirm') + + await conditionPromise(() => bufferView.moveToCaretPosition.callCount > 0) + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + expect(editor1.getCursorBufferPosition()).toEqual([8, 3]) + }) + + it('updates the message when the error gets resolved', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + const emptyMessage = 'Jump to line in active editor' + const errorMessage = 'Invalid line number' + + await atom.workspace.open('sample.js') + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + + bufferView.selectListView.refs.queryEditor.setText(':42') + await getOrScheduleUpdatePromise() + expect(bufferView.selectListView.refs.emptyMessage.innerText).toEqual(emptyMessage) + expect(bufferView.selectListView.refs.errorMessage).toBeUndefined() + + bufferView.selectListView.refs.queryEditor.setText(':42a') + await getOrScheduleUpdatePromise() + expect(bufferView.selectListView.refs.emptyMessage).toBeUndefined() + expect(bufferView.selectListView.refs.errorMessage.innerText).toEqual(errorMessage) + + bufferView.selectListView.refs.queryEditor.setText(':42') + await getOrScheduleUpdatePromise() + expect(bufferView.selectListView.refs.emptyMessage.innerText).toEqual(emptyMessage) + expect(bufferView.selectListView.refs.errorMessage).toBeUndefined() + }) + + it('shows a specific error message when the column is invalid', async () => { + const [editor1] = atom.workspace.getTextEditors() + const errorMessage = 'Invalid column number' + + await atom.workspace.open('sample.js') + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + + bufferView.selectListView.refs.queryEditor.setText(':42:12a') + await getOrScheduleUpdatePromise() + expect(bufferView.selectListView.refs.emptyMessage).toBeUndefined() + expect(bufferView.selectListView.refs.errorMessage.innerText).toEqual(errorMessage) + }) + + it('shows a more specific message when jumping to line and column', async () => { + const [editor1] = atom.workspace.getTextEditors() + const emptyColumnMessage = 'Jump to line and column in active editor' + + await atom.workspace.open('sample.js') + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + + bufferView.selectListView.refs.queryEditor.setText(':42:') + await getOrScheduleUpdatePromise() + expect(bufferView.selectListView.refs.emptyMessage.innerText).toEqual(emptyColumnMessage) + + bufferView.selectListView.refs.queryEditor.setText(':42:12') + await getOrScheduleUpdatePromise() + expect(bufferView.selectListView.refs.emptyMessage.innerText).toEqual(emptyColumnMessage) + }) + }) + }) + }) + + describe('match highlighting', () => { + beforeEach(async () => { + jasmine.attachToDOM(workspaceElement) + await bufferView.toggle() + }) + + it('highlights an exact match', async () => { + bufferView.selectListView.refs.queryEditor.setText('sample.js') + + await getOrScheduleUpdatePromise() + + const resultView = bufferView.element.querySelector('li') + const primaryMatches = resultView.querySelectorAll('.primary-line .character-match') + const secondaryMatches = resultView.querySelectorAll('.secondary-line .character-match') + expect(primaryMatches.length).toBe(1) + expect(primaryMatches[primaryMatches.length - 1].textContent).toBe('sample.js') + // Use `toBeGreaterThan` because dir may have some characters in it + expect(secondaryMatches.length).toBeGreaterThan(0) + expect(secondaryMatches[secondaryMatches.length - 1].textContent).toBe('sample.js') + }) + + it('highlights a partial match', async () => { + bufferView.selectListView.refs.queryEditor.setText('sample') + + await getOrScheduleUpdatePromise() + + const resultView = bufferView.element.querySelector('li') + const primaryMatches = resultView.querySelectorAll('.primary-line .character-match') + const secondaryMatches = resultView.querySelectorAll('.secondary-line .character-match') + expect(primaryMatches.length).toBe(1) + expect(primaryMatches[primaryMatches.length - 1].textContent).toBe('sample') + // Use `toBeGreaterThan` because dir may have some characters in it + expect(secondaryMatches.length).toBeGreaterThan(0) + expect(secondaryMatches[secondaryMatches.length - 1].textContent).toBe('sample') + }) + + it('highlights multiple matches in the file name', async () => { + bufferView.selectListView.refs.queryEditor.setText('samplejs') + + await getOrScheduleUpdatePromise() + + const resultView = bufferView.element.querySelector('li') + const primaryMatches = resultView.querySelectorAll('.primary-line .character-match') + const secondaryMatches = resultView.querySelectorAll('.secondary-line .character-match') + expect(primaryMatches.length).toBe(2) + expect(primaryMatches[0].textContent).toBe('sample') + expect(primaryMatches[primaryMatches.length - 1].textContent).toBe('js') + // Use `toBeGreaterThan` because dir may have some characters in it + expect(secondaryMatches.length).toBeGreaterThan(1) + expect(secondaryMatches[secondaryMatches.length - 1].textContent).toBe('js') + }) + + it('highlights matches in the directory and file name', async () => { + spyOn(bufferView, 'projectRelativePathsForFilePaths').andCallFake((paths) => paths) + bufferView.selectListView.refs.queryEditor.setText('root-dirsample') + + await bufferView.setItems([ + { + filePath: path.join('test', 'root-dir1', 'sample.js'), + label: path.join('root-dir1', 'sample.js') + } + ]) + + await filesPromise() + const resultView = bufferView.element.querySelector('li') + const primaryMatches = resultView.querySelectorAll('.primary-line .character-match') + const secondaryMatches = resultView.querySelectorAll('.secondary-line .character-match') + expect(primaryMatches.length).toBe(1) + expect(primaryMatches[primaryMatches.length - 1].textContent).toBe('sample') + expect(secondaryMatches.length).toBe(2) + expect(secondaryMatches[0].textContent).toBe('root-dir') + expect(secondaryMatches[secondaryMatches.length - 1].textContent).toBe('sample') + }) + + describe('when splitting panes', () => { + it('opens the selected path to that line number in a new pane', async () => { + const [editor1, editor2] = atom.workspace.getTextEditors() // eslint-disable-line no-unused-vars + + await atom.workspace.open('sample.js') + + expect(atom.workspace.getActiveTextEditor()).toBe(editor1) + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.insertText(':4') + + await getOrScheduleUpdatePromise() + + expect(bufferView.element.querySelectorAll('li').length).toBe(0) + spyOn(bufferView, 'moveToCaretPosition').andCallThrough() + atom.commands.dispatch(bufferView.element, 'pane:split-left') + + await conditionPromise(() => bufferView.moveToCaretPosition.callCount > 0) + + expect(atom.workspace.getActiveTextEditor()).not.toBe(editor1) + expect(atom.workspace.getActiveTextEditor().getPath()).toBe(editor1.getPath()) + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([3, 4]) + }) + }) + }) + + describe('preserve last search', () => { + it('does not preserve last search by default', async () => { + await projectView.toggle() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.insertText('this should not show up next time we open finder') + + await projectView.toggle() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(false) + + await projectView.toggle() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(true) + expect(projectView.selectListView.getQuery()).toBe('') + }) + + it('preserves last search when the config is set', async () => { + atom.config.set('fuzzy-finder.preserveLastSearch', true) + + await projectView.toggle() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(true) + projectView.selectListView.refs.queryEditor.insertText('this should show up next time we open finder') + + await projectView.toggle() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(false) + + await projectView.toggle() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(true) + expect(projectView.selectListView.getQuery()).toBe('this should show up next time we open finder') + expect(projectView.selectListView.refs.queryEditor.getSelectedText()).toBe('this should show up next time we open finder') + }) + }) + + describe('prefill query from selection', () => { + it('should not be enabled by default', async () => { + await atom.workspace.open() + + atom.workspace.getActiveTextEditor().setText('sample.txt') + atom.workspace.getActiveTextEditor().setSelectedBufferRange([[0, 0], [0, 10]]) + expect(atom.workspace.getActiveTextEditor().getSelectedText()).toBe('sample.txt') + + await projectView.toggle() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(true) + expect(projectView.selectListView.getQuery()).toBe('') + expect(projectView.selectListView.refs.queryEditor.getSelectedText()).toBe('') + }) + + it('takes selection from active editor and prefills query with it', async () => { + atom.config.set('fuzzy-finder.prefillFromSelection', true) + + await atom.workspace.open() + + atom.workspace.getActiveTextEditor().setText('sample.txt') + atom.workspace.getActiveTextEditor().setSelectedBufferRange([[0, 0], [0, 10]]) + expect(atom.workspace.getActiveTextEditor().getSelectedText()).toBe('sample.txt') + + await projectView.toggle() + + expect(atom.workspace.panelForItem(projectView).isVisible()).toBe(true) + expect(projectView.selectListView.getQuery()).toBe('sample.txt') + expect(projectView.selectListView.refs.queryEditor.getSelectedText()).toBe('sample.txt') + }) + }) + + describe('default file icons', () => { + it('shows a text icon for text-based formats', async () => { + await atom.workspace.open('sample.js') + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.insertText('js') + + await getOrScheduleUpdatePromise() + + const firstResult = bufferView.element.querySelector('li .primary-line') + expect(DefaultFileIcons.iconClassForPath(firstResult.dataset.path)).toBe('icon-file-text') + }) + + it('shows an image icon for graphic formats', async () => { + await atom.workspace.open('sample.gif') + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.insertText('gif') + + await getOrScheduleUpdatePromise() + + const firstResult = bufferView.element.querySelector('li .primary-line') + expect(DefaultFileIcons.iconClassForPath(firstResult.dataset.path)).toBe('icon-file-media') + }) + }) + + describe('icon services', () => { + describe('atom.file-icons', () => { + it('has a default handler', () => { + expect(getIconServices().fileIcons).toBe(DefaultFileIcons) + }) + + it('allows services to replace the default handler', async () => { + const provider = {iconClassForPath: () => 'foo bar'} + const disposable = atom.packages.serviceHub.provide('atom.file-icons', '1.0.0', provider) + expect(getIconServices().fileIcons).toBe(provider) + + await atom.workspace.open('sample.js') + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.insertText('js') + + await getOrScheduleUpdatePromise() + + const firstResult = bufferView.element.querySelector('li .primary-line') + expect(firstResult).toBeDefined() + expect(firstResult.className).toBe('primary-line file icon foo bar') + disposable.dispose() + expect(getIconServices().fileIcons).toBe(DefaultFileIcons) + }) + }) + + describe('file-icons.element-icons', () => { + it('has no default handler', () => { + expect(getIconServices().elementIcons).toBe(null) + }) + + it('uses the element-icon service if available', async () => { + const provider = element => { + element.classList.add('foo', 'bar') + return new Disposable(() => { + element.classList.remove('foo', 'bar') + }) + } + const disposable = atom.packages.serviceHub.provide('file-icons.element-icons', '1.0.0', provider) + expect(getIconServices().elementIcons).toBe(provider) + + await atom.workspace.open('sample.js') + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.insertText('js') + + await getOrScheduleUpdatePromise() + + const firstResult = bufferView.element.querySelector('li .primary-line') + expect(firstResult).toBeDefined() + expect(firstResult.className).toBe('primary-line file icon foo bar') + disposable.dispose() + expect(getIconServices().elementIcons).toBe(null) + expect(firstResult.classList).not.toBe('primary-line file icon foo bar') + }) + }) + + describe('when both services are provided', () => { + it('gives priority to the element-icon service', async () => { + const basicProvider = {iconClassForPath: () => 'foo'} + const elementProvider = element => { + element.classList.add('bar') + return new Disposable(() => { + element.classList.remove('bar') + }) + } + spyOn(basicProvider, 'iconClassForPath').andCallThrough() + atom.packages.serviceHub.provide('atom.file-icons', '1.0.0', basicProvider) + atom.packages.serviceHub.provide('file-icons.element-icons', '1.0.0', elementProvider) + expect(getIconServices().fileIcons).toBe(basicProvider) + expect(getIconServices().elementIcons).toBe(elementProvider) + + await atom.workspace.open('sample.js') + + await bufferView.toggle() + + expect(atom.workspace.panelForItem(bufferView).isVisible()).toBe(true) + bufferView.selectListView.refs.queryEditor.insertText('js') + + await getOrScheduleUpdatePromise() + + const firstResult = bufferView.element.querySelector('li .primary-line') + expect(firstResult).toBeDefined() + expect(firstResult.className).toBe('primary-line file icon bar') + expect(basicProvider.iconClassForPath).not.toHaveBeenCalled() + }) + }) + }) + + describe('Git integration', () => { + let projectPath, gitRepository, gitDirectory + + beforeEach(() => { + projectPath = atom.project.getDirectories()[0].resolve('git/working-dir') + fs.renameSync(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) + atom.project.setPaths([rootDir2, projectPath]) + + gitDirectory = atom.project.getDirectories()[1] + gitRepository = atom.project.getRepositories()[1] + + return new Promise( + resolve => gitRepository.onDidChangeStatuses(resolve) + ) + }) + + describe('git-status-finder behavior', () => { + let originalPath, newPath + + beforeEach(async () => { + jasmine.attachToDOM(workspaceElement) + + await atom.workspace.open(path.join(projectPath, 'a.txt')) + + const editor = atom.workspace.getActiveTextEditor() + originalPath = editor.getPath() + fs.writeFileSync(originalPath, 'making a change for the better') + gitRepository.getPathStatus(originalPath) + + newPath = atom.project.getDirectories()[1].resolve('newsample.js') + fs.writeFileSync(newPath, '') + gitRepository.getPathStatus(newPath) + }) + + it('displays all new and modified paths', async () => { + expect(atom.workspace.panelForItem(gitStatusView)).toBeNull() + await gitStatusView.toggle() + + await filesPromise() + expect(atom.workspace.panelForItem(gitStatusView).isVisible()).toBe(true) + expect(gitStatusView.element.querySelectorAll('.file').length).toBe(4) + expect(gitStatusView.element.querySelectorAll('.status.status-modified').length).toBe(1) + expect(gitStatusView.element.querySelectorAll('.status.status-added').length).toBe(3) + }) + }) + + describe('status decorations', () => { + let originalPath, editor, newPath + + beforeEach(async () => { + jasmine.attachToDOM(workspaceElement) + + await atom.workspace.open(path.join(projectPath, 'a.txt')) + + editor = atom.workspace.getActiveTextEditor() + originalPath = editor.getPath() + newPath = gitDirectory.resolve('newsample.js') + fs.writeFileSync(newPath, '') + fs.writeFileSync(originalPath, 'a change') + }) + + describe('when a modified file is shown in the list', () => + it('displays the modified icon', async () => { + gitRepository.getPathStatus(editor.getPath()) + + bufferView.toggle() + await filesPromise() + expect(bufferView.element.querySelectorAll('.status.status-modified').length).toBe(1) + expect(bufferView.element.querySelector('.status.status-modified').closest('li').querySelector('.file').textContent).toBe('a.txt') + }) + ) + + describe('when a new file is shown in the list', () => + it('displays the new icon', async () => { + await atom.workspace.open(path.join(projectPath, 'newsample.js')) + + gitRepository.getPathStatus(editor.getPath()) + + bufferView.toggle() + await filesPromise() + expect(bufferView.element.querySelectorAll('.status.status-added').length).toBe(1) + expect(bufferView.element.querySelector('.status.status-added').closest('li').querySelector('.file').textContent).toBe('newsample.js') + }) + ) + }) + + describe('when core.excludeVcsIgnoredPaths is set to true', () => { + beforeEach(() => atom.config.set('core.excludeVcsIgnoredPaths', true)) + + describe("when the project's path is the repository's working directory", () => { + beforeEach(() => { + const ignoreFile = path.join(projectPath, '.gitignore') + fs.writeFileSync(ignoreFile, 'ignored.txt') + + const ignoredFile = path.join(projectPath, 'ignored.txt') + fs.writeFileSync(ignoredFile, 'ignored text') + }) + + it('excludes paths that are git ignored', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('ignored.txt'))).not.toBeDefined() + }) + }) + + describe("when the project's path is a subfolder of the repository's working directory", () => { + beforeEach(() => { + atom.project.setPaths([gitDirectory.resolve('dir')]) + const ignoreFile = path.join(projectPath, '.gitignore') + fs.writeFileSync(ignoreFile, 'b.txt') + }) + + if (useRipGrep) { + it('does excludes paths that are git ignored', async () => { + fs.writeFileSync(path.join(projectPath, 'dir', 'a.txt'), 'something') + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('b.txt'))).not.toBeDefined() + }) + } else { + it('does not exclude paths that are git ignored', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('b.txt'))).toBeDefined() + }) + } + }) + + describe('when the .gitignore matches parts of the path to the root folder', () => { + beforeEach(() => { + const ignoreFile = path.join(projectPath, '.gitignore') + fs.writeFileSync(ignoreFile, path.basename(projectPath)) + }) + + it('only applies the .gitignore patterns to relative paths within the root folder', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('file.txt'))).toBeDefined() + }) + }) + + describe('when core.ignoredNames does not have .git in its glob patterns', () => { + beforeEach(() => { + atom.config.set('core.ignoredNames', []) + }) + + it('still ignores .git directory', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => + a.textContent.includes('HEAD'))).not.toBeDefined() + }) + }) + }) + + describe('when core.excludeVcsIgnoredPaths is set to false', () => { + beforeEach(() => atom.config.set('core.excludeVcsIgnoredPaths', false)) + + describe("when the project's path is the repository's working directory", () => { + beforeEach(() => { + const ignoreFile = path.join(projectPath, '.gitignore') + fs.writeFileSync(ignoreFile, 'ignored.txt') + + const ignoredFile = path.join(projectPath, 'ignored.txt') + fs.writeFileSync(ignoredFile, 'ignored text') + }) + + it("doesn't exclude paths that are git ignored", async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes('ignored.txt'))).toBeDefined() + }) + }) + }) + + describe('logging of metrics events', () => { + it('logs the crawling time', async () => { + // After setting the reporter it may receive some old events from previous tests + // that we want to discard. + reporterStub.addTiming.resetHistory() + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(reporterStub.addTiming.firstCall.args[0]).toEqual('fuzzy-finder-v1') + expect(reporterStub.addTiming.firstCall.args[2]).toEqual( + {ec: 'time-to-crawl', el: useRipGrep ? 'ripgrep' : 'fs', ev: 5} + ) + }) + + it('queues the events until a reporter is set', async () => { + // After setting the reporter it may receive some old events from previous tests + // that we want to discard. + reporterStub.addTiming.resetHistory() + + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + fuzzyFinderPackage.consumeMetricsReporter(reporterStub) + + expect(reporterStub.addTiming.firstCall.args[0]).toEqual('fuzzy-finder-v1') + expect(reporterStub.addTiming.firstCall.args[2]).toEqual( + {ec: 'time-to-crawl', el: useRipGrep ? 'ripgrep' : 'fs', ev: 5} + ) + }) + }) + }) + + describe('error handling', () => { + beforeEach(() => { + const junkDirPath = fs.realpathSync(temp.mkdirSync('junk-1')) + const brokenFilePath = path.join(junkDirPath, 'delete.txt') + fs.writeFileSync(brokenFilePath, 'delete-me') + + for (let i = 0; i < 1000; i++) { + fs.symlinkSync(brokenFilePath, atom.project.getDirectories()[0].resolve('broken-symlink-' + i)) + } + + fs.unlinkSync(brokenFilePath) + }) + + it('copes with a lot of errors during indexing', async () => { + await projectView.toggle() + + await waitForPathsToDisplay(projectView) + + expect(projectView.element.querySelector('.loading')).not.toBeVisible() + }) + }) + }) + } + + it('shows all files for the current project once the initial crawler has finished', async () => { + await waitForInitialCrawlerToFinish(fuzzyFinder) + + projectView = fuzzyFinder.createProjectView() + jasmine.attachToDOM(workspaceElement) + + await projectView.selectListView.update({maxResults: null}) + await projectView.toggle() + + expect(projectView.element.querySelector('.loading')).not.toBeVisible() + + await waitForPathsToDisplay(projectView) + + eachFilePath([rootDir1, rootDir2], (filePath) => { + const item = Array.from(projectView.element.querySelectorAll('li')).find(a => a.textContent.includes(filePath)) + expect(item).toExist() + const nameDiv = item.querySelector('div:first-child') + expect(nameDiv.dataset.name).toBe(path.basename(filePath)) + expect(nameDiv.textContent).toBe(path.basename(filePath)) + }) + + expect(projectView.element.querySelector('.loading')).not.toBeVisible() + }) +}) diff --git a/packages/fuzzy-finder/spec/project-view-spec.js b/packages/fuzzy-finder/spec/project-view-spec.js new file mode 100644 index 0000000000..b440329084 --- /dev/null +++ b/packages/fuzzy-finder/spec/project-view-spec.js @@ -0,0 +1,86 @@ +const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers') // eslint-disable-line no-unused-vars +const fs = require('fs') +const os = require('os') +const path = require('path') +const sinon = require('sinon') +const temp = require('temp').track() +const ProjectView = require('../lib/project-view') +const ReporterProxy = require('../lib/reporter-proxy') + +const metricsReporter = new ReporterProxy() + +describe('ProjectView', () => { + beforeEach(() => { + jasmine.useRealClock() + + // Limit concurrency on the crawler to avoid indeterminism. + sinon.stub(os, 'cpus').returns({length: 1}) + }) + + afterEach(() => { + os.cpus.restore() + }) + + it('includes remote editors when teletype is enabled', async () => { + const projectView = new ProjectView([], metricsReporter) + + const projectPath = fs.realpathSync(temp.mkdirSync()) + const file1Path = path.join(projectPath, 'a') + fs.writeFileSync(file1Path, 'a') + const file2Path = path.join(projectPath, 'b') + fs.writeFileSync(file2Path, 'b') + atom.project.setPaths([projectPath]) + + projectView.setTeletypeService({ + async getRemoteEditors () { + return [ + {uri: 'remote1-uri', path: 'remote1-path', hostGitHubUsername: 'user-1'}, + {uri: 'remote2-uri', path: 'remote2-path', hostGitHubUsername: 'user-2'} + ] + } + }) + + projectView.toggle() + await conditionPromise(() => projectView.items.length === 4) + expect(projectView.items).toEqual([ + {uri: 'remote1-uri', filePath: 'remote1-path', label: '@user-1: remote1-path', ownerGitHubUsername: 'user-1'}, + {uri: 'remote2-uri', filePath: 'remote2-path', label: '@user-2: remote2-path', ownerGitHubUsername: 'user-2'}, + {uri: file1Path, filePath: file1Path, label: 'a'}, + {uri: file2Path, filePath: file2Path, label: 'b'} + ]) + }) + + it('shows remote editors even when there is no open project', async () => { + const projectView = new ProjectView([], metricsReporter) + + atom.project.setPaths([]) + projectView.setTeletypeService({ + async getRemoteEditors () { + return [ + {uri: 'remote1-uri', path: 'remote1-path', hostGitHubUsername: 'user-1'}, + {uri: 'remote2-uri', path: 'remote2-path', hostGitHubUsername: 'user-2'} + ] + } + }) + + await projectView.toggle() + expect(projectView.items).toEqual([ + {uri: 'remote1-uri', filePath: 'remote1-path', label: '@user-1: remote1-path', ownerGitHubUsername: 'user-1'}, + {uri: 'remote2-uri', filePath: 'remote2-path', label: '@user-2: remote2-path', ownerGitHubUsername: 'user-2'} + ]) + }) + + it('gracefully defaults to empty list if teletype is unable to provide remote editors', async () => { + const projectView = new ProjectView([], metricsReporter) + + atom.project.setPaths([]) + projectView.setTeletypeService({ + async getRemoteEditors () { + return null + } + }) + + await projectView.toggle() + expect(projectView.items).toEqual([]) + }) +}) diff --git a/packages/fuzzy-finder/styles/fuzzy-finder.less b/packages/fuzzy-finder/styles/fuzzy-finder.less new file mode 100644 index 0000000000..e768deac5a --- /dev/null +++ b/packages/fuzzy-finder/styles/fuzzy-finder.less @@ -0,0 +1,27 @@ +@import "ui-variables"; + +// Highlight matched text +.fuzzy-finder .list-group .character-match { + color: @text-color-highlight; + font-weight: bold; +} + +.FuzzyFinderResult { + position: relative; + + @size: 28px; + + &.has-avatar { + // add some extra space for the avatar + padding-right: @size + (@component-padding * 2) !important; + } + + &-avatar { + position: absolute !important; + border-radius: @size; + width: @size; + top: 50%; + margin-top: -(@size / 2); + right: @component-padding; + } +} diff --git a/yarn.lock b/yarn.lock index 3ef2190180..c9d6b7a5a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,13 +29,6 @@ dependencies: "@babel/core" "7.x" -"@atom/fuzzy-native@^1.1.2": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@atom/fuzzy-native/-/fuzzy-native-1.2.1.tgz#2a773bfa230da99e65c6708218b09bbd78293191" - integrity sha512-ABUIbeQqfoA4WUK+PAsspM9jLaGlj0wjyIc9CIi1OMAHv71/vqrpJHPX2fHWiREEXYxwh/CBCshhkOWESbnNnQ== - dependencies: - nan "^2.14.2" - "@atom/source-map-support@^0.3.4": version "0.3.4" resolved "https://registry.yarnpkg.com/@atom/source-map-support/-/source-map-support-0.3.4.tgz#55ccbe0e64b2c742c5b333f357f9a93161145cfd" @@ -1583,6 +1576,12 @@ "@types/node" "*" playwright-core "1.22.2" +"@pulsar-edit/fuzzy-native@https://github.com/pulsar-edit/fuzzy-native.git#13d2e5f": + version "1.2.1" + resolved "https://github.com/pulsar-edit/fuzzy-native.git#13d2e5fe348bc0a38bbec1de86d43940893010c8" + dependencies: + nan "2.17.0" + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -2256,11 +2255,6 @@ async-exit-hook@^2.0.1: resolved "https://registry.yarnpkg.com/async-exit-hook/-/async-exit-hook-2.0.1.tgz#8bd8b024b0ec9b1c01cccb9af9db29bd717dfaf3" integrity sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw== -async@0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.6.tgz#ad3f373d9249ae324881565582bc90e152abbd68" - integrity sha512-LTdAJ0KBRK5o4BlBlUoGvfGNOMON+NLbONgDZk80SX0G8LQZyjN+74nNADIpQ/+rxun6+fYm7z4vIzAB51UKUA== - async@3.2.4, async@^3.2.0, async@^3.2.3: version "3.2.4" resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" @@ -4802,24 +4796,18 @@ fuzzaldrin-plus@^0.6.0: resolved "https://registry.yarnpkg.com/fuzzaldrin-plus/-/fuzzaldrin-plus-0.6.0.tgz#832f6489fbe876769459599c914a670ec22947ee" integrity sha512-srIDThJHkdp3aPwJpR/HNzYZCRJwm07b/igxseoHSB7qR8e/gQp4F6lMGknE3TQI1Aq14TiFf/wzrHOp9LY/EA== -fuzzaldrin@^2.0, fuzzaldrin@^2.1, fuzzaldrin@^2.1.0: +fuzzaldrin@^2.1, fuzzaldrin@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz#90204c3e2fdaa6941bb28d16645d418063a90e9b" integrity sha512-zgllBYwfHR5P3CncJiGbGVPpa3iFYW1yuPaIv8DiTVRrcg5/6uETNL5zvIoKflG1aifXVUZTlIroDehw4WygGA== -"fuzzy-finder@https://codeload.github.com/atom/fuzzy-finder/legacy.tar.gz/refs/tags/v1.14.3": +"fuzzy-finder@file:packages/fuzzy-finder": version "1.14.3" - resolved "https://codeload.github.com/atom/fuzzy-finder/legacy.tar.gz/refs/tags/v1.14.3#7cd40191b8930bb49039a860ab868f554f90f41d" dependencies: - "@atom/fuzzy-native" "^1.1.2" - async "0.2.6" + "@pulsar-edit/fuzzy-native" "https://github.com/pulsar-edit/fuzzy-native.git#13d2e5f" atom-select-list "^0.7.0" fs-plus "^3.0.0" - fuzzaldrin "^2.0" - fuzzaldrin-plus "^0.6.0" - humanize-plus "~1.8.2" minimatch "~3.0.3" - temp "~0.8.1" underscore-plus "^1.7.0" vscode-ripgrep "^1.2.5" wrench "^1.5" @@ -7030,7 +7018,7 @@ nan@2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== -nan@^2.10.0, nan@^2.12.1, nan@^2.13.2, nan@^2.14.0, nan@^2.14.1, nan@^2.14.2: +nan@2.17.0, nan@^2.10.0, nan@^2.12.1, nan@^2.13.2, nan@^2.14.0, nan@^2.14.1, nan@^2.14.2: version "2.17.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==