text: 'use strict';
  
  function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
  
  const util = require('util');
  const util__default = _interopDefault(util);
  const fs = require('../sys/node/graceful-fs.js');
  const fs__default = _interopDefault(fs);
  const path$1 = require('path');
  const path$1__default = _interopDefault(path$1);
  const querystring = require('querystring');
  const Url = require('url');
  const zlib = require('zlib');
  const buffer = require('buffer');
  const openInEditorApi = _interopDefault(require('./open-in-editor-api.js'));
  const net = require('net');
  const http = require('http');
  const https = require('https');
  const fs$1 = _interopDefault(require('fs'));
  const events = _interopDefault(require('events'));
  const assert = _interopDefault(require('assert'));
  const os = require('os');
  const crypto = require('crypto');
  const child_process = require('child_process');
  const ws = require('./ws.js');
  
  const DEV_SERVER_URL = '/~dev-server';
  const DEV_MODULE_URL = '/~dev-module';
  const DEV_SERVER_INIT_URL = `${DEV_SERVER_URL}-init`;
  const OPEN_IN_EDITOR_URL = `${DEV_SERVER_URL}-open-in-editor`;
  
  const version = '1.14.0';
  
  const msgResolves = new Map();
  let resolveIds = 1;
  function sendMsg(prcs, msg) {
      prcs.send(msg);
  }
  function sendMsgWithResponse(prcs, msg) {
      return new Promise(resolve => {
          msg.resolveId = resolveIds++;
          msgResolves.set(msg.resolveId, resolve);
          sendMsg(prcs, msg);
      });
  }
  function createMessageReceiver(prcs, cb) {
      prcs.on('message', (msg) => {
          if (typeof msg.resolveId === 'number') {
              const resolve = msgResolves.get(msg.resolveId);
              if (resolve) {
                  msgResolves.delete(msg.resolveId);
                  resolve(msg);
              }
          }
          cb(msg);
      });
  }
  function sendError(prcs, e) {
      const msg = {
          error: {
              message: e,
          },
      };
      if (typeof e === 'string') {
          msg.error.message = e + '';
      }
      else if (e) {
          try {
              msg.error.message = util__default.inspect(e) + '';
          }
          catch (e) { }
      }
      sendMsg(prcs, msg);
  }
  function responseHeaders(headers) {
      return Object.assign({}, DEFAULT_HEADERS, headers);
  }
  const DEFAULT_HEADERS = {
      'cache-control': 'no-cache, no-store, must-revalidate, max-age=0',
      'expires': '0',
      'server': 'Stencil Dev Server ' + version,
      'date': 'Wed, 1 Jan 2000 00:00:00 GMT',
      'access-control-allow-origin': '*',
      'access-control-expose-headers': '*',
  };
  function getBrowserUrl(protocol, address, port, basePath, pathname) {
      address = address === `0.0.0.0` ? `localhost` : address;
      const portSuffix = !port || port === 80 || port === 443 ? '' : ':' + port;
      let path = basePath;
      if (pathname.startsWith('/')) {
          pathname = pathname.substring(1);
      }
      path += pathname;
      protocol = protocol.replace(/\:/g, '');
      return `${protocol}://${address}${portSuffix}${path}`;
  }
  function getDevServerClientUrl(devServerConfig, host) {
      let address = devServerConfig.address;
      let port = devServerConfig.port;
      if (host) {
          address = host;
          port = null;
      }
      return getBrowserUrl(devServerConfig.protocol, address, port, devServerConfig.basePath, DEV_SERVER_URL);
  }
  function getContentType(devServerConfig, filePath) {
      const last = filePath.replace(/^.*[/\\]/, '').toLowerCase();
      const ext = last.replace(/^.*\./, '').toLowerCase();
      const hasPath = last.length < filePath.length;
      const hasDot = ext.length < last.length - 1;
      return ((hasDot || !hasPath) && devServerConfig.contentTypes[ext]) || 'application/octet-stream';
  }
  function isHtmlFile(filePath) {
      filePath = filePath.toLowerCase().trim();
      return filePath.endsWith('.html') || filePath.endsWith('.htm');
  }
  function isCssFile(filePath) {
      filePath = filePath.toLowerCase().trim();
      return filePath.endsWith('.css');
  }
  const TXT_EXT = ['css', 'html', 'htm', 'js', 'json', 'svg', 'xml'];
  function isSimpleText(filePath) {
      const ext = filePath
          .toLowerCase()
          .trim()
          .split('.')
          .pop();
      return TXT_EXT.includes(ext);
  }
  function isDevClient(pathname) {
      return pathname.startsWith(DEV_SERVER_URL);
  }
  function isDevModule(pathname) {
      return pathname.includes(DEV_MODULE_URL);
  }
  function isOpenInEditor(pathname) {
      return pathname === OPEN_IN_EDITOR_URL;
  }
  function isInitialDevServerLoad(pathname) {
      return pathname === DEV_SERVER_INIT_URL;
  }
  function isDevServerClient(pathname) {
      return pathname === DEV_SERVER_URL;
  }
  function shouldCompress(devServerConfig, req) {
      if (!devServerConfig.gzip) {
          return false;
      }
      if (req.method !== 'GET') {
          return false;
      }
      const acceptEncoding = req.headers && req.headers['accept-encoding'];
      if (typeof acceptEncoding !== 'string') {
          return false;
      }
      if (!acceptEncoding.includes('gzip')) {
          return false;
      }
      return true;
  }
  
  const IS_NODE_ENV = typeof global !== 'undefined' &&
      typeof require === 'function' &&
      !!global.process &&
      Array.isArray(global.process.argv) &&
      typeof __filename === 'string' &&
      (!global.origin || typeof global.origin !== 'string');
  const IS_NODE_WINDOWS_ENV = IS_NODE_ENV && global.process.platform === 'win32';
  
  const noop = () => {
      /* noop*/
  };
  const flatOne = (array) => {
      if (array.flat) {
          return array.flat(1);
      }
      return array.reduce((result, item) => {
          result.push(...item);
          return result;
      }, []);
  };
  const unique = (array, predicate = i => i) => {
      const set = new Set();
      return array.filter(item => {
          const key = predicate(item);
          if (key == null) {
              return true;
          }
          if (set.has(key)) {
              return false;
          }
          set.add(key);
          return true;
      });
  };
  const isString = (v) => typeof v === 'string';
  
  /*!
   * Ported to ESM from:
   * is-glob <https://github.com/jonschlinkert/is-glob>
   *
   * Copyright (c) 2014-2017, Jon Schlinkert.
   * Released under the MIT License.
   */
  const isGlobChars = { '{': '}', '(': ')', '[': ']' };
  const isGlobStrictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
  const isExtglobRegex = /(\\).|([@?!+*]\(.*\))/;
  const isExtglob = (str) => {
      let match;
      while ((match = isExtglobRegex.exec(str))) {
          if (match[2]) {
              return true;
          }
          str = str.slice(match.index + match[0].length);
      }
      return false;
  };
  const isGlob = (str) => {
      if (!isString(str) || str === '') {
          return false;
      }
      if (isExtglob(str)) {
          return true;
      }
      const regex = isGlobStrictRegex;
      let match;
      while ((match = regex.exec(str))) {
          if (match[2]) {
              return true;
          }
          let idx = match.index + match[0].length;
          // if an open bracket/brace/paren is escaped,
          // set the index to the next closing character
          const open = match[1];
          const close = open ? isGlobChars[open] : null;
          if (open && close) {
              const n = str.indexOf(close, idx);
              if (n !== -1) {
                  idx = n + 1;
              }
          }
          str = str.slice(idx);
      }
      return false;
  };
  
  const buildError = (diagnostics) => {
      const diagnostic = {
          level: 'error',
          type: 'build',
          header: 'Build Error',
          messageText: 'build error',
          relFilePath: null,
          absFilePath: null,
          lines: [],
      };
      if (diagnostics) {
          diagnostics.push(diagnostic);
      }
      return diagnostic;
  };
  const catchError = (diagnostics, err, msg) => {
      const diagnostic = {
          level: 'error',
          type: 'build',
          header: 'Build Error',
          messageText: 'build error',
          relFilePath: null,
          absFilePath: null,
          lines: [],
      };
      if (isString(msg)) {
          diagnostic.messageText = msg;
      }
      else if (err != null) {
          if (err.stack != null) {
              diagnostic.messageText = err.stack.toString();
          }
          else {
              if (err.message != null) {
                  diagnostic.messageText = err.message.toString();
              }
              else {
                  diagnostic.messageText = err.toString();
              }
          }
      }
      if (diagnostics != null && !shouldIgnoreError(diagnostic.messageText)) {
          diagnostics.push(diagnostic);
      }
      return diagnostic;
  };
  const shouldIgnoreError = (msg) => {
      return msg === TASK_CANCELED_MSG;
  };
  const TASK_CANCELED_MSG = `task canceled`;
  
  /**
   * Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar
   * Forward-slash paths can be used in Windows as long as they're not
   * extended-length paths and don't contain any non-ascii characters.
   * This was created since the path methods in Node.js outputs \\ paths on Windows.
   */
  const normalizePath = (path) => {
      if (typeof path !== 'string') {
          throw new Error(`invalid path to normalize`);
      }
      path = normalizeSlashes(path.trim());
      const components = pathComponents(path, getRootLength(path));
      const reducedComponents = reducePathComponents(components);
      const rootPart = reducedComponents[0];
      const secondPart = reducedComponents[1];
      const normalized = rootPart + reducedComponents.slice(1).join('/');
      if (normalized === '') {
          return '.';
      }
      if (rootPart === '' && secondPart && path.includes('/') && !secondPart.startsWith('.') && !secondPart.startsWith('@')) {
          return './' + normalized;
      }
      return normalized;
  };
  const normalizeSlashes = (path) => path.replace(backslashRegExp, '/');
  const altDirectorySeparator = '\\';
  const urlSchemeSeparator = '://';
  const backslashRegExp = /\\/g;
  const reducePathComponents = (components) => {
      if (!Array.isArray(components) || components.length === 0) {
          return [];
      }
      const reduced = [components[0]];
      for (let i = 1; i < components.length; i++) {
          const component = components[i];
          if (!component)
              continue;
          if (component === '.')
              continue;
          if (component === '..') {
              if (reduced.length > 1) {
                  if (reduced[reduced.length - 1] !== '..') {
                      reduced.pop();
                      continue;
                  }
              }
              else if (reduced[0])
                  continue;
          }
          reduced.push(component);
      }
      return reduced;
  };
  const getRootLength = (path) => {
      const rootLength = getEncodedRootLength(path);
      return rootLength < 0 ? ~rootLength : rootLength;
  };
  const getEncodedRootLength = (path) => {
      if (!path)
          return 0;
      const ch0 = path.charCodeAt(0);
      // POSIX or UNC
      if (ch0 === 47 /* slash */ || ch0 === 92 /* backslash */) {
          if (path.charCodeAt(1) !== ch0)
              return 1; // POSIX: "/" (or non-normalized "\")
          const p1 = path.indexOf(ch0 === 47 /* slash */ ? '/' : altDirectorySeparator, 2);
          if (p1 < 0)
              return path.length; // UNC: "//server" or "\\server"
          return p1 + 1; // UNC: "//server/" or "\\server\"
      }
      // DOS
      if (isVolumeCharacter(ch0) && path.charCodeAt(1) === 58 /* colon */) {
          const ch2 = path.charCodeAt(2);
          if (ch2 === 47 /* slash */ || ch2 === 92 /* backslash */)
              return 3; // DOS: "c:/" or "c:\"
          if (path.length === 2)
              return 2; // DOS: "c:" (but not "c:d")
      }
      // URL
      const schemeEnd = path.indexOf(urlSchemeSeparator);
      if (schemeEnd !== -1) {
          const authorityStart = schemeEnd + urlSchemeSeparator.length;
          const authorityEnd = path.indexOf('/', authorityStart);
          if (authorityEnd !== -1) {
              // URL: "file:///", "file://server/", "file://server/path"
              // For local "file" URLs, include the leading DOS volume (if present).
              // Per https://www.ietf.org/rfc/rfc1738.txt, a host of "" or "localhost" is a
              // special case interpreted as "the machine from which the URL is being interpreted".
              const scheme = path.slice(0, schemeEnd);
              const authority = path.slice(authorityStart, authorityEnd);
              if (scheme === 'file' && (authority === '' || authority === 'localhost') && isVolumeCharacter(path.charCodeAt(authorityEnd + 1))) {
                  const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2);
                  if (volumeSeparatorEnd !== -1) {
                      if (path.charCodeAt(volumeSeparatorEnd) === 47 /* slash */) {
                          // URL: "file:///c:/", "file://localhost/c:/", "file:///c%3a/", "file://localhost/c%3a/"
                          return ~(volumeSeparatorEnd + 1);
                      }
                      if (volumeSeparatorEnd === path.length) {
                          // URL: "file:///c:", "file://localhost/c:", "file:///c$3a", "file://localhost/c%3a"
                          // but not "file:///c:d" or "file:///c%3ad"
                          return ~volumeSeparatorEnd;
                      }
                  }
              }
              return ~(authorityEnd + 1); // URL: "file://server/", "http://server/"
          }
          return ~path.length; // URL: "file://server", "http://server"
      }
      // relative
      return 0;
  };
  const isVolumeCharacter = (charCode) => (charCode >= 97 /* a */ && charCode <= 122 /* z */) || (charCode >= 65 /* A */ && charCode <= 90 /* Z */);
  const getFileUrlVolumeSeparatorEnd = (url, start) => {
      const ch0 = url.charCodeAt(start);
      if (ch0 === 58 /* colon */)
          return start + 1;
      if (ch0 === 37 /* percent */ && url.charCodeAt(start + 1) === 51 /* _3 */) {
          const ch2 = url.charCodeAt(start + 2);
          if (ch2 === 97 /* a */ || ch2 === 65 /* A */)
              return start + 3;
      }
      return -1;
  };
  const pathComponents = (path, rootLength) => {
      const root = path.substring(0, rootLength);
      const rest = path.substring(rootLength).split('/');
      const restLen = rest.length;
      if (restLen > 0 && !rest[restLen - 1]) {
          rest.pop();
      }
      return [root, ...rest];
  };
  
  function serve500(devServerConfig, req, res, error, xSource) {
      try {
          res.writeHead(500, responseHeaders({
              'content-type': 'text/plain; charset=utf-8',
              'x-source': xSource,
          }));
          res.write(util__default.inspect(error));
          res.end();
          if (devServerConfig.logRequests) {
              sendMsg(process, {
                  requestLog: {
                      method: req.method,
                      url: req.url,
                      status: 500,
                  },
              });
          }
      }
      catch (e) {
          sendError(process, 'serve500: ' + e);
      }
  }
  
  async function serve404(devServerConfig, req, res, xSource) {
      try {
          if (req.pathname === '/favicon.ico') {
              try {
                  const defaultFavicon = path$1__default.join(devServerConfig.devServerDir, 'static', 'favicon.ico');
                  res.writeHead(200, responseHeaders({
                      'content-type': 'image/x-icon',
                      'x-source': `favicon: ${xSource}`,
                  }));
                  const rs = fs__default.createReadStream(defaultFavicon);
                  rs.on('error', err => {
                      res.writeHead(404, responseHeaders({
                          'content-type': 'text/plain; charset=utf-8',
                          'x-source': `createReadStream error: ${err}, ${xSource}`,
                      }));
                      res.write(util__default.inspect(err));
                      res.end();
                  });
                  rs.pipe(res);
                  return;
              }
              catch (e) {
                  serve500(devServerConfig, req, res, e, xSource);
              }
          }
          const content = ['404 File Not Found', 'Url: ' + req.pathname, 'File: ' + req.filePath].join('\n');
          serve404Content(devServerConfig, req, res, content, xSource);
          if (devServerConfig.logRequests) {
              sendMsg(process, {
                  requestLog: {
                      method: req.method,
                      url: req.url,
                      status: 404,
                  },
              });
          }
      }
      catch (e) {
          serve500(devServerConfig, req, res, e, xSource);
      }
  }
  function serve404Content(devServerConfig, req, res, content, xSource) {
      try {
          const headers = responseHeaders({
              'content-type': 'text/plain; charset=utf-8',
              'x-source': xSource,
          });
          res.writeHead(404, headers);
          res.write(content);
          res.end();
      }
      catch (e) {
          serve500(devServerConfig, req, res, e, 'serve404Content: ' + xSource);
      }
  }
  
  async function serveFile(devServerConfig, sys, req, res) {
      try {
          if (isSimpleText(req.filePath)) {
              // easy text file, use the internal cache
              let content = await sys.readFile(req.filePath, 'utf8');
              if (devServerConfig.websocket && isHtmlFile(req.filePath) && !isDevServerClient(req.pathname)) {
                  // auto inject our dev server script
                  content = appendDevServerClientScript(devServerConfig, req, content);
              }
              else if (isCssFile(req.filePath)) {
                  content = updateStyleUrls(req.url, content);
              }
              if (shouldCompress(devServerConfig, req)) {
                  // let's gzip this well known web dev text file
                  res.writeHead(200, responseHeaders({
                      'content-type': getContentType(devServerConfig, req.filePath) + '; charset=utf-8',
                      'content-encoding': 'gzip',
                      'vary': 'Accept-Encoding',
                  }));
                  zlib.gzip(content, { level: 9 }, (_, data) => {
                      res.end(data);
                  });
              }
              else {
                  // let's not gzip this file
                  res.writeHead(200, responseHeaders({
                      'content-type': getContentType(devServerConfig, req.filePath) + '; charset=utf-8',
                      'content-length': buffer.Buffer.byteLength(content, 'utf8'),
                  }));
                  res.write(content);
                  res.end();
              }
          }
          else {
              // non-well-known text file or other file, probably best we use a stream
              // but don't bother trying to gzip this file for the dev server
              res.writeHead(200, responseHeaders({
                  'content-type': getContentType(devServerConfig, req.filePath),
                  'content-length': req.stats.size,
              }));
              fs__default.createReadStream(req.filePath).pipe(res);
          }
          if (devServerConfig.logRequests) {
              sendMsg(process, {
                  requestLog: {
                      method: req.method,
                      url: req.url,
                      status: 200,
                  },
              });
          }
      }
      catch (e) {
          serve500(devServerConfig, req, res, e, 'serveFile');
      }
  }
  function updateStyleUrls(cssUrl, oldCss) {
      const parsedUrl = Url.parse(cssUrl);
      const qs = querystring.parse(parsedUrl.query);
      const versionId = qs['s-hmr'];
      const hmrUrls = qs['s-hmr-urls'];
      if (versionId && hmrUrls) {
          hmrUrls.split(',').forEach(hmrUrl => {
              urlVersionIds.set(hmrUrl, versionId);
          });
      }
      const reg = /url\((['"]?)(.*)\1\)/gi;
      let result;
      let newCss = oldCss;
      while ((result = reg.exec(oldCss)) !== null) {
          const oldUrl = result[2];
          const parsedUrl = Url.parse(oldUrl);
          const fileName = path$1__default.basename(parsedUrl.pathname);
          const versionId = urlVersionIds.get(fileName);
          if (!versionId) {
              continue;
          }
          const qs = querystring.parse(parsedUrl.query);
          qs['s-hmr'] = versionId;
          parsedUrl.search = querystring.stringify(qs);
          const newUrl = Url.format(parsedUrl);
          newCss = newCss.replace(oldUrl, newUrl);
      }
      return newCss;
  }
  const urlVersionIds = new Map();
  function appendDevServerClientScript(devServerConfig, req, content) {
      const devServerClientUrl = getDevServerClientUrl(devServerConfig, req.host);
      const iframe = `<iframe title="Stencil Dev Server Connector ${version} &#9889;" src="${devServerClientUrl}" style="display:block;width:0;height:0;border:0;visibility:hidden" aria-hidden="true"></iframe>`;
      return appendDevServerClientIframe(content, iframe);
  }
  function appendDevServerClientIframe(content, iframe) {
      if (content.includes('</body>')) {
          return content.replace('</body>', `${iframe}</body>`);
      }
      if (content.includes('</html>')) {
          return content.replace('</html>', `${iframe}</html>`);
      }
      return `${content}${iframe}`;
  }
  
  async function serveOpenInEditor(devServerConfig, sys, req, res) {
      let status = 200;
      const data = {};
      try {
          if (devServerConfig.editors.length > 0) {
              await parseData(devServerConfig, sys, req, data);
              await openDataInEditor(data);
          }
          else {
              data.error = `no editors available`;
          }
      }
      catch (e) {
          data.error = e + '';
          status = 500;
      }
      sendMsg(process, {
          requestLog: {
              method: req.method,
              url: req.url,
              status,
          },
      });
      res.writeHead(status, responseHeaders({
          'content-type': 'application/json; charset=utf-8',
      }));
      res.write(JSON.stringify(data, null, 2));
      res.end();
  }
  async function parseData(devServerConfig, sys, req, data) {
      const query = Url.parse(req.url).query;
      const qs = querystring.parse(query);
      if (typeof qs.file !== 'string') {
          data.error = `missing file`;
          return;
      }
      data.file = qs.file;
      if (qs.line != null && !isNaN(qs.line)) {
          data.line = parseInt(qs.line, 10);
      }
      if (typeof data.line !== 'number' || data.line < 1) {
          data.line = 1;
      }
      if (qs.column != null && !isNaN(qs.column)) {
          data.column = parseInt(qs.column, 10);
      }
      if (typeof data.column !== 'number' || data.column < 1) {
          data.column = 1;
      }
      if (typeof qs.editor === 'string') {
          qs.editor = qs.editor.trim().toLowerCase();
          if (devServerConfig.editors.some(e => e.id === qs.editor)) {
              data.editor = qs.editor;
          }
          else {
              data.error = `invalid editor: ${qs.editor}`;
              return;
          }
      }
      else {
          data.editor = devServerConfig.editors[0].id;
      }
      try {
          const stat = await sys.stat(data.file);
          data.exists = !!stat && stat.isFile();
      }
      catch (e) {
          data.exists = false;
      }
  }
  async function openDataInEditor(data) {
      if (!data.exists || data.error) {
          return;
      }
      try {
          const opts = {
              editor: data.editor,
          };
          const editor = openInEditorApi.configure(opts, err => (data.error = err + ''));
          if (data.error) {
              return;
          }
          data.open = `${data.file}:${data.line}:${data.column}`;
          await editor.open(data.open);
      }
      catch (e) {
          data.error = e + '';
      }
  }
  async function getEditors() {
      const editors = [];
      try {
          await Promise.all(Object.keys(openInEditorApi.editors).map(async (editorId) => {
              const isSupported = await isEditorSupported(editorId);
              editors.push({
                  id: editorId,
                  priority: EDITOR_PRIORITY[editorId],
                  supported: isSupported,
              });
          }));
      }
      catch (e) { }
      return editors
          .filter(e => e.supported)
          .sort((a, b) => {
          if (a.priority < b.priority)
              return -1;
          if (a.priority > b.priority)
              return 1;
          return 0;
      })
          .map(e => {
          return {
              id: e.id,
              name: EDITORS[e.id],
          };
      });
  }
  async function isEditorSupported(editorId) {
      let isSupported = false;
      try {
          await openInEditorApi.editors[editorId].detect();
          isSupported = true;
      }
      catch (e) { }
      return isSupported;
  }
  const EDITORS = {
      atom: 'Atom',
      code: 'Code',
      emacs: 'Emacs',
      idea14ce: 'IDEA 14 Community Edition',
      phpstorm: 'PhpStorm',
      sublime: 'Sublime',
      webstorm: 'WebStorm',
      vim: 'Vim',
      visualstudio: 'Visual Studio',
  };
  const EDITOR_PRIORITY = {
      code: 1,
      atom: 2,
      sublime: 3,
      visualstudio: 4,
      idea14ce: 5,
      webstorm: 6,
      phpstorm: 7,
      vim: 8,
      emacs: 9,
  };
  
  async function serveDevClient(devServerConfig, sys, req, res) {
      try {
          if (isOpenInEditor(req.pathname)) {
              return serveOpenInEditor(devServerConfig, sys, req, res);
          }
          if (isDevServerClient(req.pathname)) {
              return serveDevClientScript(devServerConfig, sys, req, res);
          }
          if (isInitialDevServerLoad(req.pathname)) {
              req.filePath = path$1__default.join(devServerConfig.devServerDir, 'templates', 'initial-load.html');
          }
          else {
              const staticFile = req.pathname.replace(DEV_SERVER_URL + '/', '');
              req.filePath = path$1__default.join(devServerConfig.devServerDir, 'static', staticFile);
          }
          try {
              req.stats = await sys.stat(req.filePath);
              if (req.stats) {
                  return serveFile(devServerConfig, sys, req, res);
              }
              return serve404(devServerConfig, req, res, 'serveDevClient no stats');
          }
          catch (e) {
              return serve404(devServerConfig, req, res, `serveDevClient stats error ${e}`);
          }
      }
      catch (e) {
          return serve500(devServerConfig, req, res, e, 'serveDevClient');
      }
  }
  async function serveDevClientScript(devServerConfig, sys, req, res) {
      try {
          const filePath = path$1__default.join(devServerConfig.devServerDir, 'connector.html');
          let content = await sys.readFile(filePath, 'utf8');
          if (typeof content === 'string') {
              const devClientConfig = {
                  basePath: devServerConfig.basePath,
                  editors: devServerConfig.editors,
                  reloadStrategy: devServerConfig.reloadStrategy,
              };
              content = content.replace('window.__DEV_CLIENT_CONFIG__', JSON.stringify(devClientConfig));
              res.writeHead(200, responseHeaders({
                  'content-type': 'text/html; charset=utf-8',
              }));
              res.write(content);
              res.end();
          }
          else {
              serve404(devServerConfig, req, res, 'serveDevClientScript');
          }
      }
      catch (e) {
          serve500(devServerConfig, req, res, e, 'serveDevClientScript');
      }
  }
  
  async function serveCompilerRequest(devServerConfig, req, res) {
      try {
          const msgResults = await sendMsgWithResponse(process, {
              compilerRequestPath: req.url,
          });
          const results = msgResults.compilerRequestResults;
          if (results) {
              const headers = {
                  'content-type': 'application/javascript; charset=utf-8',
                  'content-length': Buffer.byteLength(results.content, 'utf8'),
                  'x-dev-node-module-id': results.nodeModuleId,
                  'x-dev-node-module-version': results.nodeModuleVersion,
                  'x-dev-node-module-resolved-path': results.nodeResolvedPath,
                  'x-dev-node-module-cache-path': results.cachePath,
                  'x-dev-node-module-cache-hit': results.cacheHit,
              };
              res.writeHead(results.status, responseHeaders(headers));
              res.write(results.content);
              res.end();
              return;
          }
          return serve404(devServerConfig, req, res, 'serveCompilerRequest');
      }
      catch (e) {
          return serve500(devServerConfig, req, res, e, 'serveCompilerRequest');
      }
  }
  
  let dirTemplate = null;
  async function serveDirectoryIndex(devServerConfig, sys, req, res) {
      try {
          const indexFilePath = path$1__default.join(req.filePath, 'index.html');
          req.stats = await sys.stat(indexFilePath);
          if (req.stats && req.stats.isFile()) {
              req.filePath = indexFilePath;
              return serveFile(devServerConfig, sys, req, res);
          }
      }
      catch (e) { }
      if (!req.pathname.endsWith('/')) {
          if (devServerConfig.logRequests) {
              sendMsg(process, {
                  requestLog: {
                      method: req.method,
                      url: req.url,
                      status: 302,
                  },
              });
          }
          res.writeHead(302, {
              location: req.pathname + '/',
          });
          return res.end();
      }
      try {
          const dirFilePaths = await sys.readdir(req.filePath);
          try {
              if (dirTemplate == null) {
                  const dirTemplatePath = path$1__default.join(devServerConfig.devServerDir, 'templates', 'directory-index.html');
                  dirTemplate = await sys.readFile(dirTemplatePath, 'utf8');
              }
              const files = await getFiles(sys, req.pathname, dirFilePaths);
              const templateHtml = dirTemplate
                  .replace('{{title}}', getTitle(req.pathname))
                  .replace('{{nav}}', getName(req.pathname))
                  .replace('{{files}}', files);
              res.writeHead(200, responseHeaders({
                  'content-type': 'text/html; charset=utf-8',
                  'x-directory-index': req.pathname,
              }));
              res.write(templateHtml);
              res.end();
              if (devServerConfig.logRequests) {
                  sendMsg(process, {
                      requestLog: {
                          method: req.method,
                          url: req.url,
                          status: 200,
                      },
                  });
              }
          }
          catch (e) {
              serve500(devServerConfig, req, res, e, 'serveDirectoryIndex');
          }
      }
      catch (e) {
          serve404(devServerConfig, req, res, 'serveDirectoryIndex');
      }
  }
  async function getFiles(sys, urlPathName, dirItemNames) {
      const items = await getDirectoryItems(sys, urlPathName, dirItemNames);
      if (urlPathName !== '/') {
          items.unshift({
              isDirectory: true,
              pathname: '../',
              name: '..',
          });
      }
      return items
          .map(item => {
          return `
          <li class="${item.isDirectory ? 'directory' : 'file'}">
            <a href="${item.pathname}">
              <span class="icon"></span>
              <span>${item.name}</span>
            </a>
          </li>`;
      })
          .join('');
  }
  async function getDirectoryItems(sys, urlPathName, dirFilePaths) {
      const items = await Promise.all(dirFilePaths.map(async (dirFilePath) => {
          const fileName = path$1__default.basename(dirFilePath);
          const stats = await sys.stat(dirFilePath);
          const item = {
              name: fileName,
              pathname: Url.resolve(urlPathName, fileName),
              isDirectory: !!(stats && stats.isDirectory()),
          };
          return item;
      }));
      return items;
  }
  function getTitle(pathName) {
      return pathName;
  }
  function getName(pathName) {
      const dirs = pathName.split('/');
      dirs.pop();
      let url = '';
      return (dirs
          .map((dir, index) => {
          url += dir + '/';
          const text = index === 0 ? `~` : dir;
          return `<a href="${url}">${text}</a>`;
      })
          .join('<span>/</span>') + '<span>/</span>');
  }
  
  function createRequestHandler(devServerConfig, sys) {
      return async function (incomingReq, res) {
          try {
              const req = normalizeHttpRequest(devServerConfig, incomingReq);
              if (req.url === '') {
                  res.writeHead(302, { location: '/' });
                  if (devServerConfig.logRequests) {
                      sendMsg(process, {
                          requestLog: {
                              method: req.method,
                              url: req.url,
                              status: 302,
                          },
                      });
                  }
                  return res.end();
              }
              if (isDevClient(req.pathname) && devServerConfig.websocket) {
                  return serveDevClient(devServerConfig, sys, req, res);
              }
              if (isDevModule(req.pathname)) {
                  return serveCompilerRequest(devServerConfig, req, res);
              }
              if (!isValidUrlBasePath(devServerConfig.basePath, req.url)) {
                  console.log(1);
                  if (devServerConfig.logRequests) {
                      sendMsg(process, {
                          requestLog: {
                              method: req.method,
                              url: req.url,
                              status: 404,
                          },
                      });
                  }
                  return serve404Content(devServerConfig, req, res, `404 File Not Found, base path: ${devServerConfig.basePath}`, `invalid basePath`);
              }
              try {
                  req.stats = await sys.stat(req.filePath);
                  if (req.stats) {
                      if (req.stats.isFile()) {
                          return serveFile(devServerConfig, sys, req, res);
                      }
                      if (req.stats.isDirectory()) {
                          return serveDirectoryIndex(devServerConfig, sys, req, res);
                      }
                  }
              }
              catch (e) { }
              const xSource = ['notfound'];
              const validHistoryApi = isValidHistoryApi(devServerConfig, req);
              xSource.push(`validHistoryApi: ${validHistoryApi}`);
              if (validHistoryApi) {
                  try {
                      const indexFilePath = path$1__default.join(devServerConfig.root, devServerConfig.historyApiFallback.index);
                      xSource.push(`indexFilePath: ${indexFilePath}`);
                      req.stats = await sys.stat(indexFilePath);
                      if (req.stats && req.stats.isFile()) {
                          req.filePath = indexFilePath;
                          return serveFile(devServerConfig, sys, req, res);
                      }
                  }
                  catch (e) {
                      xSource.push(`notfound error: ${e}`);
                  }
              }
              return serve404(devServerConfig, req, res, xSource.join(', '));
          }
          catch (e) {
              return serve500(devServerConfig, incomingReq, res, e, `not found error`);
          }
      };
  }
  function isValidUrlBasePath(basePath, url) {
      // normalize the paths to always end with a slash for the check
      if (!url.endsWith('/')) {
          url += '/';
      }
      if (!basePath.endsWith('/')) {
          basePath += '/';
      }
      return url.startsWith(basePath);
  }
  function normalizeHttpRequest(devServerConfig, incomingReq) {
      const req = {
          method: (incomingReq.method || 'GET').toUpperCase(),
          headers: incomingReq.headers,
          acceptHeader: (incomingReq.headers && typeof incomingReq.headers.accept === 'string' && incomingReq.headers.accept) || '',
          url: (incomingReq.url || '').trim() || '',
          host: (incomingReq.headers && typeof incomingReq.headers.host === 'string' && incomingReq.headers.host) || null,
      };
      const parsedUrl = Url.parse(req.url);
      const parts = (parsedUrl.pathname || '').replace(/\\/g, '/').split('/');
      req.pathname = parts.map(part => decodeURIComponent(part)).join('/');
      if (req.pathname.length > 0 && !isDevClient(req.pathname)) {
          req.pathname = '/' + req.pathname.substring(devServerConfig.basePath.length);
      }
      req.filePath = normalizePath(path$1__default.normalize(path$1__default.join(devServerConfig.root, path$1__default.relative('/', req.pathname))));
      return req;
  }
  function isValidHistoryApi(devServerConfig, req) {
      if (!devServerConfig.historyApiFallback) {
          return false;
      }
      if (req.method !== 'GET') {
          return false;
      }
      if (!req.acceptHeader.includes('text/html')) {
          return false;
      }
      if (!devServerConfig.historyApiFallback.disableDotRule && req.pathname.includes('.')) {
          return false;
      }
      return true;
  }
  
  async function findClosestOpenPort(host, port) {
      async function t(portToCheck) {
          const isTaken = await isPortTaken(host, portToCheck);
          if (!isTaken) {
              return portToCheck;
          }
          return t(portToCheck + 1);
      }
      return t(port);
  }
  function isPortTaken(host, port) {
      return new Promise((resolve, reject) => {
          const tester = net.createServer()
              .once('error', () => {
              resolve(true);
          })
              .once('listening', () => {
              tester
                  .once('close', () => {
                  resolve(false);
              })
                  .close();
          })
              .on('error', (err) => {
              reject(err);
          })
              .listen(port, host);
      });
  }
  
  async function createHttpServer(devServerConfig, sys, destroys) {
      // figure out the port to be listening on
      // by figuring out the first one available
      devServerConfig.port = await findClosestOpenPort(devServerConfig.address, devServerConfig.port);
      // create our request handler
      const reqHandler = createRequestHandler(devServerConfig, sys);
      const credentials = devServerConfig.https;
      let server = credentials ? https.createServer(credentials, reqHandler) : http.createServer(reqHandler);
      destroys.push(() => {
          // close down the serve on destroy
          server.close();
          server = null;
      });
      return server;
  }
  
  const copyFile = util.promisify(fs__default.copyFile);
  const mkdir = util.promisify(fs__default.mkdir);
  const readdir = util.promisify(fs__default.readdir);
  const stat = util.promisify(fs__default.stat);
  
  // Copyright Joyent, Inc. and other Node contributors.
  //
  // 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.
  
  
  var isWindows = process.platform === 'win32';
  
  
  // JavaScript implementation of realpath, ported from node pre-v6
  
  var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG);
  
  function rethrow() {
    // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and
    // is fairly slow to generate.
    var callback;
    if (DEBUG) {
      var backtrace = new Error;
      callback = debugCallback;
    } else
      callback = missingCallback;
  
    return callback;
  
    function debugCallback(err) {
      if (err) {
        backtrace.message = err.message;
        err = backtrace;
        missingCallback(err);
      }
    }
  
    function missingCallback(err) {
      if (err) {
        if (process.throwDeprecation)
          throw err;  // Forgot a callback but don't know where? Use NODE_DEBUG=fs
        else if (!process.noDeprecation) {
          var msg = 'fs: missing callback ' + (err.stack || err.message);
          if (process.traceDeprecation)
            console.trace(msg);
          else
            console.error(msg);
        }
      }
    }
  }
  
  function maybeCallback(cb) {
    return typeof cb === 'function' ? cb : rethrow();
  }
  
  var normalize = path$1__default.normalize;
  
  // Regexp that finds the next partion of a (partial) path
  // result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
  if (isWindows) {
    var nextPartRe = /(.*?)(?:[\/\\]+|$)/g;
  } else {
    var nextPartRe = /(.*?)(?:[\/]+|$)/g;
  }
  
  // Regex to find the device root, including trailing slash. E.g. 'c:\\'.
  if (isWindows) {
    var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/;
  } else {
    var splitRootRe = /^[\/]*/;
  }
  
  var realpathSync = function realpathSync(p, cache) {
    // make p is absolute
    p = path$1__default.resolve(p);
  
    if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
      return cache[p];
    }
  
    var original = p,
        seenLinks = {},
        knownHard = {};
  
    // current character position in p
    var pos;
    // the partial path so far, including a trailing slash if any
    var current;
    // the partial path without a trailing slash (except when pointing at a root)
    var base;
    // the partial path scanned in the previous round, with slash
    var previous;
  
    start();
  
    function start() {
      // Skip over roots
      var m = splitRootRe.exec(p);
      pos = m[0].length;
      current = m[0];
      base = m[0];
      previous = '';
  
      // On windows, check that the root exists. On unix there is no need.
      if (isWindows && !knownHard[base]) {
        fs$1.lstatSync(base);
        knownHard[base] = true;
      }
    }
  
    // walk down the path, swapping out linked pathparts for their real
    // values
    // NB: p.length changes.
    while (pos < p.length) {
      // find the next part
      nextPartRe.lastIndex = pos;
      var result = nextPartRe.exec(p);
      previous = current;
      current += result[0];
      base = previous + result[1];
      pos = nextPartRe.lastIndex;
  
      // continue if not a symlink
      if (knownHard[base] || (cache && cache[base] === base)) {
        continue;
      }
  
      var resolvedLink;
      if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
        // some known symbolic link.  no need to stat again.
        resolvedLink = cache[base];
      } else {
        var stat = fs$1.lstatSync(base);
        if (!stat.isSymbolicLink()) {
          knownHard[base] = true;
          if (cache) cache[base] = base;
          continue;
        }
  
        // read the link if it wasn't read before
        // dev/ino always return 0 on windows, so skip the check.
        var linkTarget = null;
        if (!isWindows) {
          var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
          if (seenLinks.hasOwnProperty(id)) {
            linkTarget = seenLinks[id];
          }
        }
        if (linkTarget === null) {
          fs$1.statSync(base);
          linkTarget = fs$1.readlinkSync(base);
        }
        resolvedLink = path$1__default.resolve(previous, linkTarget);
        // track this, if given a cache.
        if (cache) cache[base] = resolvedLink;
        if (!isWindows) seenLinks[id] = linkTarget;
      }
  
      // resolve the link, then start over
      p = path$1__default.resolve(resolvedLink, p.slice(pos));
      start();
    }
  
    if (cache) cache[original] = p;
  
    return p;
  };
  
  
  var realpath = function realpath(p, cache, cb) {
    if (typeof cb !== 'function') {
      cb = maybeCallback(cache);
      cache = null;
    }
  
    // make p is absolute
    p = path$1__default.resolve(p);
  
    if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
      return process.nextTick(cb.bind(null, null, cache[p]));
    }
  
    var original = p,
        seenLinks = {},
        knownHard = {};
  
    // current character position in p
    var pos;
    // the partial path so far, including a trailing slash if any
    var current;
    // the partial path without a trailing slash (except when pointing at a root)
    var base;
    // the partial path scanned in the previous round, with slash
    var previous;
  
    start();
  
    function start() {
      // Skip over roots
      var m = splitRootRe.exec(p);
      pos = m[0].length;
      current = m[0];
      base = m[0];
      previous = '';
  
      // On windows, check that the root exists. On unix there is no need.
      if (isWindows && !knownHard[base]) {
        fs$1.lstat(base, function(err) {
          if (err) return cb(err);
          knownHard[base] = true;
          LOOP();
        });
      } else {
        process.nextTick(LOOP);
      }
    }
  
    // walk down the path, swapping out linked pathparts for their real
    // values
    function LOOP() {
      // stop if scanned past end of path
      if (pos >= p.length) {
        if (cache) cache[original] = p;
        return cb(null, p);
      }
  
      // find the next part
      nextPartRe.lastIndex = pos;
      var result = nextPartRe.exec(p);
      previous = current;
      current += result[0];
      base = previous + result[1];
      pos = nextPartRe.lastIndex;
  
      // continue if not a symlink
      if (knownHard[base] || (cache && cache[base] === base)) {
        return process.nextTick(LOOP);
      }
  
      if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
        // known symbolic link.  no need to stat again.
        return gotResolvedLink(cache[base]);
      }
  
      return fs$1.lstat(base, gotStat);
    }
  
    function gotStat(err, stat) {
      if (err) return cb(err);
  
      // if not a symlink, skip to the next path part
      if (!stat.isSymbolicLink()) {
        knownHard[base] = true;
        if (cache) cache[base] = base;
        return process.nextTick(LOOP);
      }
  
      // stat & read the link if not read before
      // call gotTarget as soon as the link target is known
      // dev/ino always return 0 on windows, so skip the check.
      if (!isWindows) {
        var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
        if (seenLinks.hasOwnProperty(id)) {
          return gotTarget(null, seenLinks[id], base);
        }
      }
      fs$1.stat(base, function(err) {
        if (err) return cb(err);
  
        fs$1.readlink(base, function(err, target) {
          if (!isWindows) seenLinks[id] = target;
          gotTarget(err, target);
        });
      });
    }
  
    function gotTarget(err, target, base) {
      if (err) return cb(err);
  
      var resolvedLink = path$1__default.resolve(previous, target);
      if (cache) cache[base] = resolvedLink;
      gotResolvedLink(resolvedLink);
    }
  
    function gotResolvedLink(resolvedLink) {
      // resolve the link, then start over
      p = path$1__default.resolve(resolvedLink, p.slice(pos));
      start();
    }
  };
  
  var old = {
  	realpathSync: realpathSync,
  	realpath: realpath
  };
  
  var fs_realpath = realpath$1;
  realpath$1.realpath = realpath$1;
  realpath$1.sync = realpathSync$1;
  realpath$1.realpathSync = realpathSync$1;
  realpath$1.monkeypatch = monkeypatch;
  realpath$1.unmonkeypatch = unmonkeypatch;
  
  
  var origRealpath = fs$1.realpath;
  var origRealpathSync = fs$1.realpathSync;
  
  var version$1 = process.version;
  var ok = /^v[0-5]\./.test(version$1);
  
  
  function newError (er) {
    return er && er.syscall === 'realpath' && (
      er.code === 'ELOOP' ||
      er.code === 'ENOMEM' ||
      er.code === 'ENAMETOOLONG'
    )
  }
  
  function realpath$1 (p, cache, cb) {
    if (ok) {
      return origRealpath(p, cache, cb)
    }
  
    if (typeof cache === 'function') {
      cb = cache;
      cache = null;
    }
    origRealpath(p, cache, function (er, result) {
      if (newError(er)) {
        old.realpath(p, cache, cb);
      } else {
        cb(er, result);
      }
    });
  }
  
  function realpathSync$1 (p, cache) {
    if (ok) {
      return origRealpathSync(p, cache)
    }
  
    try {
      return origRealpathSync(p, cache)
    } catch (er) {
      if (newError(er)) {
        return old.realpathSync(p, cache)
      } else {
        throw er
      }
    }
  }
  
  function monkeypatch () {
    fs$1.realpath = realpath$1;
    fs$1.realpathSync = realpathSync$1;
  }
  
  function unmonkeypatch () {
    fs$1.realpath = origRealpath;
    fs$1.realpathSync = origRealpathSync;
  }
  
  var concatMap = function (xs, fn) {
      var res = [];
      for (var i = 0; i < xs.length; i++) {
          var x = fn(xs[i], i);
          if (isArray(x)) res.push.apply(res, x);
          else res.push(x);
      }
      return res;
  };
  
  var isArray = Array.isArray || function (xs) {
      return Object.prototype.toString.call(xs) === '[object Array]';
  };
  
  var balancedMatch = balanced;
  function balanced(a, b, str) {
    if (a instanceof RegExp) a = maybeMatch(a, str);
    if (b instanceof RegExp) b = maybeMatch(b, str);
  
    var r = range(a, b, str);
  
    return r && {
      start: r[0],
      end: r[1],
      pre: str.slice(0, r[0]),
      body: str.slice(r[0] + a.length, r[1]),
      post: str.slice(r[1] + b.length)
    };
  }
  
  function maybeMatch(reg, str) {
    var m = str.match(reg);
    return m ? m[0] : null;
  }
  
  balanced.range = range;
  function range(a, b, str) {
    var begs, beg, left, right, result;
    var ai = str.indexOf(a);
    var bi = str.indexOf(b, ai + 1);
    var i = ai;
  
    if (ai >= 0 && bi > 0) {
      begs = [];
      left = str.length;
  
      while (i >= 0 && !result) {
        if (i == ai) {
          begs.push(i);
          ai = str.indexOf(a, i + 1);
        } else if (begs.length == 1) {
          result = [ begs.pop(), bi ];
        } else {
          beg = begs.pop();
          if (beg < left) {
            left = beg;
            right = bi;
          }
  
          bi = str.indexOf(b, i + 1);
        }
  
        i = ai < bi && ai >= 0 ? ai : bi;
      }
  
      if (begs.length) {
        result = [ left, right ];
      }
    }
  
    return result;
  }
  
  var braceExpansion = expandTop;
  
  var escSlash = '\0SLASH'+Math.random()+'\0';
  var escOpen = '\0OPEN'+Math.random()+'\0';
  var escClose = '\0CLOSE'+Math.random()+'\0';
  var escComma = '\0COMMA'+Math.random()+'\0';
  var escPeriod = '\0PERIOD'+Math.random()+'\0';
  
  function numeric(str) {
    return parseInt(str, 10) == str
      ? parseInt(str, 10)
      : str.charCodeAt(0);
  }
  
  function escapeBraces(str) {
    return str.split('\\\\').join(escSlash)
              .split('\\{').join(escOpen)
              .split('\\}').join(escClose)
              .split('\\,').join(escComma)
              .split('\\.').join(escPeriod);
  }
  
  function unescapeBraces(str) {
    return str.split(escSlash).join('\\')
              .split(escOpen).join('{')
              .split(escClose).join('}')
              .split(escComma).join(',')
              .split(escPeriod).join('.');
  }
  
  
  // Basically just str.split(","), but handling cases
  // where we have nested braced sections, which should be
  // treated as individual members, like {a,{b,c},d}
  function parseCommaParts(str) {
    if (!str)
      return [''];
  
    var parts = [];
    var m = balancedMatch('{', '}', str);
  
    if (!m)
      return str.split(',');
  
    var pre = m.pre;
    var body = m.body;
    var post = m.post;
    var p = pre.split(',');
  
    p[p.length-1] += '{' + body + '}';
    var postParts = parseCommaParts(post);
    if (post.length) {
      p[p.length-1] += postParts.shift();
      p.push.apply(p, postParts);
    }
  
    parts.push.apply(parts, p);
  
    return parts;
  }
  
  function expandTop(str) {
    if (!str)
      return [];
  
    // I don't know why Bash 4.3 does this, but it does.
    // Anything starting with {} will have the first two bytes preserved
    // but *only* at the top level, so {},a}b will not expand to anything,
    // but a{},b}c will be expanded to [a}c,abc].
    // One could argue that this is a bug in Bash, but since the goal of
    // this module is to match Bash's rules, we escape a leading {}
    if (str.substr(0, 2) === '{}') {
      str = '\\{\\}' + str.substr(2);
    }
  
    return expand(escapeBraces(str), true).map(unescapeBraces);
  }
  
  function embrace(str) {
    return '{' + str + '}';
  }
  function isPadded(el) {
    return /^-?0\d/.test(el);
  }
  
  function lte(i, y) {
    return i <= y;
  }
  function gte(i, y) {
    return i >= y;
  }
  
  function expand(str, isTop) {
    var expansions = [];
  
    var m = balancedMatch('{', '}', str);
    if (!m || /\$$/.test(m.pre)) return [str];
  
    var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
    var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
    var isSequence = isNumericSequence || isAlphaSequence;
    var isOptions = m.body.indexOf(',') >= 0;
    if (!isSequence && !isOptions) {
      // {a},b}
      if (m.post.match(/,.*\}/)) {
        str = m.pre + '{' + m.body + escClose + m.post;
        return expand(str);
      }
      return [str];
    }
  
    var n;
    if (isSequence) {
      n = m.body.split(/\.\./);
    } else {
      n = parseCommaParts(m.body);
      if (n.length === 1) {
        // x{{a,b}}y ==> x{a}y x{b}y
        n = expand(n[0], false).map(embrace);
        if (n.length === 1) {
          var post = m.post.length
            ? expand(m.post, false)
            : [''];
          return post.map(function(p) {
            return m.pre + n[0] + p;
          });
        }
      }
    }
  
    // at this point, n is the parts, and we know it's not a comma set
    // with a single entry.
  
    // no need to expand pre, since it is guaranteed to be free of brace-sets
    var pre = m.pre;
    var post = m.post.length
      ? expand(m.post, false)
      : [''];
  
    var N;
  
    if (isSequence) {
      var x = numeric(n[0]);
      var y = numeric(n[1]);
      var width = Math.max(n[0].length, n[1].length);
      var incr = n.length == 3
        ? Math.abs(numeric(n[2]))
        : 1;
      var test = lte;
      var reverse = y < x;
      if (reverse) {
        incr *= -1;
        test = gte;
      }
      var pad = n.some(isPadded);
  
      N = [];
  
      for (var i = x; test(i, y); i += incr) {
        var c;
        if (isAlphaSequence) {
          c = String.fromCharCode(i);
          if (c === '\\')
            c = '';
        } else {
          c = String(i);
          if (pad) {
            var need = width - c.length;
            if (need > 0) {
              var z = new Array(need + 1).join('0');
              if (i < 0)
                c = '-' + z + c.slice(1);
              else
                c = z + c;
            }
          }
        }
        N.push(c);
      }
    } else {
      N = concatMap(n, function(el) { return expand(el, false) });
    }
  
    for (var j = 0; j < N.length; j++) {
      for (var k = 0; k < post.length; k++) {
        var expansion = pre + N[j] + post[k];
        if (!isTop || isSequence || expansion)
          expansions.push(expansion);
      }
    }
  
    return expansions;
  }
  
  var minimatch_1 = minimatch;
  minimatch.Minimatch = Minimatch;
  
  var path = { sep: '/' };
  try {
    path = path$1__default;
  } catch (er) {}
  
  var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {};
  
  
  var plTypes = {
    '!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
    '?': { open: '(?:', close: ')?' },
    '+': { open: '(?:', close: ')+' },
    '*': { open: '(?:', close: ')*' },
    '@': { open: '(?:', close: ')' }
  };
  
  // any single thing other than /
  // don't need to escape / when using new RegExp()
  var qmark = '[^/]';
  
  // * => any number of characters
  var star = qmark + '*?';
  
  // ** when dots are allowed.  Anything goes, except .. and .
  // not (^ or / followed by one or two dots followed by $ or /),
  // followed by anything, any number of times.
  var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?';
  
  // not a ^ or / followed by a dot,
  // followed by anything, any number of times.
  var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?';
  
  // characters that need to be escaped in RegExp.
  var reSpecials = charSet('().*{}+?[]^$\\!');
  
  // "abc" -> { a:true, b:true, c:true }
  function charSet (s) {
    return s.split('').reduce(function (set, c) {
      set[c] = true;
      return set
    }, {})
  }
  
  // normalizes slashes.
  var slashSplit = /\/+/;
  
  minimatch.filter = filter;
  function filter (pattern, options) {
    options = options || {};
    return function (p, i, list) {
      return minimatch(p, pattern, options)
    }
  }
  
  function ext (a, b) {
    a = a || {};
    b = b || {};
    var t = {};
    Object.keys(b).forEach(function (k) {
      t[k] = b[k];
    });
    Object.keys(a).forEach(function (k) {
      t[k] = a[k];
    });
    return t
  }
  
  minimatch.defaults = function (def) {
    if (!def || !Object.keys(def).length) return minimatch
  
    var orig = minimatch;
  
    var m = function minimatch (p, pattern, options) {
      return orig.minimatch(p, pattern, ext(def, options))
    };
  
    m.Minimatch = function Minimatch (pattern, options) {
      return new orig.Minimatch(pattern, ext(def, options))
    };
  
    return m
  };
  
  Minimatch.defaults = function (def) {
    if (!def || !Object.keys(def).length) return Minimatch
    return minimatch.defaults(def).Minimatch
  };
  
  function minimatch (p, pattern, options) {
    if (typeof pattern !== 'string') {
      throw new TypeError('glob pattern string required')
    }
  
    if (!options) options = {};
  
    // shortcut: comments match nothing.
    if (!options.nocomment && pattern.charAt(0) === '#') {
      return false
    }
  
    // "" only matches ""
    if (pattern.trim() === '') return p === ''
  
    return new Minimatch(pattern, options).match(p)
  }
  
  function Minimatch (pattern, options) {
    if (!(this instanceof Minimatch)) {
      return new Minimatch(pattern, options)
    }
  
    if (typeof pattern !== 'string') {
      throw new TypeError('glob pattern string required')
    }
  
    if (!options) options = {};
    pattern = pattern.trim();
  
    // windows support: need to use /, not \
    if (path.sep !== '/') {
      pattern = pattern.split(path.sep).join('/');
    }
  
    this.options = options;
    this.set = [];
    this.pattern = pattern;
    this.regexp = null;
    this.negate = false;
    this.comment = false;
    this.empty = false;
  
    // make the set of regexps etc.
    this.make();
  }
  
  Minimatch.prototype.debug = function () {};
  
  Minimatch.prototype.make = make;
  function make () {
    // don't do it more than once.
    if (this._made) return
  
    var pattern = this.pattern;
    var options = this.options;
  
    // empty patterns and comments match nothing.
    if (!options.nocomment && pattern.charAt(0) === '#') {
      this.comment = true;
      return
    }
    if (!pattern) {
      this.empty = true;
      return
    }
  
    // step 1: figure out negation, etc.
    this.parseNegate();
  
    // step 2: expand braces
    var set = this.globSet = this.braceExpand();
  
    if (options.debug) this.debug = console.error;
  
    this.debug(this.pattern, set);
  
    // step 3: now we have a set, so turn each one into a series of path-portion
    // matching patterns.
    // These will be regexps, except in the case of "**", which is
    // set to the GLOBSTAR object for globstar behavior,
    // and will not contain any / characters
    set = this.globParts = set.map(function (s) {
      return s.split(slashSplit)
    });
  
    this.debug(this.pattern, set);
  
    // glob --> regexps
    set = set.map(function (s, si, set) {
      return s.map(this.parse, this)
    }, this);
  
    this.debug(this.pattern, set);
  
    // filter out everything that didn't compile properly.
    set = set.filter(function (s) {
      return s.indexOf(false) === -1
    });
  
    this.debug(this.pattern, set);
  
    this.set = set;
  }
  
  Minimatch.prototype.parseNegate = parseNegate;
  function parseNegate () {
    var pattern = this.pattern;
    var negate = false;
    var options = this.options;
    var negateOffset = 0;
  
    if (options.nonegate) return
  
    for (var i = 0, l = pattern.length
      ; i < l && pattern.charAt(i) === '!'
      ; i++) {
      negate = !negate;
      negateOffset++;
    }
  
    if (negateOffset) this.pattern = pattern.substr(negateOffset);
    this.negate = negate;
  }
  
  // Brace expansion:
  // a{b,c}d -> abd acd
  // a{b,}c -> abc ac
  // a{0..3}d -> a0d a1d a2d a3d
  // a{b,c{d,e}f}g -> abg acdfg acefg
  // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
  //
  // Invalid sets are not expanded.
  // a{2..}b -> a{2..}b
  // a{b}c -> a{b}c
  minimatch.braceExpand = function (pattern, options) {
    return braceExpand(pattern, options)
  };
  
  Minimatch.prototype.braceExpand = braceExpand;
  
  function braceExpand (pattern, options) {
    if (!options) {
      if (this instanceof Minimatch) {
        options = this.options;
      } else {
        options = {};
      }
    }
  
    pattern = typeof pattern === 'undefined'
      ? this.pattern : pattern;
  
    if (typeof pattern === 'undefined') {
      throw new TypeError('undefined pattern')
    }
  
    if (options.nobrace ||
      !pattern.match(/\{.*\}/)) {
      // shortcut. no need to expand.
      return [pattern]
    }
  
    return braceExpansion(pattern)
  }
  
  // parse a component of the expanded set.
  // At this point, no pattern may contain "/" in it
  // so we're going to return a 2d array, where each entry is the full
  // pattern, split on '/', and then turned into a regular expression.
  // A regexp is made at the end which joins each array with an
  // escaped /, and another full one which joins each regexp with |.
  //
  // Following the lead of Bash 4.1, note that "**" only has special meaning
  // when it is the *only* thing in a path portion.  Otherwise, any series
  // of * is equivalent to a single *.  Globstar behavior is enabled by
  // default, and can be disabled by setting options.noglobstar.
  Minimatch.prototype.parse = parse;
  var SUBPARSE = {};
  function parse (pattern, isSub) {
    if (pattern.length > 1024 * 64) {
      throw new TypeError('pattern is too long')
    }
  
    var options = this.options;
  
    // shortcuts
    if (!options.noglobstar && pattern === '**') return GLOBSTAR
    if (pattern === '') return ''
  
    var re = '';
    var hasMagic = !!options.nocase;
    var escaping = false;
    // ? => one single character
    var patternListStack = [];
    var negativeLists = [];
    var stateChar;
    var inClass = false;
    var reClassStart = -1;
    var classStart = -1;
    // . and .. never match anything that doesn't start with .,
    // even when options.dot is set.
    var patternStart = pattern.charAt(0) === '.' ? '' // anything
    // not (start or / followed by . or .. followed by / or end)
    : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))'
    : '(?!\\.)';
    var self = this;
  
    function clearStateChar () {
      if (stateChar) {
        // we had some state-tracking character
        // that wasn't consumed by this pass.
        switch (stateChar) {
          case '*':
            re += star;
            hasMagic = true;
          break
          case '?':
            re += qmark;
            hasMagic = true;
          break
          default:
            re += '\\' + stateChar;
          break
        }
        self.debug('clearStateChar %j %j', stateChar, re);
        stateChar = false;
      }
    }
  
    for (var i = 0, len = pattern.length, c
      ; (i < len) && (c = pattern.charAt(i))
      ; i++) {
      this.debug('%s\t%s %s %j', pattern, i, re, c);
  
      // skip over any that are escaped.
      if (escaping && reSpecials[c]) {
        re += '\\' + c;
        escaping = false;
        continue
      }
  
      switch (c) {
        case '/':
          // completely not allowed, even escaped.
          // Should already be path-split by now.
          return false
  
        case '\\':
          clearStateChar();
          escaping = true;
        continue
  
        // the various stateChar values
        // for the "extglob" stuff.
        case '?':
        case '*':
        case '+':
        case '@':
        case '!':
          this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c);
  
          // all of those are literals inside a class, except that
          // the glob [!a] means [^a] in regexp
          if (inClass) {
            this.debug('  in class');
            if (c === '!' && i === classStart + 1) c = '^';
            re += c;
            continue
          }
  
          // if we already have a stateChar, then it means
          // that there was something like ** or +? in there.
          // Handle the stateChar, then proceed with this one.
          self.debug('call clearStateChar %j', stateChar);
          clearStateChar();
          stateChar = c;
          // if extglob is disabled, then +(asdf|foo) isn't a thing.
          // just clear the statechar *now*, rather than even diving into
          // the patternList stuff.
          if (options.noext) clearStateChar();
        continue
  
        case '(':
          if (inClass) {
            re += '(';
            continue
          }
  
          if (!stateChar) {
            re += '\\(';
            continue
          }
  
          patternListStack.push({
            type: stateChar,
            start: i - 1,
            reStart: re.length,
            open: plTypes[stateChar].open,
            close: plTypes[stateChar].close
          });
          // negation is (?:(?!js)[^/]*)
          re += stateChar === '!' ? '(?:(?!(?:' : '(?:';
          this.debug('plType %j %j', stateChar, re);
          stateChar = false;
        continue
  
        case ')':
          if (inClass || !patternListStack.length) {
            re += '\\)';
            continue
          }
  
          clearStateChar();
          hasMagic = true;
          var pl = patternListStack.pop();
          // negation is (?:(?!js)[^/]*)
          // The others are (?:<pattern>)<type>
          re += pl.close;
          if (pl.type === '!') {
            negativeLists.push(pl);
          }
          pl.reEnd = re.length;
        continue
  
        case '|':
          if (inClass || !patternListStack.length || escaping) {
            re += '\\|';
            escaping = false;
            continue
          }
  
          clearStateChar();
          re += '|';
        continue
  
        // these are mostly the same in regexp and glob
        case '[':
          // swallow any state-tracking char before the [
          clearStateChar();
  
          if (inClass) {
            re += '\\' + c;
            continue
          }
  
          inClass = true;
          classStart = i;
          reClassStart = re.length;
          re += c;
        continue
  
        case ']':
          //  a right bracket shall lose its special
          //  meaning and represent itself in
          //  a bracket expression if it occurs
          //  first in the list.  -- POSIX.2 2.8.3.2
          if (i === classStart + 1 || !inClass) {
            re += '\\' + c;
            escaping = false;
            continue
          }
  
          // handle the case where we left a class open.
          // "[z-a]" is valid, equivalent to "\[z-a\]"
          if (inClass) {
            // split where the last [ was, make sure we don't have
            // an invalid re. if so, re-walk the contents of the
            // would-be class to re-translate any characters that
            // were passed through as-is
            // TODO: It would probably be faster to determine this
            // without a try/catch and a new RegExp, but it's tricky
            // to do safely.  For now, this is safe and works.
            var cs = pattern.substring(classStart + 1, i);
            try {
              RegExp('[' + cs + ']');
            } catch (er) {
              // not a valid class!
              var sp = this.parse(cs, SUBPARSE);
              re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]';
              hasMagic = hasMagic || sp[1];
              inClass = false;
              continue
            }
          }
  
          // finish up the class.
          hasMagic = true;
          inClass = false;
          re += c;
        continue
  
        default:
          // swallow any state char that wasn't consumed
          clearStateChar();
  
          if (escaping) {
            // no need
            escaping = false;
          } else if (reSpecials[c]
            && !(c === '^' && inClass)) {
            re += '\\';
          }
  
          re += c;
  
      } // switch
    } // for
  
    // handle the case where we left a class open.
    // "[abc" is valid, equivalent to "\[abc"
    if (inClass) {
      // split where the last [ was, and escape it
      // this is a huge pita.  We now have to re-walk
      // the contents of the would-be class to re-translate
      // any characters that were passed through as-is
      cs = pattern.substr(classStart + 1);
      sp = this.parse(cs, SUBPARSE);
      re = re.substr(0, reClassStart) + '\\[' + sp[0];
      hasMagic = hasMagic || sp[1];
    }
  
    // handle the case where we had a +( thing at the *end*
    // of the pattern.
    // each pattern list stack adds 3 chars, and we need to go through
    // and escape any | chars that were passed through as-is for the regexp.
    // Go through and escape them, taking care not to double-escape any
    // | chars that were already escaped.
    for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
      var tail = re.slice(pl.reStart + pl.open.length);
      this.debug('setting tail', re, pl);
      // maybe some even number of \, then maybe 1 \, followed by a |
      tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) {
        if (!$2) {
          // the | isn't already escaped, so escape it.
          $2 = '\\';
        }
  
        // need to escape all those slashes *again*, without escaping the
        // one that we need for escaping the | character.  As it works out,
        // escaping an even number of slashes can be done by simply repeating
        // it exactly after itself.  That's why this trick works.
        //
        // I am sorry that you have to see this.
        return $1 + $1 + $2 + '|'
      });
  
      this.debug('tail=%j\n   %s', tail, tail, pl, re);
      var t = pl.type === '*' ? star
        : pl.type === '?' ? qmark
        : '\\' + pl.type;
  
      hasMagic = true;
      re = re.slice(0, pl.reStart) + t + '\\(' + tail;
    }
  
    // handle trailing things that only matter at the very end.
    clearStateChar();
    if (escaping) {
      // trailing \\
      re += '\\\\';
    }
  
    // only need to apply the nodot start if the re starts with
    // something that could conceivably capture a dot
    var addPatternStart = false;
    switch (re.charAt(0)) {
      case '.':
      case '[':
      case '(': addPatternStart = true;
    }
  
    // Hack to work around lack of negative lookbehind in JS
    // A pattern like: *.!(x).!(y|z) needs to ensure that a name
    // like 'a.xyz.yz' doesn't match.  So, the first negative
    // lookahead, has to look ALL the way ahead, to the end of
    // the pattern.
    for (var n = negativeLists.length - 1; n > -1; n--) {
      var nl = negativeLists[n];
  
      var nlBefore = re.slice(0, nl.reStart);
      var nlFirst = re.slice(nl.reStart, nl.reEnd - 8);
      var nlLast = re.slice(nl.reEnd - 8, nl.reEnd);
      var nlAfter = re.slice(nl.reEnd);
  
      nlLast += nlAfter;
  
      // Handle nested stuff like *(*.js|!(*.json)), where open parens
      // mean that we should *not* include the ) in the bit that is considered
      // "after" the negated section.
      var openParensBefore = nlBefore.split('(').length - 1;
      var cleanAfter = nlAfter;
      for (i = 0; i < openParensBefore; i++) {
        cleanAfter = cleanAfter.replace(/\)[+*?]?/, '');
      }
      nlAfter = cleanAfter;
  
      var dollar = '';
      if (nlAfter === '' && isSub !== SUBPARSE) {
        dollar = '$';
      }
      var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast;
      re = newRe;
    }
  
    // if the re is not "" at this point, then we need to make sure
    // it doesn't match against an empty path part.
    // Otherwise a/* will match a/, which it should not.
    if (re !== '' && hasMagic) {
      re = '(?=.)' + re;
    }
  
    if (addPatternStart) {
      re = patternStart + re;
    }
  
    // parsing just a piece of a larger pattern.
    if (isSub === SUBPARSE) {
      return [re, hasMagic]
    }
  
    // skip the regexp for non-magical patterns
    // unescape anything in it, though, so that it'll be
    // an exact match against a file etc.
    if (!hasMagic) {
      return globUnescape(pattern)
    }
  
    var flags = options.nocase ? 'i' : '';
    try {
      var regExp = new RegExp('^' + re + '$', flags);
    } catch (er) {
      // If it was an invalid regular expression, then it can't match
      // anything.  This trick looks for a character after the end of
      // the string, which is of course impossible, except in multi-line
      // mode, but it's not a /m regex.
      return new RegExp('$.')
    }
  
    regExp._glob = pattern;
    regExp._src = re;
  
    return regExp
  }
  
  minimatch.makeRe = function (pattern, options) {
    return new Minimatch(pattern, options || {}).makeRe()
  };
  
  Minimatch.prototype.makeRe = makeRe;
  function makeRe () {
    if (this.regexp || this.regexp === false) return this.regexp
  
    // at this point, this.set is a 2d array of partial
    // pattern strings, or "**".
    //
    // It's better to use .match().  This function shouldn't
    // be used, really, but it's pretty convenient sometimes,
    // when you just want to work with a regex.
    var set = this.set;
  
    if (!set.length) {
      this.regexp = false;
      return this.regexp
    }
    var options = this.options;
  
    var twoStar = options.noglobstar ? star
      : options.dot ? twoStarDot
      : twoStarNoDot;
    var flags = options.nocase ? 'i' : '';
  
    var re = set.map(function (pattern) {
      return pattern.map(function (p) {
        return (p === GLOBSTAR) ? twoStar
        : (typeof p === 'string') ? regExpEscape(p)
        : p._src
      }).join('\\\/')
    }).join('|');
  
    // must match entire pattern
    // ending in a * or ** will make it less strict.
    re = '^(?:' + re + ')$';
  
    // can match anything, as long as it's not this.
    if (this.negate) re = '^(?!' + re + ').*$';
  
    try {
      this.regexp = new RegExp(re, flags);
    } catch (ex) {
      this.regexp = false;
    }
    return this.regexp
  }
  
  minimatch.match = function (list, pattern, options) {
    options = options || {};
    var mm = new Minimatch(pattern, options);
    list = list.filter(function (f) {
      return mm.match(f)
    });
    if (mm.options.nonull && !list.length) {
      list.push(pattern);
    }
    return list
  };
  
  Minimatch.prototype.match = match;
  function match (f, partial) {
    this.debug('match', f, this.pattern);
    // short-circuit in the case of busted things.
    // comments, etc.
    if (this.comment) return false
    if (this.empty) return f === ''
  
    if (f === '/' && partial) return true
  
    var options = this.options;
  
    // windows: need to use /, not \
    if (path.sep !== '/') {
      f = f.split(path.sep).join('/');
    }
  
    // treat the test path as a set of pathparts.
    f = f.split(slashSplit);
    this.debug(this.pattern, 'split', f);
  
    // just ONE of the pattern sets in this.set needs to match
    // in order for it to be valid.  If negating, then just one
    // match means that we have failed.
    // Either way, return on the first hit.
  
    var set = this.set;
    this.debug(this.pattern, 'set', set);
  
    // Find the basename of the path by looking for the last non-empty segment
    var filename;
    var i;
    for (i = f.length - 1; i >= 0; i--) {
      filename = f[i];
      if (filename) break
    }
  
    for (i = 0; i < set.length; i++) {
      var pattern = set[i];
      var file = f;
      if (options.matchBase && pattern.length === 1) {
        file = [filename];
      }
      var hit = this.matchOne(file, pattern, partial);
      if (hit) {
        if (options.flipNegate) return true
        return !this.negate
      }
    }
  
    // didn't get any hits.  this is success if it's a negative
    // pattern, failure otherwise.
    if (options.flipNegate) return false
    return this.negate
  }
  
  // set partial to true to test if, for example,
  // "/a/b" matches the start of "/*/b/*/d"
  // Partial means, if you run out of file before you run
  // out of pattern, then that's fine, as long as all
  // the parts match.
  Minimatch.prototype.matchOne = function (file, pattern, partial) {
    var options = this.options;
  
    this.debug('matchOne',
      { 'this': this, file: file, pattern: pattern });
  
    this.debug('matchOne', file.length, pattern.length);
  
    for (var fi = 0,
        pi = 0,
        fl = file.length,
        pl = pattern.length
        ; (fi < fl) && (pi < pl)
        ; fi++, pi++) {
      this.debug('matchOne loop');
      var p = pattern[pi];
      var f = file[fi];
  
      this.debug(pattern, p, f);
  
      // should be impossible.
      // some invalid regexp stuff in the set.
      if (p === false) return false
  
      if (p === GLOBSTAR) {
        this.debug('GLOBSTAR', [pattern, p, f]);
  
        // "**"
        // a/**/b/**/c would match the following:
        // a/b/x/y/z/c
        // a/x/y/z/b/c
        // a/b/x/b/x/c
        // a/b/c
        // To do this, take the rest of the pattern after
        // the **, and see if it would match the file remainder.
        // If so, return success.
        // If not, the ** "swallows" a segment, and try again.
        // This is recursively awful.
        //
        // a/**/b/**/c matching a/b/x/y/z/c
        // - a matches a
        // - doublestar
        //   - matchOne(b/x/y/z/c, b/**/c)
        //     - b matches b
        //     - doublestar
        //       - matchOne(x/y/z/c, c) -> no
        //       - matchOne(y/z/c, c) -> no
        //       - matchOne(z/c, c) -> no
        //       - matchOne(c, c) yes, hit
        var fr = fi;
        var pr = pi + 1;
        if (pr === pl) {
          this.debug('** at the end');
          // a ** at the end will just swallow the rest.
          // We have found a match.
          // however, it will not swallow /.x, unless
          // options.dot is set.
          // . and .. are *never* matched by **, for explosively
          // exponential reasons.
          for (; fi < fl; fi++) {
            if (file[fi] === '.' || file[fi] === '..' ||
              (!options.dot && file[fi].charAt(0) === '.')) return false
          }
          return true
        }
  
        // ok, let's see if we can swallow whatever we can.
        while (fr < fl) {
          var swallowee = file[fr];
  
          this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
  
          // XXX remove this slice.  Just pass the start index.
          if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
            this.debug('globstar found match!', fr, fl, swallowee);
            // found a match.
            return true
          } else {
            // can't swallow "." or ".." ever.
            // can only swallow ".foo" when explicitly asked.
            if (swallowee === '.' || swallowee === '..' ||
              (!options.dot && swallowee.charAt(0) === '.')) {
              this.debug('dot detected!', file, fr, pattern, pr);
              break
            }
  
            // ** swallows a segment, and continue.
            this.debug('globstar swallow a segment, and continue');
            fr++;
          }
        }
  
        // no match was found.
        // However, in partial mode, we can't say this is necessarily over.
        // If there's more *pattern* left, then
        if (partial) {
          // ran out of file
          this.debug('\n>>> no match, partial?', file, fr, pattern, pr);
          if (fr === fl) return true
        }
        return false
      }
  
      // something other than **
      // non-magic patterns just have to match exactly
      // patterns with magic have been turned into regexps.
      var hit;
      if (typeof p === 'string') {
        if (options.nocase) {
          hit = f.toLowerCase() === p.toLowerCase();
        } else {
          hit = f === p;
        }
        this.debug('string match', p, f, hit);
      } else {
        hit = f.match(p);
        this.debug('pattern match', p, f, hit);
      }
  
      if (!hit) return false
    }
  
    // Note: ending in / means that we'll get a final ""
    // at the end of the pattern.  This can only match a
    // corresponding "" at the end of the file.
    // If the file ends in /, then it can only match a
    // a pattern that ends in /, unless the pattern just
    // doesn't have any more for it. But, a/b/ should *not*
    // match "a/b/*", even though "" matches against the
    // [^/]*? pattern, except in partial mode, where it might
    // simply not be reached yet.
    // However, a/b/ should still satisfy a/*
  
    // now either we fell off the end of the pattern, or we're done.
    if (fi === fl && pi === pl) {
      // ran out of pattern and filename at the same time.
      // an exact hit!
      return true
    } else if (fi === fl) {
      // ran out of file, but still had pattern left.
      // this is ok if we're doing the match as part of
      // a glob fs traversal.
      return partial
    } else if (pi === pl) {
      // ran out of pattern, still have file left.
      // this is only acceptable if we're on the very last
      // empty segment of a file with a trailing slash.
      // a/* should match a/b/
      var emptyFileEnd = (fi === fl - 1) && (file[fi] === '');
      return emptyFileEnd
    }
  
    // should be unreachable.
    throw new Error('wtf?')
  };
  
  // replace stuff like \* with *
  function globUnescape (s) {
    return s.replace(/\\(.)/g, '$1')
  }
  
  function regExpEscape (s) {
    return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
  }
  
  function createCommonjsModule(fn, basedir, module) {
  	return module = {
  	  path: basedir,
  	  exports: {},
  	  require: function (path, base) {
        return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
      }
  	}, fn(module, module.exports), module.exports;
  }
  
  function commonjsRequire () {
  	throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
  }
  
  var inherits_browser = createCommonjsModule(function (module) {
  if (typeof Object.create === 'function') {
    // implementation from standard node.js 'util' module
    module.exports = function inherits(ctor, superCtor) {
      if (superCtor) {
        ctor.super_ = superCtor;
        ctor.prototype = Object.create(superCtor.prototype, {
          constructor: {
            value: ctor,
            enumerable: false,
            writable: true,
            configurable: true
          }
        });
      }
    };
  } else {
    // old school shim for old browsers
    module.exports = function inherits(ctor, superCtor) {
      if (superCtor) {
        ctor.super_ = superCtor;
        var TempCtor = function () {};
        TempCtor.prototype = superCtor.prototype;
        ctor.prototype = new TempCtor();
        ctor.prototype.constructor = ctor;
      }
    };
  }
  });
  
  var inherits = createCommonjsModule(function (module) {
  try {
    var util = util__default;
    /* istanbul ignore next */
    if (typeof util.inherits !== 'function') throw '';
    module.exports = util.inherits;
  } catch (e) {
    /* istanbul ignore next */
    module.exports = inherits_browser;
  }
  });
  
  var alphasort_1 = alphasort;
  var alphasorti_1 = alphasorti;
  var setopts_1 = setopts;
  var ownProp_1 = ownProp;
  var makeAbs_1 = makeAbs;
  var finish_1 = finish;
  var mark_1 = mark;
  var isIgnored_1 = isIgnored;
  var childrenIgnored_1 = childrenIgnored;
  
  function ownProp (obj, field) {
    return Object.prototype.hasOwnProperty.call(obj, field)
  }
  
  
  
  
  var Minimatch$1 = minimatch_1.Minimatch;
  
  function alphasorti (a, b) {
    return a.toLowerCase().localeCompare(b.toLowerCase())
  }
  
  function alphasort (a, b) {
    return a.localeCompare(b)
  }
  
  function setupIgnores (self, options) {
    self.ignore = options.ignore || [];
  
    if (!Array.isArray(self.ignore))
      self.ignore = [self.ignore];
  
    if (self.ignore.length) {
      self.ignore = self.ignore.map(ignoreMap);
    }
  }
  
  // ignore patterns are always in dot:true mode.
  function ignoreMap (pattern) {
    var gmatcher = null;
    if (pattern.slice(-3) === '/**') {
      var gpattern = pattern.replace(/(\/\*\*)+$/, '');
      gmatcher = new Minimatch$1(gpattern, { dot: true });
    }
  
    return {
      matcher: new Minimatch$1(pattern, { dot: true }),
      gmatcher: gmatcher
    }
  }
  
  function setopts (self, pattern, options) {
    if (!options)
      options = {};
  
    // base-matching: just use globstar for that.
    if (options.matchBase && -1 === pattern.indexOf("/")) {
      if (options.noglobstar) {
        throw new Error("base matching requires globstar")
      }
      pattern = "**/" + pattern;
    }
  
    self.silent = !!options.silent;
    self.pattern = pattern;
    self.strict = options.strict !== false;
    self.realpath = !!options.realpath;
    self.realpathCache = options.realpathCache || Object.create(null);
    self.follow = !!options.follow;
    self.dot = !!options.dot;
    self.mark = !!options.mark;
    self.nodir = !!options.nodir;
    if (self.nodir)
      self.mark = true;
    self.sync = !!options.sync;
    self.nounique = !!options.nounique;
    self.nonull = !!options.nonull;
    self.nosort = !!options.nosort;
    self.nocase = !!options.nocase;
    self.stat = !!options.stat;
    self.noprocess = !!options.noprocess;
    self.absolute = !!options.absolute;
  
    self.maxLength = options.maxLength || Infinity;
    self.cache = options.cache || Object.create(null);
    self.statCache = options.statCache || Object.create(null);
    self.symlinks = options.symlinks || Object.create(null);
  
    setupIgnores(self, options);
  
    self.changedCwd = false;
    var cwd = process.cwd();
    if (!ownProp(options, "cwd"))
      self.cwd = cwd;
    else {
      self.cwd = path$1__default.resolve(options.cwd);
      self.changedCwd = self.cwd !== cwd;
    }
  
    self.root = options.root || path$1__default.resolve(self.cwd, "/");
    self.root = path$1__default.resolve(self.root);
    if (process.platform === "win32")
      self.root = self.root.replace(/\\/g, "/");
  
    // TODO: is an absolute `cwd` supposed to be resolved against `root`?
    // e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test')
    self.cwdAbs = path$1.isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd);
    if (process.platform === "win32")
      self.cwdAbs = self.cwdAbs.replace(/\\/g, "/");
    self.nomount = !!options.nomount;
  
    // disable comments and negation in Minimatch.
    // Note that they are not supported in Glob itself anyway.
    options.nonegate = true;
    options.nocomment = true;
  
    self.minimatch = new Minimatch$1(pattern, options);
    self.options = self.minimatch.options;
  }
  
  function finish (self) {
    var nou = self.nounique;
    var all = nou ? [] : Object.create(null);
  
    for (var i = 0, l = self.matches.length; i < l; i ++) {
      var matches = self.matches[i];
      if (!matches || Object.keys(matches).length === 0) {
        if (self.nonull) {
          // do like the shell, and spit out the literal glob
          var literal = self.minimatch.globSet[i];
          if (nou)
            all.push(literal);
          else
            all[literal] = true;
        }
      } else {
        // had matches
        var m = Object.keys(matches);
        if (nou)
          all.push.apply(all, m);
        else
          m.forEach(function (m) {
            all[m] = true;
          });
      }
    }
  
    if (!nou)
      all = Object.keys(all);
  
    if (!self.nosort)
      all = all.sort(self.nocase ? alphasorti : alphasort);
  
    // at *some* point we statted all of these
    if (self.mark) {
      for (var i = 0; i < all.length; i++) {
        all[i] = self._mark(all[i]);
      }
      if (self.nodir) {
        all = all.filter(function (e) {
          var notDir = !(/\/$/.test(e));
          var c = self.cache[e] || self.cache[makeAbs(self, e)];
          if (notDir && c)
            notDir = c !== 'DIR' && !Array.isArray(c);
          return notDir
        });
      }
    }
  
    if (self.ignore.length)
      all = all.filter(function(m) {
        return !isIgnored(self, m)
      });
  
    self.found = all;
  }
  
  function mark (self, p) {
    var abs = makeAbs(self, p);
    var c = self.cache[abs];
    var m = p;
    if (c) {
      var isDir = c === 'DIR' || Array.isArray(c);
      var slash = p.slice(-1) === '/';
  
      if (isDir && !slash)
        m += '/';
      else if (!isDir && slash)
        m = m.slice(0, -1);
  
      if (m !== p) {
        var mabs = makeAbs(self, m);
        self.statCache[mabs] = self.statCache[abs];
        self.cache[mabs] = self.cache[abs];
      }
    }
  
    return m
  }
  
  // lotta situps...
  function makeAbs (self, f) {
    var abs = f;
    if (f.charAt(0) === '/') {
      abs = path$1__default.join(self.root, f);
    } else if (path$1.isAbsolute(f) || f === '') {
      abs = f;
    } else if (self.changedCwd) {
      abs = path$1__default.resolve(self.cwd, f);
    } else {
      abs = path$1__default.resolve(f);
    }
  
    if (process.platform === 'win32')
      abs = abs.replace(/\\/g, '/');
  
    return abs
  }
  
  
  // Return true, if pattern ends with globstar '**', for the accompanying parent directory.
  // Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents
  function isIgnored (self, path) {
    if (!self.ignore.length)
      return false
  
    return self.ignore.some(function(item) {
      return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path))
    })
  }
  
  function childrenIgnored (self, path) {
    if (!self.ignore.length)
      return false
  
    return self.ignore.some(function(item) {
      return !!(item.gmatcher && item.gmatcher.match(path))
    })
  }
  
  var common = {
  	alphasort: alphasort_1,
  	alphasorti: alphasorti_1,
  	setopts: setopts_1,
  	ownProp: ownProp_1,
  	makeAbs: makeAbs_1,
  	finish: finish_1,
  	mark: mark_1,
  	isIgnored: isIgnored_1,
  	childrenIgnored: childrenIgnored_1
  };
  
  var sync = globSync;
  globSync.GlobSync = GlobSync;
  var setopts$1 = common.setopts;
  var ownProp$1 = common.ownProp;
  var childrenIgnored$1 = common.childrenIgnored;
  var isIgnored$1 = common.isIgnored;
  
  function globSync (pattern, options) {
    if (typeof options === 'function' || arguments.length === 3)
      throw new TypeError('callback provided to sync glob\n'+
                          'See: https://github.com/isaacs/node-glob/issues/167')
  
    return new GlobSync(pattern, options).found
  }
  
  function GlobSync (pattern, options) {
    if (!pattern)
      throw new Error('must provide pattern')
  
    if (typeof options === 'function' || arguments.length === 3)
      throw new TypeError('callback provided to sync glob\n'+
                          'See: https://github.com/isaacs/node-glob/issues/167')
  
    if (!(this instanceof GlobSync))
      return new GlobSync(pattern, options)
  
    setopts$1(this, pattern, options);
  
    if (this.noprocess)
      return this
  
    var n = this.minimatch.set.length;
    this.matches = new Array(n);
    for (var i = 0; i < n; i ++) {
      this._process(this.minimatch.set[i], i, false);
    }
    this._finish();
  }
  
  GlobSync.prototype._finish = function () {
    assert(this instanceof GlobSync);
    if (this.realpath) {
      var self = this;
      this.matches.forEach(function (matchset, index) {
        var set = self.matches[index] = Object.create(null);
        for (var p in matchset) {
          try {
            p = self._makeAbs(p);
            var real = fs_realpath.realpathSync(p, self.realpathCache);
            set[real] = true;
          } catch (er) {
            if (er.syscall === 'stat')
              set[self._makeAbs(p)] = true;
            else
              throw er
          }
        }
      });
    }
    common.finish(this);
  };
  
  
  GlobSync.prototype._process = function (pattern, index, inGlobStar) {
    assert(this instanceof GlobSync);
  
    // Get the first [n] parts of pattern that are all strings.
    var n = 0;
    while (typeof pattern[n] === 'string') {
      n ++;
    }
    // now n is the index of the first one that is *not* a string.
  
    // See if there's anything else
    var prefix;
    switch (n) {
      // if not, then this is rather simple
      case pattern.length:
        this._processSimple(pattern.join('/'), index);
        return
  
      case 0:
        // pattern *starts* with some non-trivial item.
        // going to readdir(cwd), but not include the prefix in matches.
        prefix = null;
        break
  
      default:
        // pattern has some string bits in the front.
        // whatever it starts with, whether that's 'absolute' like /foo/bar,
        // or 'relative' like '../baz'
        prefix = pattern.slice(0, n).join('/');
        break
    }
  
    var remain = pattern.slice(n);
  
    // get the list of entries.
    var read;
    if (prefix === null)
      read = '.';
    else if (path$1.isAbsolute(prefix) || path$1.isAbsolute(pattern.join('/'))) {
      if (!prefix || !path$1.isAbsolute(prefix))
        prefix = '/' + prefix;
      read = prefix;
    } else
      read = prefix;
  
    var abs = this._makeAbs(read);
  
    //if ignored, skip processing
    if (childrenIgnored$1(this, read))
      return
  
    var isGlobStar = remain[0] === minimatch_1.GLOBSTAR;
    if (isGlobStar)
      this._processGlobStar(prefix, read, abs, remain, index, inGlobStar);
    else
      this._processReaddir(prefix, read, abs, remain, index, inGlobStar);
  };
  
  
  GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) {
    var entries = this._readdir(abs, inGlobStar);
  
    // if the abs isn't a dir, then nothing can match!
    if (!entries)
      return
  
    // It will only match dot entries if it starts with a dot, or if
    // dot is set.  Stuff like @(.foo|.bar) isn't allowed.
    var pn = remain[0];
    var negate = !!this.minimatch.negate;
    var rawGlob = pn._glob;
    var dotOk = this.dot || rawGlob.charAt(0) === '.';
  
    var matchedEntries = [];
    for (var i = 0; i < entries.length; i++) {
      var e = entries[i];
      if (e.charAt(0) !== '.' || dotOk) {
        var m;
        if (negate && !prefix) {
          m = !e.match(pn);
        } else {
          m = e.match(pn);
        }
        if (m)
          matchedEntries.push(e);
      }
    }
  
    var len = matchedEntries.length;
    // If there are no matched entries, then nothing matches.
    if (len === 0)
      return
  
    // if this is the last remaining pattern bit, then no need for
    // an additional stat *unless* the user has specified mark or
    // stat explicitly.  We know they exist, since readdir returned
    // them.
  
    if (remain.length === 1 && !this.mark && !this.stat) {
      if (!this.matches[index])
        this.matches[index] = Object.create(null);
  
      for (var i = 0; i < len; i ++) {
        var e = matchedEntries[i];
        if (prefix) {
          if (prefix.slice(-1) !== '/')
            e = prefix + '/' + e;
          else
            e = prefix + e;
        }
  
        if (e.charAt(0) === '/' && !this.nomount) {
          e = path$1__default.join(this.root, e);
        }
        this._emitMatch(index, e);
      }
      // This was the last one, and no stats were needed
      return
    }
  
    // now test all matched entries as stand-ins for that part
    // of the pattern.
    remain.shift();
    for (var i = 0; i < len; i ++) {
      var e = matchedEntries[i];
      var newPattern;
      if (prefix)
        newPattern = [prefix, e];
      else
        newPattern = [e];
      this._process(newPattern.concat(remain), index, inGlobStar);
    }
  };
  
  
  GlobSync.prototype._emitMatch = function (index, e) {
    if (isIgnored$1(this, e))
      return
  
    var abs = this._makeAbs(e);
  
    if (this.mark)
      e = this._mark(e);
  
    if (this.absolute) {
      e = abs;
    }
  
    if (this.matches[index][e])
      return
  
    if (this.nodir) {
      var c = this.cache[abs];
      if (c === 'DIR' || Array.isArray(c))
        return
    }
  
    this.matches[index][e] = true;
  
    if (this.stat)
      this._stat(e);
  };
  
  
  GlobSync.prototype._readdirInGlobStar = function (abs) {
    // follow all symlinked directories forever
    // just proceed as if this is a non-globstar situation
    if (this.follow)
      return this._readdir(abs, false)
  
    var entries;
    var lstat;
    try {
      lstat = fs$1.lstatSync(abs);
    } catch (er) {
      if (er.code === 'ENOENT') {
        // lstat failed, doesn't exist
        return null
      }
    }
  
    var isSym = lstat && lstat.isSymbolicLink();
    this.symlinks[abs] = isSym;
  
    // If it's not a symlink or a dir, then it's definitely a regular file.
    // don't bother doing a readdir in that case.
    if (!isSym && lstat && !lstat.isDirectory())
      this.cache[abs] = 'FILE';
    else
      entries = this._readdir(abs, false);
  
    return entries
  };
  
  GlobSync.prototype._readdir = function (abs, inGlobStar) {
  
    if (inGlobStar && !ownProp$1(this.symlinks, abs))
      return this._readdirInGlobStar(abs)
  
    if (ownProp$1(this.cache, abs)) {
      var c = this.cache[abs];
      if (!c || c === 'FILE')
        return null
  
      if (Array.isArray(c))
        return c
    }
  
    try {
      return this._readdirEntries(abs, fs$1.readdirSync(abs))
    } catch (er) {
      this._readdirError(abs, er);
      return null
    }
  };
  
  GlobSync.prototype._readdirEntries = function (abs, entries) {
    // if we haven't asked to stat everything, then just
    // assume that everything in there exists, so we can avoid
    // having to stat it a second time.
    if (!this.mark && !this.stat) {
      for (var i = 0; i < entries.length; i ++) {
        var e = entries[i];
        if (abs === '/')
          e = abs + e;
        else
          e = abs + '/' + e;
        this.cache[e] = true;
      }
    }
  
    this.cache[abs] = entries;
  
    // mark and cache dir-ness
    return entries
  };
  
  GlobSync.prototype._readdirError = function (f, er) {
    // handle errors, and cache the information
    switch (er.code) {
      case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205
      case 'ENOTDIR': // totally normal. means it *does* exist.
        var abs = this._makeAbs(f);
        this.cache[abs] = 'FILE';
        if (abs === this.cwdAbs) {
          var error = new Error(er.code + ' invalid cwd ' + this.cwd);
          error.path = this.cwd;
          error.code = er.code;
          throw error
        }
        break
  
      case 'ENOENT': // not terribly unusual
      case 'ELOOP':
      case 'ENAMETOOLONG':
      case 'UNKNOWN':
        this.cache[this._makeAbs(f)] = false;
        break
  
      default: // some unusual error.  Treat as failure.
        this.cache[this._makeAbs(f)] = false;
        if (this.strict)
          throw er
        if (!this.silent)
          console.error('glob error', er);
        break
    }
  };
  
  GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) {
  
    var entries = this._readdir(abs, inGlobStar);
  
    // no entries means not a dir, so it can never have matches
    // foo.txt/** doesn't match foo.txt
    if (!entries)
      return
  
    // test without the globstar, and with every child both below
    // and replacing the globstar.
    var remainWithoutGlobStar = remain.slice(1);
    var gspref = prefix ? [ prefix ] : [];
    var noGlobStar = gspref.concat(remainWithoutGlobStar);
  
    // the noGlobStar pattern exits the inGlobStar state
    this._process(noGlobStar, index, false);
  
    var len = entries.length;
    var isSym = this.symlinks[abs];
  
    // If it's a symlink, and we're in a globstar, then stop
    if (isSym && inGlobStar)
      return
  
    for (var i = 0; i < len; i++) {
      var e = entries[i];
      if (e.charAt(0) === '.' && !this.dot)
        continue
  
      // these two cases enter the inGlobStar state
      var instead = gspref.concat(entries[i], remainWithoutGlobStar);
      this._process(instead, index, true);
  
      var below = gspref.concat(entries[i], remain);
      this._process(below, index, true);
    }
  };
  
  GlobSync.prototype._processSimple = function (prefix, index) {
    // XXX review this.  Shouldn't it be doing the mounting etc
    // before doing stat?  kinda weird?
    var exists = this._stat(prefix);
  
    if (!this.matches[index])
      this.matches[index] = Object.create(null);
  
    // If it doesn't exist, then just mark the lack of results
    if (!exists)
      return
  
    if (prefix && path$1.isAbsolute(prefix) && !this.nomount) {
      var trail = /[\/\\]$/.test(prefix);
      if (prefix.charAt(0) === '/') {
        prefix = path$1__default.join(this.root, prefix);
      } else {
        prefix = path$1__default.resolve(this.root, prefix);
        if (trail)
          prefix += '/';
      }
    }
  
    if (process.platform === 'win32')
      prefix = prefix.replace(/\\/g, '/');
  
    // Mark this as a match
    this._emitMatch(index, prefix);
  };
  
  // Returns either 'DIR', 'FILE', or false
  GlobSync.prototype._stat = function (f) {
    var abs = this._makeAbs(f);
    var needDir = f.slice(-1) === '/';
  
    if (f.length > this.maxLength)
      return false
  
    if (!this.stat && ownProp$1(this.cache, abs)) {
      var c = this.cache[abs];
  
      if (Array.isArray(c))
        c = 'DIR';
  
      // It exists, but maybe not how we need it
      if (!needDir || c === 'DIR')
        return c
  
      if (needDir && c === 'FILE')
        return false
  
      // otherwise we have to stat, because maybe c=true
      // if we know it exists, but not what it is.
    }
    var stat = this.statCache[abs];
    if (!stat) {
      var lstat;
      try {
        lstat = fs$1.lstatSync(abs);
      } catch (er) {
        if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
          this.statCache[abs] = false;
          return false
        }
      }
  
      if (lstat && lstat.isSymbolicLink()) {
        try {
          stat = fs$1.statSync(abs);
        } catch (er) {
          stat = lstat;
        }
      } else {
        stat = lstat;
      }
    }
  
    this.statCache[abs] = stat;
  
    var c = true;
    if (stat)
      c = stat.isDirectory() ? 'DIR' : 'FILE';
  
    this.cache[abs] = this.cache[abs] || c;
  
    if (needDir && c === 'FILE')
      return false
  
    return c
  };
  
  GlobSync.prototype._mark = function (p) {
    return common.mark(this, p)
  };
  
  GlobSync.prototype._makeAbs = function (f) {
    return common.makeAbs(this, f)
  };
  
  // Returns a wrapper function that returns a wrapped callback
  // The wrapper function should do some stuff, and return a
  // presumably different callback function.
  // This makes sure that own properties are retained, so that
  // decorations and such are not lost along the way.
  var wrappy_1 = wrappy;
  function wrappy (fn, cb) {
    if (fn && cb) return wrappy(fn)(cb)
  
    if (typeof fn !== 'function')
      throw new TypeError('need wrapper function')
  
    Object.keys(fn).forEach(function (k) {
      wrapper[k] = fn[k];
    });
  
    return wrapper
  
    function wrapper() {
      var args = new Array(arguments.length);
      for (var i = 0; i < args.length; i++) {
        args[i] = arguments[i];
      }
      var ret = fn.apply(this, args);
      var cb = args[args.length-1];
      if (typeof ret === 'function' && ret !== cb) {
        Object.keys(cb).forEach(function (k) {
          ret[k] = cb[k];
        });
      }
      return ret
    }
  }
  
  var once_1 = wrappy_1(once);
  var strict = wrappy_1(onceStrict);
  
  once.proto = once(function () {
    Object.defineProperty(Function.prototype, 'once', {
      value: function () {
        return once(this)
      },
      configurable: true
    });
  
    Object.defineProperty(Function.prototype, 'onceStrict', {
      value: function () {
        return onceStrict(this)
      },
      configurable: true
    });
  });
  
  function once (fn) {
    var f = function () {
      if (f.called) return f.value
      f.called = true;
      return f.value = fn.apply(this, arguments)
    };
    f.called = false;
    return f
  }
  
  function onceStrict (fn) {
    var f = function () {
      if (f.called)
        throw new Error(f.onceError)
      f.called = true;
      return f.value = fn.apply(this, arguments)
    };
    var name = fn.name || 'Function wrapped with `once`';
    f.onceError = name + " shouldn't be called more than once";
    f.called = false;
    return f
  }
  once_1.strict = strict;
  
  var reqs = Object.create(null);
  
  
  var inflight_1 = wrappy_1(inflight);
  
  function inflight (key, cb) {
    if (reqs[key]) {
      reqs[key].push(cb);
      return null
    } else {
      reqs[key] = [cb];
      return makeres(key)
    }
  }
  
  function makeres (key) {
    return once_1(function RES () {
      var cbs = reqs[key];
      var len = cbs.length;
      var args = slice(arguments);
  
      // XXX It's somewhat ambiguous whether a new callback added in this
      // pass should be queued for later execution if something in the
      // list of callbacks throws, or if it should just be discarded.
      // However, it's such an edge case that it hardly matters, and either
      // choice is likely as surprising as the other.
      // As it happens, we do go ahead and schedule it for later execution.
      try {
        for (var i = 0; i < len; i++) {
          cbs[i].apply(null, args);
        }
      } finally {
        if (cbs.length > len) {
          // added more in the interim.
          // de-zalgo, just in case, but don't call again.
          cbs.splice(0, len);
          process.nextTick(function () {
            RES.apply(null, args);
          });
        } else {
          delete reqs[key];
        }
      }
    })
  }
  
  function slice (args) {
    var length = args.length;
    var array = [];
  
    for (var i = 0; i < length; i++) array[i] = args[i];
    return array
  }
  
  // Approach:
  //
  // 1. Get the minimatch set
  // 2. For each pattern in the set, PROCESS(pattern, false)
  // 3. Store matches per-set, then uniq them
  //
  // PROCESS(pattern, inGlobStar)
  // Get the first [n] items from pattern that are all strings
  // Join these together.  This is PREFIX.
  //   If there is no more remaining, then stat(PREFIX) and
  //   add to matches if it succeeds.  END.
  //
  // If inGlobStar and PREFIX is symlink and points to dir
  //   set ENTRIES = []
  // else readdir(PREFIX) as ENTRIES
  //   If fail, END
  //
  // with ENTRIES
  //   If pattern[n] is GLOBSTAR
  //     // handle the case where the globstar match is empty
  //     // by pruning it out, and testing the resulting pattern
  //     PROCESS(pattern[0..n] + pattern[n+1 .. $], false)
  //     // handle other cases.
  //     for ENTRY in ENTRIES (not dotfiles)
  //       // attach globstar + tail onto the entry
  //       // Mark that this entry is a globstar match
  //       PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true)
  //
  //   else // not globstar
  //     for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
  //       Test ENTRY against pattern[n]
  //       If fails, continue
  //       If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
  //
  // Caveat:
  //   Cache all stats and readdirs results to minimize syscall.  Since all
  //   we ever care about is existence and directory-ness, we can just keep
  //   `true` for files, and [children,...] for directories, or `false` for
  //   things that don't exist.
  
  var glob_1 = glob;
  
  var EE = events.EventEmitter;
  var setopts$2 = common.setopts;
  var ownProp$2 = common.ownProp;
  
  
  var childrenIgnored$2 = common.childrenIgnored;
  var isIgnored$2 = common.isIgnored;
  
  
  
  function glob (pattern, options, cb) {
    if (typeof options === 'function') cb = options, options = {};
    if (!options) options = {};
  
    if (options.sync) {
      if (cb)
        throw new TypeError('callback provided to sync glob')
      return sync(pattern, options)
    }
  
    return new Glob(pattern, options, cb)
  }
  
  glob.sync = sync;
  var GlobSync$1 = glob.GlobSync = sync.GlobSync;
  
  // old api surface
  glob.glob = glob;
  
  function extend (origin, add) {
    if (add === null || typeof add !== 'object') {
      return origin
    }
  
    var keys = Object.keys(add);
    var i = keys.length;
    while (i--) {
      origin[keys[i]] = add[keys[i]];
    }
    return origin
  }
  
  glob.hasMagic = function (pattern, options_) {
    var options = extend({}, options_);
    options.noprocess = true;
  
    var g = new Glob(pattern, options);
    var set = g.minimatch.set;
  
    if (!pattern)
      return false
  
    if (set.length > 1)
      return true
  
    for (var j = 0; j < set[0].length; j++) {
      if (typeof set[0][j] !== 'string')
        return true
    }
  
    return false
  };
  
  glob.Glob = Glob;
  inherits(Glob, EE);
  function Glob (pattern, options, cb) {
    if (typeof options === 'function') {
      cb = options;
      options = null;
    }
  
    if (options && options.sync) {
      if (cb)
        throw new TypeError('callback provided to sync glob')
      return new GlobSync$1(pattern, options)
    }
  
    if (!(this instanceof Glob))
      return new Glob(pattern, options, cb)
  
    setopts$2(this, pattern, options);
    this._didRealPath = false;
  
    // process each pattern in the minimatch set
    var n = this.minimatch.set.length;
  
    // The matches are stored as {<filename>: true,...} so that
    // duplicates are automagically pruned.
    // Later, we do an Object.keys() on these.
    // Keep them as a list so we can fill in when nonull is set.
    this.matches = new Array(n);
  
    if (typeof cb === 'function') {
      cb = once_1(cb);
      this.on('error', cb);
      this.on('end', function (matches) {
        cb(null, matches);
      });
    }
  
    var self = this;
    this._processing = 0;
  
    this._emitQueue = [];
    this._processQueue = [];
    this.paused = false;
  
    if (this.noprocess)
      return this
  
    if (n === 0)
      return done()
  
    var sync = true;
    for (var i = 0; i < n; i ++) {
      this._process(this.minimatch.set[i], i, false, done);
    }
    sync = false;
  
    function done () {
      --self._processing;
      if (self._processing <= 0) {
        if (sync) {
          process.nextTick(function () {
            self._finish();
          });
        } else {
          self._finish();
        }
      }
    }
  }
  
  Glob.prototype._finish = function () {
    assert(this instanceof Glob);
    if (this.aborted)
      return
  
    if (this.realpath && !this._didRealpath)
      return this._realpath()
  
    common.finish(this);
    this.emit('end', this.found);
  };
  
  Glob.prototype._realpath = function () {
    if (this._didRealpath)
      return
  
    this._didRealpath = true;
  
    var n = this.matches.length;
    if (n === 0)
      return this._finish()
  
    var self = this;
    for (var i = 0; i < this.matches.length; i++)
      this._realpathSet(i, next);
  
    function next () {
      if (--n === 0)
        self._finish();
    }
  };
  
  Glob.prototype._realpathSet = function (index, cb) {
    var matchset = this.matches[index];
    if (!matchset)
      return cb()
  
    var found = Object.keys(matchset);
    var self = this;
    var n = found.length;
  
    if (n === 0)
      return cb()
  
    var set = this.matches[index] = Object.create(null);
    found.forEach(function (p, i) {
      // If there's a problem with the stat, then it means that
      // one or more of the links in the realpath couldn't be
      // resolved.  just return the abs value in that case.
      p = self._makeAbs(p);
      fs_realpath.realpath(p, self.realpathCache, function (er, real) {
        if (!er)
          set[real] = true;
        else if (er.syscall === 'stat')
          set[p] = true;
        else
          self.emit('error', er); // srsly wtf right here
  
        if (--n === 0) {
          self.matches[index] = set;
          cb();
        }
      });
    });
  };
  
  Glob.prototype._mark = function (p) {
    return common.mark(this, p)
  };
  
  Glob.prototype._makeAbs = function (f) {
    return common.makeAbs(this, f)
  };
  
  Glob.prototype.abort = function () {
    this.aborted = true;
    this.emit('abort');
  };
  
  Glob.prototype.pause = function () {
    if (!this.paused) {
      this.paused = true;
      this.emit('pause');
    }
  };
  
  Glob.prototype.resume = function () {
    if (this.paused) {
      this.emit('resume');
      this.paused = false;
      if (this._emitQueue.length) {
        var eq = this._emitQueue.slice(0);
        this._emitQueue.length = 0;
        for (var i = 0; i < eq.length; i ++) {
          var e = eq[i];
          this._emitMatch(e[0], e[1]);
        }
      }
      if (this._processQueue.length) {
        var pq = this._processQueue.slice(0);
        this._processQueue.length = 0;
        for (var i = 0; i < pq.length; i ++) {
          var p = pq[i];
          this._processing--;
          this._process(p[0], p[1], p[2], p[3]);
        }
      }
    }
  };
  
  Glob.prototype._process = function (pattern, index, inGlobStar, cb) {
    assert(this instanceof Glob);
    assert(typeof cb === 'function');
  
    if (this.aborted)
      return
  
    this._processing++;
    if (this.paused) {
      this._processQueue.push([pattern, index, inGlobStar, cb]);
      return
    }
  
    //console.error('PROCESS %d', this._processing, pattern)
  
    // Get the first [n] parts of pattern that are all strings.
    var n = 0;
    while (typeof pattern[n] === 'string') {
      n ++;
    }
    // now n is the index of the first one that is *not* a string.
  
    // see if there's anything else
    var prefix;
    switch (n) {
      // if not, then this is rather simple
      case pattern.length:
        this._processSimple(pattern.join('/'), index, cb);
        return
  
      case 0:
        // pattern *starts* with some non-trivial item.
        // going to readdir(cwd), but not include the prefix in matches.
        prefix = null;
        break
  
      default:
        // pattern has some string bits in the front.
        // whatever it starts with, whether that's 'absolute' like /foo/bar,
        // or 'relative' like '../baz'
        prefix = pattern.slice(0, n).join('/');
        break
    }
  
    var remain = pattern.slice(n);
  
    // get the list of entries.
    var read;
    if (prefix === null)
      read = '.';
    else if (path$1.isAbsolute(prefix) || path$1.isAbsolute(pattern.join('/'))) {
      if (!prefix || !path$1.isAbsolute(prefix))
        prefix = '/' + prefix;
      read = prefix;
    } else
      read = prefix;
  
    var abs = this._makeAbs(read);
  
    //if ignored, skip _processing
    if (childrenIgnored$2(this, read))
      return cb()
  
    var isGlobStar = remain[0] === minimatch_1.GLOBSTAR;
    if (isGlobStar)
      this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb);
    else
      this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb);
  };
  
  Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) {
    var self = this;
    this._readdir(abs, inGlobStar, function (er, entries) {
      return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb)
    });
  };
  
  Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) {
  
    // if the abs isn't a dir, then nothing can match!
    if (!entries)
      return cb()
  
    // It will only match dot entries if it starts with a dot, or if
    // dot is set.  Stuff like @(.foo|.bar) isn't allowed.
    var pn = remain[0];
    var negate = !!this.minimatch.negate;
    var rawGlob = pn._glob;
    var dotOk = this.dot || rawGlob.charAt(0) === '.';
  
    var matchedEntries = [];
    for (var i = 0; i < entries.length; i++) {
      var e = entries[i];
      if (e.charAt(0) !== '.' || dotOk) {
        var m;
        if (negate && !prefix) {
          m = !e.match(pn);
        } else {
          m = e.match(pn);
        }
        if (m)
          matchedEntries.push(e);
      }
    }
  
    //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries)
  
    var len = matchedEntries.length;
    // If there are no matched entries, then nothing matches.
    if (len === 0)
      return cb()
  
    // if this is the last remaining pattern bit, then no need for
    // an additional stat *unless* the user has specified mark or
    // stat explicitly.  We know they exist, since readdir returned
    // them.
  
    if (remain.length === 1 && !this.mark && !this.stat) {
      if (!this.matches[index])
        this.matches[index] = Object.create(null);
  
      for (var i = 0; i < len; i ++) {
        var e = matchedEntries[i];
        if (prefix) {
          if (prefix !== '/')
            e = prefix + '/' + e;
          else
            e = prefix + e;
        }
  
        if (e.charAt(0) === '/' && !this.nomount) {
          e = path$1__default.join(this.root, e);
        }
        this._emitMatch(index, e);
      }
      // This was the last one, and no stats were needed
      return cb()
    }
  
    // now test all matched entries as stand-ins for that part
    // of the pattern.
    remain.shift();
    for (var i = 0; i < len; i ++) {
      var e = matchedEntries[i];
      if (prefix) {
        if (prefix !== '/')
          e = prefix + '/' + e;
        else
          e = prefix + e;
      }
      this._process([e].concat(remain), index, inGlobStar, cb);
    }
    cb();
  };
  
  Glob.prototype._emitMatch = function (index, e) {
    if (this.aborted)
      return
  
    if (isIgnored$2(this, e))
      return
  
    if (this.paused) {
      this._emitQueue.push([index, e]);
      return
    }
  
    var abs = path$1.isAbsolute(e) ? e : this._makeAbs(e);
  
    if (this.mark)
      e = this._mark(e);
  
    if (this.absolute)
      e = abs;
  
    if (this.matches[index][e])
      return
  
    if (this.nodir) {
      var c = this.cache[abs];
      if (c === 'DIR' || Array.isArray(c))
        return
    }
  
    this.matches[index][e] = true;
  
    var st = this.statCache[abs];
    if (st)
      this.emit('stat', e, st);
  
    this.emit('match', e);
  };
  
  Glob.prototype._readdirInGlobStar = function (abs, cb) {
    if (this.aborted)
      return
  
    // follow all symlinked directories forever
    // just proceed as if this is a non-globstar situation
    if (this.follow)
      return this._readdir(abs, false, cb)
  
    var lstatkey = 'lstat\0' + abs;
    var self = this;
    var lstatcb = inflight_1(lstatkey, lstatcb_);
  
    if (lstatcb)
      fs$1.lstat(abs, lstatcb);
  
    function lstatcb_ (er, lstat) {
      if (er && er.code === 'ENOENT')
        return cb()
  
      var isSym = lstat && lstat.isSymbolicLink();
      self.symlinks[abs] = isSym;
  
      // If it's not a symlink or a dir, then it's definitely a regular file.
      // don't bother doing a readdir in that case.
      if (!isSym && lstat && !lstat.isDirectory()) {
        self.cache[abs] = 'FILE';
        cb();
      } else
        self._readdir(abs, false, cb);
    }
  };
  
  Glob.prototype._readdir = function (abs, inGlobStar, cb) {
    if (this.aborted)
      return
  
    cb = inflight_1('readdir\0'+abs+'\0'+inGlobStar, cb);
    if (!cb)
      return
  
    //console.error('RD %j %j', +inGlobStar, abs)
    if (inGlobStar && !ownProp$2(this.symlinks, abs))
      return this._readdirInGlobStar(abs, cb)
  
    if (ownProp$2(this.cache, abs)) {
      var c = this.cache[abs];
      if (!c || c === 'FILE')
        return cb()
  
      if (Array.isArray(c))
        return cb(null, c)
    }
    fs$1.readdir(abs, readdirCb(this, abs, cb));
  };
  
  function readdirCb (self, abs, cb) {
    return function (er, entries) {
      if (er)
        self._readdirError(abs, er, cb);
      else
        self._readdirEntries(abs, entries, cb);
    }
  }
  
  Glob.prototype._readdirEntries = function (abs, entries, cb) {
    if (this.aborted)
      return
  
    // if we haven't asked to stat everything, then just
    // assume that everything in there exists, so we can avoid
    // having to stat it a second time.
    if (!this.mark && !this.stat) {
      for (var i = 0; i < entries.length; i ++) {
        var e = entries[i];
        if (abs === '/')
          e = abs + e;
        else
          e = abs + '/' + e;
        this.cache[e] = true;
      }
    }
  
    this.cache[abs] = entries;
    return cb(null, entries)
  };
  
  Glob.prototype._readdirError = function (f, er, cb) {
    if (this.aborted)
      return
  
    // handle errors, and cache the information
    switch (er.code) {
      case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205
      case 'ENOTDIR': // totally normal. means it *does* exist.
        var abs = this._makeAbs(f);
        this.cache[abs] = 'FILE';
        if (abs === this.cwdAbs) {
          var error = new Error(er.code + ' invalid cwd ' + this.cwd);
          error.path = this.cwd;
          error.code = er.code;
          this.emit('error', error);
          this.abort();
        }
        break
  
      case 'ENOENT': // not terribly unusual
      case 'ELOOP':
      case 'ENAMETOOLONG':
      case 'UNKNOWN':
        this.cache[this._makeAbs(f)] = false;
        break
  
      default: // some unusual error.  Treat as failure.
        this.cache[this._makeAbs(f)] = false;
        if (this.strict) {
          this.emit('error', er);
          // If the error is handled, then we abort
          // if not, we threw out of here
          this.abort();
        }
        if (!this.silent)
          console.error('glob error', er);
        break
    }
  
    return cb()
  };
  
  Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) {
    var self = this;
    this._readdir(abs, inGlobStar, function (er, entries) {
      self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb);
    });
  };
  
  
  Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) {
    //console.error('pgs2', prefix, remain[0], entries)
  
    // no entries means not a dir, so it can never have matches
    // foo.txt/** doesn't match foo.txt
    if (!entries)
      return cb()
  
    // test without the globstar, and with every child both below
    // and replacing the globstar.
    var remainWithoutGlobStar = remain.slice(1);
    var gspref = prefix ? [ prefix ] : [];
    var noGlobStar = gspref.concat(remainWithoutGlobStar);
  
    // the noGlobStar pattern exits the inGlobStar state
    this._process(noGlobStar, index, false, cb);
  
    var isSym = this.symlinks[abs];
    var len = entries.length;
  
    // If it's a symlink, and we're in a globstar, then stop
    if (isSym && inGlobStar)
      return cb()
  
    for (var i = 0; i < len; i++) {
      var e = entries[i];
      if (e.charAt(0) === '.' && !this.dot)
        continue
  
      // these two cases enter the inGlobStar state
      var instead = gspref.concat(entries[i], remainWithoutGlobStar);
      this._process(instead, index, true, cb);
  
      var below = gspref.concat(entries[i], remain);
      this._process(below, index, true, cb);
    }
  
    cb();
  };
  
  Glob.prototype._processSimple = function (prefix, index, cb) {
    // XXX review this.  Shouldn't it be doing the mounting etc
    // before doing stat?  kinda weird?
    var self = this;
    this._stat(prefix, function (er, exists) {
      self._processSimple2(prefix, index, er, exists, cb);
    });
  };
  Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) {
  
    //console.error('ps2', prefix, exists)
  
    if (!this.matches[index])
      this.matches[index] = Object.create(null);
  
    // If it doesn't exist, then just mark the lack of results
    if (!exists)
      return cb()
  
    if (prefix && path$1.isAbsolute(prefix) && !this.nomount) {
      var trail = /[\/\\]$/.test(prefix);
      if (prefix.charAt(0) === '/') {
        prefix = path$1__default.join(this.root, prefix);
      } else {
        prefix = path$1__default.resolve(this.root, prefix);
        if (trail)
          prefix += '/';
      }
    }
  
    if (process.platform === 'win32')
      prefix = prefix.replace(/\\/g, '/');
  
    // Mark this as a match
    this._emitMatch(index, prefix);
    cb();
  };
  
  // Returns either 'DIR', 'FILE', or false
  Glob.prototype._stat = function (f, cb) {
    var abs = this._makeAbs(f);
    var needDir = f.slice(-1) === '/';
  
    if (f.length > this.maxLength)
      return cb()
  
    if (!this.stat && ownProp$2(this.cache, abs)) {
      var c = this.cache[abs];
  
      if (Array.isArray(c))
        c = 'DIR';
  
      // It exists, but maybe not how we need it
      if (!needDir || c === 'DIR')
        return cb(null, c)
  
      if (needDir && c === 'FILE')
        return cb()
  
      // otherwise we have to stat, because maybe c=true
      // if we know it exists, but not what it is.
    }
    var stat = this.statCache[abs];
    if (stat !== undefined) {
      if (stat === false)
        return cb(null, stat)
      else {
        var type = stat.isDirectory() ? 'DIR' : 'FILE';
        if (needDir && type === 'FILE')
          return cb()
        else
          return cb(null, type, stat)
      }
    }
  
    var self = this;
    var statcb = inflight_1('stat\0' + abs, lstatcb_);
    if (statcb)
      fs$1.lstat(abs, statcb);
  
    function lstatcb_ (er, lstat) {
      if (lstat && lstat.isSymbolicLink()) {
        // If it's a symlink, then treat it as the target, unless
        // the target does not exist, then treat it as a file.
        return fs$1.stat(abs, function (er, stat) {
          if (er)
            self._stat2(f, abs, null, lstat, cb);
          else
            self._stat2(f, abs, er, stat, cb);
        })
      } else {
        self._stat2(f, abs, er, lstat, cb);
      }
    }
  };
  
  Glob.prototype._stat2 = function (f, abs, er, stat, cb) {
    if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
      this.statCache[abs] = false;
      return cb()
    }
  
    var needDir = f.slice(-1) === '/';
    this.statCache[abs] = stat;
  
    if (abs.slice(-1) === '/' && stat && !stat.isDirectory())
      return cb(null, false, stat)
  
    var c = true;
    if (stat)
      c = stat.isDirectory() ? 'DIR' : 'FILE';
    this.cache[abs] = this.cache[abs] || c;
  
    if (needDir && c === 'FILE')
      return cb()
  
    return cb(null, c, stat)
  };
  
  async function nodeCopyTasks(copyTasks, srcDir) {
      const results = {
          diagnostics: [],
          dirPaths: [],
          filePaths: [],
      };
      try {
          copyTasks = flatOne(await Promise.all(copyTasks.map(task => processGlobs(task, srcDir))));
          copyTasks = unique(copyTasks, task => task.dest);
          const allCopyTasks = [];
          // figure out all the file copy tasks we'll have
          // by digging down through any directory copy tasks
          while (copyTasks.length > 0) {
              const tasks = copyTasks.splice(0, 100);
              await Promise.all(tasks.map(copyTask => processCopyTask(results, allCopyTasks, copyTask)));
          }
          // figure out which directories we'll need to make first
          const mkDirs = ensureDirs(allCopyTasks);
          try {
              await Promise.all(mkDirs.map(dir => mkdir(dir, { recursive: true })));
          }
          catch (mkDirErr) { }
          while (allCopyTasks.length > 0) {
              const tasks = allCopyTasks.splice(0, 100);
              await Promise.all(tasks.map(copyTask => copyFile(copyTask.src, copyTask.dest)));
          }
      }
      catch (e) {
          catchError(results.diagnostics, e);
      }
      return results;
  }
  async function processGlobs(copyTask, srcDir) {
      return isGlob(copyTask.src)
          ? await processGlobTask(copyTask, srcDir)
          : [
              {
                  src: getSrcAbsPath(srcDir, copyTask.src),
                  dest: copyTask.keepDirStructure ? path$1__default.join(copyTask.dest, copyTask.src) : copyTask.dest,
                  warn: copyTask.warn,
                  keepDirStructure: copyTask.keepDirStructure,
              },
          ];
  }
  function getSrcAbsPath(srcDir, src) {
      if (path$1__default.isAbsolute(src)) {
          return src;
      }
      return path$1__default.join(srcDir, src);
  }
  async function processGlobTask(copyTask, srcDir) {
      const files = await asyncGlob(copyTask.src, {
          cwd: srcDir,
          nodir: true,
      });
      return files.map(globRelPath => createGlobCopyTask(copyTask, srcDir, globRelPath));
  }
  function createGlobCopyTask(copyTask, srcDir, globRelPath) {
      const dest = path$1__default.join(copyTask.dest, copyTask.keepDirStructure ? globRelPath : path$1__default.basename(globRelPath));
      return {
          src: path$1__default.join(srcDir, globRelPath),
          dest,
          warn: copyTask.warn,
          keepDirStructure: copyTask.keepDirStructure,
      };
  }
  async function processCopyTask(results, allCopyTasks, copyTask) {
      try {
          copyTask.src = normalizePath(copyTask.src);
          copyTask.dest = normalizePath(copyTask.dest);
          // get the stats for this src to see if it's a directory or not
          const stats = await stat(copyTask.src);
          if (stats.isDirectory()) {
              // still a directory, keep diggin down
              if (!results.dirPaths.includes(copyTask.dest)) {
                  results.dirPaths.push(copyTask.dest);
              }
              await processCopyTaskDirectory(results, allCopyTasks, copyTask);
          }
          else if (!shouldIgnore(copyTask.src)) {
              // this is a file we should copy
              if (!results.filePaths.includes(copyTask.dest)) {
                  results.filePaths.push(copyTask.dest);
              }
              allCopyTasks.push(copyTask);
          }
      }
      catch (e) {
          if (copyTask.warn !== false) {
              const err = buildError(results.diagnostics);
              err.messageText = e.message;
          }
      }
  }
  async function processCopyTaskDirectory(results, allCopyTasks, copyTask) {
      try {
          const dirItems = await readdir(copyTask.src);
          await Promise.all(dirItems.map(async (dirItem) => {
              const subCopyTask = {
                  src: path$1__default.join(copyTask.src, dirItem),
                  dest: path$1__default.join(copyTask.dest, dirItem),
                  warn: copyTask.warn,
              };
              await processCopyTask(results, allCopyTasks, subCopyTask);
          }));
      }
      catch (e) {
          catchError(results.diagnostics, e);
      }
  }
  function ensureDirs(copyTasks) {
      const mkDirs = [];
      copyTasks.forEach(copyTask => {
          addMkDir(mkDirs, path$1__default.dirname(copyTask.dest));
      });
      mkDirs.sort((a, b) => {
          const partsA = a.split('/').length;
          const partsB = b.split('/').length;
          if (partsA < partsB)
              return -1;
          if (partsA > partsB)
              return 1;
          if (a < b)
              return -1;
          if (a > b)
              return 1;
          return 0;
      });
      return mkDirs;
  }
  function addMkDir(mkDirs, destDir) {
      destDir = normalizePath(destDir);
      if (destDir === ROOT_DIR || destDir + '/' === ROOT_DIR || destDir === '') {
          return;
      }
      if (!mkDirs.includes(destDir)) {
          mkDirs.push(destDir);
      }
  }
  const ROOT_DIR = normalizePath(path$1__default.resolve('/'));
  function shouldIgnore(filePath) {
      filePath = filePath.trim().toLowerCase();
      return IGNORE.some(ignoreFile => filePath.endsWith(ignoreFile));
  }
  const IGNORE = ['.ds_store', '.gitignore', 'desktop.ini', 'thumbs.db'];
  function asyncGlob(pattern, opts) {
      return new Promise((resolve, reject) => {
          glob_1(pattern, opts, (err, files) => {
              if (err) {
                  reject(err);
              }
              else {
                  resolve(files);
              }
          });
      });
  }
  
  var fn = new Intl.Collator(0, { numeric:1 }).compare;
  
  function semiver (a, b, bool) {
  	a = a.split('.');
  	b = b.split('.');
  
  	return fn(a[0], b[0]) || fn(a[1], b[1]) || (
  		b[2] = b.slice(2).join('.'),
  		bool = /[.-]/.test(a[2] = a.slice(2).join('.')),
  		bool == /[.-]/.test(b[2]) ? fn(a[2], b[2]) : bool ? -1 : 1
  	);
  }
  
  class NodeLazyRequire {
      constructor(nodeResolveModule, lazyDependencies) {
          this.nodeResolveModule = nodeResolveModule;
          this.lazyDependencies = lazyDependencies;
          this.moduleData = new Map();
      }
      async ensure(logger, fromDir, ensureModuleIds) {
          const depsToInstall = [];
          let isUpdate = false;
          const promises = ensureModuleIds.map(async (ensureModuleId) => {
              const existingModuleData = this.moduleData.get(ensureModuleId);
              if (existingModuleData && existingModuleData.fromDir && existingModuleData.modulePath) {
                  return;
              }
              const [minVersion, maxVersion] = this.lazyDependencies[ensureModuleId];
              try {
                  const resolvedPkgJsonPath = this.nodeResolveModule.resolveModule(fromDir, ensureModuleId);
                  const installedPkgJson = await readPackageJson(resolvedPkgJsonPath);
                  isUpdate = true;
                  if (semiver(installedPkgJson.version, minVersion) >= 0) {
                      this.moduleData.set(ensureModuleId, {
                          fromDir: fromDir,
                          modulePath: path$1.dirname(resolvedPkgJsonPath),
                      });
                      return;
                  }
              }
              catch (e) { }
              depsToInstall.push({
                  moduleId: ensureModuleId,
                  requiredVersionRange: maxVersion,
              });
          });
          await Promise.all(promises);
          if (depsToInstall.length === 0) {
              return Promise.resolve();
          }
          const msg = `Please wait while required dependencies are ${isUpdate ? `updated` : `installed`}. This may take a few moments and will only be required for the initial run.`;
          logger.info(logger.magenta(msg));
          const moduleIds = depsToInstall.map(dep => dep.moduleId);
          const timeSpan = logger.createTimeSpan(`installing dependenc${moduleIds.length > 1 ? 'ies' : 'y'}: ${moduleIds.join(', ')}`);
          try {
              const installModules = depsToInstall.map(dep => {
                  let moduleId = dep.moduleId;
                  if (dep.requiredVersionRange) {
                      moduleId += '@' + dep.requiredVersionRange;
                  }
                  return moduleId;
              });
              await npmInstall(logger, fromDir, installModules);
              depsToInstall.forEach(installedDep => {
                  this.moduleData.set(installedDep.moduleId, {
                      fromDir: fromDir,
                      modulePath: null,
                  });
              });
              timeSpan.finish(`installing dependencies finished`);
          }
          catch (e) {
              logger.error(`lazy require failed: ${e}`);
          }
      }
      require(moduleId) {
          const moduleData = this.moduleData.get(moduleId);
          if (!moduleData) {
              throw new Error(`lazy required module has not been ensured: ${moduleId}`);
          }
          if (!moduleData.modulePath) {
              const modulePkgJsonPath = this.nodeResolveModule.resolveModule(moduleData.fromDir, moduleId);
              moduleData.modulePath = path$1.dirname(modulePkgJsonPath);
              this.moduleData.set(moduleId, moduleData);
          }
          return require(moduleData.modulePath);
      }
      getModulePath(moduleId) {
          const moduleData = this.moduleData.get(moduleId);
          if (!moduleData) {
              throw new Error(`lazy required module has not been ensured: ${moduleId}`);
          }
          if (!moduleData.modulePath) {
              const modulePkgJsonPath = this.nodeResolveModule.resolveModule(moduleData.fromDir, moduleId);
              moduleData.modulePath = path$1.dirname(modulePkgJsonPath);
              this.moduleData.set(moduleId, moduleData);
          }
          return moduleData.modulePath;
      }
  }
  function npmInstall(logger, fromDir, moduleIds) {
      return new Promise((resolve, reject) => {
          const cmd = 'npm';
          const args = ['install', ...moduleIds, '--no-audit', '--save-exact', '--save-dev'];
          const opts = {
              shell: true,
              cwd: fromDir,
              env: Object.assign({}, process.env),
          };
          opts.env.NODE_ENV = 'development';
          if (logger.level === 'debug') {
              args.push('--verbose');
          }
          logger.debug(`${cmd} ${args.join(' ')}`);
          logger.debug(`${cmd}, cwd: ${fromDir}`);
          const childProcess = child_process.spawn(cmd, args, opts);
          let output = '';
          if (childProcess.stdout) {
              childProcess.stdout.setEncoding('utf8');
              childProcess.stdout.on('data', data => {
                  output += data;
              });
          }
          if (childProcess.stderr) {
              childProcess.stderr.setEncoding('utf8');
              childProcess.stderr.on('data', data => {
                  output += data;
              });
          }
          childProcess.once('exit', exitCode => {
              if (logger.level === 'debug') {
                  logger.debug(`${cmd}, exit ${exitCode}`);
              }
              if (exitCode === 0) {
                  resolve();
              }
              else {
                  reject(`failed to install: ${moduleIds.join(', ')}${output ? ', ' + output : ''}`);
              }
          });
      });
  }
  function readPackageJson(pkgJsonPath) {
      return new Promise((resolve, reject) => {
          fs.readFile(pkgJsonPath, 'utf8', (err, data) => {
              if (err) {
                  reject(err);
              }
              else {
                  try {
                      resolve(JSON.parse(data));
                  }
                  catch (e) {
                      reject(e);
                  }
              }
          });
      });
  }
  
  class NodeResolveModule {
      constructor() {
          this.resolveModuleCache = new Map();
      }
      resolveModule(fromDir, moduleId, opts) {
          const cacheKey = `${fromDir}:${moduleId}`;
          const cachedPath = this.resolveModuleCache.get(cacheKey);
          if (cachedPath) {
              return cachedPath;
          }
          if (opts && opts.manuallyResolve) {
              return this.resolveModuleManually(fromDir, moduleId, cacheKey);
          }
          if (moduleId.startsWith('@types/')) {
              return this.resolveTypesModule(fromDir, moduleId, cacheKey);
          }
          const Module = require('module');
          fromDir = path$1__default.resolve(fromDir);
          const fromFile = path$1__default.join(fromDir, 'noop.js');
          let dir = normalizePath(Module._resolveFilename(moduleId, {
              id: fromFile,
              filename: fromFile,
              paths: Module._nodeModulePaths(fromDir),
          }));
          const root = normalizePath(path$1__default.parse(fromDir).root);
          let packageJsonFilePath;
          while (dir !== root) {
              dir = normalizePath(path$1__default.dirname(dir));
              packageJsonFilePath = path$1__default.join(dir, 'package.json');
              if (!fs__default.existsSync(packageJsonFilePath)) {
                  continue;
              }
              this.resolveModuleCache.set(cacheKey, packageJsonFilePath);
              return packageJsonFilePath;
          }
          throw new Error(`error loading "${moduleId}" from "${fromDir}"`);
      }
      resolveTypesModule(fromDir, moduleId, cacheKey) {
          const moduleSplt = moduleId.split('/');
          const root = normalizePath(path$1__default.parse(fromDir).root);
          let dir = normalizePath(path$1__default.join(fromDir, 'noop.js'));
          let typesPackageJsonFilePath;
          while (dir !== root) {
              dir = normalizePath(path$1__default.dirname(dir));
              typesPackageJsonFilePath = path$1__default.join(dir, 'node_modules', moduleSplt[0], moduleSplt[1], 'package.json');
              if (!fs__default.existsSync(typesPackageJsonFilePath)) {
                  continue;
              }
              this.resolveModuleCache.set(cacheKey, typesPackageJsonFilePath);
              return typesPackageJsonFilePath;
          }
          throw new Error(`error loading "${moduleId}" from "${fromDir}"`);
      }
      resolveModuleManually(fromDir, moduleId, cacheKey) {
          const root = normalizePath(path$1__default.parse(fromDir).root);
          let dir = normalizePath(path$1__default.join(fromDir, 'noop.js'));
          let packageJsonFilePath;
          while (dir !== root) {
              dir = normalizePath(path$1__default.dirname(dir));
              packageJsonFilePath = path$1__default.join(dir, 'node_modules', moduleId, 'package.json');
              if (!fs__default.existsSync(packageJsonFilePath)) {
                  continue;
              }
              this.resolveModuleCache.set(cacheKey, packageJsonFilePath);
              return packageJsonFilePath;
          }
          throw new Error(`error loading "${moduleId}" from "${fromDir}"`);
      }
  }
  
  function createNodeSys(prcs) {
      const destroys = new Set();
      const sys = {
          access(p) {
              return new Promise(resolve => {
                  fs__default.access(p, err => {
                      const hasAccess = !err;
                      resolve(hasAccess);
                  });
              });
          },
          accessSync(p) {
              let hasAccess = false;
              try {
                  fs__default.accessSync(p);
                  hasAccess = true;
              }
              catch (e) { }
              return hasAccess;
          },
          addDestory(cb) {
              destroys.add(cb);
          },
          removeDestory(cb) {
              destroys.delete(cb);
          },
          copyFile(src, dst) {
              return new Promise(resolve => {
                  fs__default.copyFile(src, dst, err => {
                      resolve(!err);
                  });
              });
          },
          async destroy() {
              const waits = [];
              destroys.forEach(cb => {
                  try {
                      const rtn = cb();
                      if (rtn && rtn.then) {
                          waits.push(rtn);
                      }
                  }
                  catch (e) {
                      console.error(`node sys destroy: ${e}`);
                  }
              });
              await Promise.all(waits);
              destroys.clear();
          },
          encodeToBase64(str) {
              return Buffer.from(str).toString('base64');
          },
          getCurrentDirectory() {
              return normalizePath(prcs.cwd());
          },
          glob: asyncGlob,
          isSymbolicLink: (p) => new Promise(resolve => {
              try {
                  fs__default.lstat(p, (err, stats) => {
                      if (err) {
                          resolve(false);
                      }
                      else {
                          resolve(stats.isSymbolicLink());
                      }
                  });
              }
              catch (e) {
                  resolve(false);
              }
          }),
          getCompilerExecutingPath: null,
          normalizePath,
          mkdir(p, opts) {
              return new Promise(resolve => {
                  if (opts) {
                      fs__default.mkdir(p, opts, err => {
                          resolve({
                              basename: path$1__default.basename(p),
                              dirname: path$1__default.dirname(p),
                              path: p,
                              newDirs: [],
                              error: err,
                          });
                      });
                  }
                  else {
                      fs__default.mkdir(p, err => {
                          resolve({
                              basename: path$1__default.basename(p),
                              dirname: path$1__default.dirname(p),
                              path: p,
                              newDirs: [],
                              error: err,
                          });
                      });
                  }
              });
          },
          mkdirSync(p, opts) {
              const results = {
                  basename: path$1__default.basename(p),
                  dirname: path$1__default.dirname(p),
                  path: p,
                  newDirs: [],
                  error: null,
              };
              try {
                  fs__default.mkdirSync(p, opts);
              }
              catch (e) {
                  results.error = e;
              }
              return results;
          },
          readdir(p) {
              return new Promise(resolve => {
                  fs__default.readdir(p, (err, files) => {
                      if (err) {
                          resolve([]);
                      }
                      else {
                          resolve(files.map(f => {
                              return normalizePath(path$1__default.join(p, f));
                          }));
                      }
                  });
              });
          },
          readdirSync(p) {
              try {
                  return fs__default.readdirSync(p).map(f => {
                      return normalizePath(path$1__default.join(p, f));
                  });
              }
              catch (e) { }
              return [];
          },
          readFile(p) {
              return new Promise(resolve => {
                  fs__default.readFile(p, 'utf8', (_, data) => {
                      resolve(data);
                  });
              });
          },
          readFileSync(p) {
              try {
                  return fs__default.readFileSync(p, 'utf8');
              }
              catch (e) { }
              return undefined;
          },
          realpath(p) {
              return new Promise(resolve => {
                  fs__default.realpath(p, 'utf8', (_, data) => {
                      resolve(data);
                  });
              });
          },
          realpathSync(p) {
              try {
                  return fs__default.realpathSync(p, 'utf8');
              }
              catch (e) { }
              return undefined;
          },
          rename(oldPath, newPath) {
              return new Promise(resolve => {
                  fs__default.rename(oldPath, newPath, error => {
                      resolve({ oldPath, newPath, error, oldDirs: [], oldFiles: [], newDirs: [], newFiles: [], renamed: [], isFile: false, isDirectory: false });
                  });
              });
          },
          resolvePath(p) {
              return normalizePath(p);
          },
          rmdir(p, opts) {
              return new Promise(resolve => {
                  const recursive = !!(opts && opts.recursive);
                  if (recursive) {
                      fs__default.rmdir(p, { recursive: true }, err => {
                          resolve({ basename: path$1__default.basename(p), dirname: path$1__default.dirname(p), path: p, removedDirs: [], removedFiles: [], error: err });
                      });
                  }
                  else {
                      fs__default.rmdir(p, err => {
                          resolve({ basename: path$1__default.basename(p), dirname: path$1__default.dirname(p), path: p, removedDirs: [], removedFiles: [], error: err });
                      });
                  }
              });
          },
          rmdirSync(p, opts) {
              try {
                  const recursive = !!(opts && opts.recursive);
                  if (recursive) {
                      fs__default.rmdirSync(p, { recursive: true });
                  }
                  else {
                      fs__default.rmdirSync(p);
                  }
                  return { basename: path$1__default.basename(p), dirname: path$1__default.dirname(p), path: p, removedDirs: [], removedFiles: [], error: null };
              }
              catch (e) {
                  return { basename: path$1__default.basename(p), dirname: path$1__default.dirname(p), path: p, removedDirs: [], removedFiles: [], error: e };
              }
          },
          stat(p) {
              return new Promise(resolve => {
                  fs__default.stat(p, (err, s) => {
                      if (err) {
                          resolve(undefined);
                      }
                      else {
                          resolve(s);
                      }
                  });
              });
          },
          statSync(p) {
              try {
                  return fs__default.statSync(p);
              }
              catch (e) { }
              return undefined;
          },
          unlink(p) {
              return new Promise(resolve => {
                  fs__default.unlink(p, err => {
                      resolve({
                          basename: path$1__default.basename(p),
                          dirname: path$1__default.dirname(p),
                          path: p,
                          error: err,
                      });
                  });
              });
          },
          unlinkSync(p) {
              const results = {
                  basename: path$1__default.basename(p),
                  dirname: path$1__default.dirname(p),
                  path: p,
                  error: null,
              };
              try {
                  fs__default.unlinkSync(p);
              }
              catch (e) {
                  results.error = e;
              }
              return results;
          },
          writeFile(p, content) {
              return new Promise(resolve => {
                  fs__default.writeFile(p, content, err => {
                      resolve({ path: p, error: err });
                  });
              });
          },
          writeFileSync(p, content) {
              const results = {
                  path: p,
                  error: null,
              };
              try {
                  fs__default.writeFileSync(p, content);
              }
              catch (e) {
                  results.error = e;
              }
              return results;
          },
          generateContentHash(content, length) {
              let hash = crypto.createHash('sha1').update(content).digest('hex').toLowerCase();
              if (typeof length === 'number') {
                  hash = hash.substr(0, length);
              }
              return Promise.resolve(hash);
          },
          copy: nodeCopyTasks,
          details: getDetails(),
      };
      const nodeResolve = new NodeResolveModule();
      sys.lazyRequire = new NodeLazyRequire(nodeResolve, {
          '@types/jest': ['24.9.1', '25.2.3'],
          '@types/puppeteer': ['1.19.0', '2.0.1'],
          'jest': ['24.9.0', '26.0.1'],
          'jest-cli': ['24.9.0', '26.0.1'],
          'pixelmatch': ['4.0.2', '4.0.2'],
          'puppeteer': ['1.19.0', '2.1.1'],
          'puppeteer-core': ['1.19.0', '2.1.1'],
          'workbox-build': ['4.3.1', '4.3.1'],
      });
      return sys;
  }
  const getDetails = () => {
      const details = {
          cpuModel: '',
          cpus: -1,
          freemem() {
              return os.freemem();
          },
          platform: '',
          release: '',
          runtime: 'node',
          runtimeVersion: '',
          tmpDir: os.tmpdir(),
          totalmem: -1,
      };
      try {
          const sysCpus = os.cpus();
          details.cpuModel = sysCpus[0].model;
          details.cpus = sysCpus.length;
          details.platform = os.platform();
          details.release = os.release();
          details.runtimeVersion = process.version;
          details.totalmem = os.totalmem();
      }
      catch (e) { }
      return details;
  };
  
  function createWebSocket(prcs, httpServer, destroys) {
      const wsConfig = {
          server: httpServer,
      };
      const wsServer = new ws.Server(wsConfig);
      function heartbeat() {
          this.isAlive = true;
      }
      wsServer.on('connection', (ws) => {
          ws.on('message', data => {
              // the server process has received a message from the browser
              // pass the message received from the browser to the main cli process
              prcs.send(JSON.parse(data.toString()));
          });
          ws.isAlive = true;
          ws.on('pong', heartbeat);
      });
      const pingInternval = setInterval(() => {
          wsServer.clients.forEach((ws) => {
              if (!ws.isAlive) {
                  return ws.close(1000);
              }
              ws.isAlive = false;
              ws.ping(noop);
          });
      }, 10000);
      function onMessageFromCli(msg) {
          // the server process has received a message from the cli's main thread
          // pass the data to each web socket for each browser/tab connected
          if (msg) {
              const data = JSON.stringify(msg);
              wsServer.clients.forEach(ws => {
                  if (ws.readyState === ws.OPEN) {
                      ws.send(data);
                  }
              });
          }
      }
      prcs.addListener('message', onMessageFromCli);
      destroys.push(() => {
          clearInterval(pingInternval);
          wsServer.clients.forEach(ws => {
              ws.close(1000);
          });
      });
  }
  
  /*
   * exit
   * https://github.com/cowboy/node-exit
   *
   * Copyright (c) 2013 "Cowboy" Ben Alman
   * Licensed under the MIT license.
   */
  
  var exit = function exit(exitCode, streams) {
    if (!streams) { streams = [process.stdout, process.stderr]; }
    var drainCount = 0;
    // Actually exit if all streams are drained.
    function tryToExit() {
      if (drainCount === streams.length) {
        process.exit(exitCode);
      }
    }
    streams.forEach(function(stream) {
      // Count drained streams now, but monitor non-drained streams.
      if (stream.bufferSize === 0) {
        drainCount++;
      } else {
        stream.write('', 'utf-8', function() {
          drainCount++;
          tryToExit();
        });
      }
      // Prevent further writing.
      stream.write = function() {};
    });
    // If all streams were already drained, exit now.
    tryToExit();
    // In Windows, when run as a Node.js child process, a script utilizing
    // this library might just exit with a 0 exit code, regardless. This code,
    // despite the fact that it looks a bit crazy, appears to fix that.
    process.on('exit', function() {
      process.exit(exitCode);
    });
  };
  
  async function startDevServerWorker(prcs, devServerConfig) {
      let hasStarted = false;
      try {
          const sys = createNodeSys(prcs);
          const destroys = [];
          devServerConfig.editors = await getEditors();
          // create the http server listening for and responding to requests from the browser
          let httpServer = await createHttpServer(devServerConfig, sys, destroys);
          if (devServerConfig.websocket) {
              // upgrade web socket requests the server receives
              createWebSocket(prcs, httpServer, destroys);
          }
          // start listening!
          httpServer.listen(devServerConfig.port, devServerConfig.address);
          // have the server worker send a message to the main cli
          // process that the server has successfully started up
          sendMsg(prcs, {
              serverStarted: {
                  address: devServerConfig.address,
                  basePath: devServerConfig.basePath,
                  browserUrl: getBrowserUrl(devServerConfig.protocol, devServerConfig.address, devServerConfig.port, devServerConfig.basePath, '/'),
                  port: devServerConfig.port,
                  protocol: devServerConfig.protocol,
                  root: devServerConfig.root,
                  initialLoadUrl: getBrowserUrl(devServerConfig.protocol, devServerConfig.address, devServerConfig.port, devServerConfig.basePath, devServerConfig.initialLoadUrl || DEV_SERVER_INIT_URL),
                  error: null,
              },
          });
          hasStarted = true;
          const closeServer = () => {
              // probably recived a SIGINT message from the parent cli process
              // let's do our best to gracefully close everything down first
              destroys.forEach(destroy => {
                  destroy();
              });
              destroys.length = 0;
              httpServer = null;
              setTimeout(() => {
                  exit(0);
              }, 5000).unref();
              prcs.removeAllListeners('message');
          };
          prcs.once('SIGINT', closeServer);
      }
      catch (e) {
          if (!hasStarted) {
              sendMsg(prcs, {
                  serverStarted: {
                      address: null,
                      basePath: null,
                      browserUrl: null,
                      initialLoadUrl: null,
                      port: null,
                      protocol: null,
                      root: null,
                      error: String(e),
                  },
              });
          }
          else {
              sendError(prcs, e);
          }
      }
  }
  
  async function startServer(devServerConfig) {
      // received a message from main to start the server
      try {
          devServerConfig.contentTypes = await loadContentTypes(devServerConfig);
          startDevServerWorker(process, devServerConfig);
      }
      catch (e) {
          sendMsg(process, {
              serverStarted: {
                  address: null,
                  basePath: null,
                  browserUrl: null,
                  initialLoadUrl: null,
                  port: null,
                  protocol: null,
                  root: null,
                  error: String(e),
              },
          });
      }
  }
  async function loadContentTypes(devServerConfig) {
      const contentTypePath = path$1__default.join(devServerConfig.devServerDir, 'content-type-db.json');
      const readFile = util__default.promisify(fs__default.readFile);
      const contentTypeJson = await readFile(contentTypePath, 'utf8');
      return JSON.parse(contentTypeJson);
  }
  createMessageReceiver(process, (msg) => {
      if (msg.startServer) {
          startServer(msg.startServer);
      }
  });
  process.on('unhandledRejection', (e) => {
      console.log('server worker error', e);
  });
  