text: "use strict";
  
  let isWindows = /^win/.test(process.platform),
      forwardSlashPattern = /\//g,
      protocolPattern = /^(\w{2,}):\/\//i,
      url = module.exports;
  
  // RegExp patterns to URL-encode special characters in local filesystem paths
  let urlEncodePatterns = [
    /\?/g, "%3F",
    /\#/g, "%23",
  ];
  
  // RegExp patterns to URL-decode special characters for local filesystem paths
  let urlDecodePatterns = [
    /\%23/g, "#",
    /\%24/g, "$",
    /\%26/g, "&",
    /\%2C/g, ",",
    /\%40/g, "@"
  ];
  
  exports.parse = require("url").parse;
  exports.resolve = require("url").resolve;
  
  /**
   * Returns the current working directory (in Node) or the current page URL (in browsers).
   *
   * @returns {string}
   */
  exports.cwd = function cwd () {
    if (process.browser) {
      return location.href;
    }
  
    let path = process.cwd();
  
    let lastChar = path.slice(-1);
    if (lastChar === "/" || lastChar === "\\") {
      return path;
    }
    else {
      return path + "/";
    }
  };
  
  /**
   * Returns the protocol of the given URL, or `undefined` if it has no protocol.
   *
   * @param   {string} path
   * @returns {?string}
   */
  exports.getProtocol = function getProtocol (path) {
    let match = protocolPattern.exec(path);
    if (match) {
      return match[1].toLowerCase();
    }
  };
  
  /**
   * Returns the lowercased file extension of the given URL,
   * or an empty string if it has no extension.
   *
   * @param   {string} path
   * @returns {string}
   */
  exports.getExtension = function getExtension (path) {
    let lastDot = path.lastIndexOf(".");
    if (lastDot >= 0) {
      return path.substr(lastDot).toLowerCase();
    }
    return "";
  };
  
  /**
   * Returns the hash (URL fragment), of the given path.
   * If there is no hash, then the root hash ("#") is returned.
   *
   * @param   {string} path
   * @returns {string}
   */
  exports.getHash = function getHash (path) {
    let hashIndex = path.indexOf("#");
    if (hashIndex >= 0) {
      return path.substr(hashIndex);
    }
    return "#";
  };
  
  /**
   * Removes the hash (URL fragment), if any, from the given path.
   *
   * @param   {string} path
   * @returns {string}
   */
  exports.stripHash = function stripHash (path) {
    let hashIndex = path.indexOf("#");
    if (hashIndex >= 0) {
      path = path.substr(0, hashIndex);
    }
    return path;
  };
  
  /**
   * Determines whether the given path is an HTTP(S) URL.
   *
   * @param   {string} path
   * @returns {boolean}
   */
  exports.isHttp = function isHttp (path) {
    let protocol = url.getProtocol(path);
    if (protocol === "http" || protocol === "https") {
      return true;
    }
    else if (protocol === undefined) {
      // There is no protocol.  If we're running in a browser, then assume it's HTTP.
      return process.browser;
    }
    else {
      // It's some other protocol, such as "ftp://", "mongodb://", etc.
      return false;
    }
  };
  
  /**
   * Determines whether the given path is a filesystem path.
   * This includes "file://" URLs.
   *
   * @param   {string} path
   * @returns {boolean}
   */
  exports.isFileSystemPath = function isFileSystemPath (path) {
    if (process.browser) {
      // We're running in a browser, so assume that all paths are URLs.
      // This way, even relative paths will be treated as URLs rather than as filesystem paths
      return false;
    }
  
    let protocol = url.getProtocol(path);
    return protocol === undefined || protocol === "file";
  };
  
  /**
   * Converts a filesystem path to a properly-encoded URL.
   *
   * This is intended to handle situations where JSON Schema $Ref Parser is called
   * with a filesystem path that contains characters which are not allowed in URLs.
   *
   * @example
   * The following filesystem paths would be converted to the following URLs:
   *
   *    <"!@#$%^&*+=?'>.json              ==>   %3C%22!@%23$%25%5E&*+=%3F\'%3E.json
   *    C:\\My Documents\\File (1).json   ==>   C:/My%20Documents/File%20(1).json
   *    file://Project #42/file.json      ==>   file://Project%20%2342/file.json
   *
   * @param {string} path
   * @returns {string}
   */
  exports.fromFileSystemPath = function fromFileSystemPath (path) {
    // Step 1: On Windows, replace backslashes with forward slashes,
    // rather than encoding them as "%5C"
    if (isWindows) {
      path = path.replace(/\\/g, "/");
    }
  
    // Step 2: `encodeURI` will take care of MOST characters
    path = encodeURI(path);
  
    // Step 3: Manually encode characters that are not encoded by `encodeURI`.
    // This includes characters such as "#" and "?", which have special meaning in URLs,
    // but are just normal characters in a filesystem path.
    for (let i = 0; i < urlEncodePatterns.length; i += 2) {
      path = path.replace(urlEncodePatterns[i], urlEncodePatterns[i + 1]);
    }
  
    return path;
  };
  
  /**
   * Converts a URL to a local filesystem path.
   *
   * @param {string}  path
   * @param {boolean} [keepFileProtocol] - If true, then "file://" will NOT be stripped
   * @returns {string}
   */
  exports.toFileSystemPath = function toFileSystemPath (path, keepFileProtocol) {
    // Step 1: `decodeURI` will decode characters such as Cyrillic characters, spaces, etc.
    path = decodeURI(path);
  
    // Step 2: Manually decode characters that are not decoded by `decodeURI`.
    // This includes characters such as "#" and "?", which have special meaning in URLs,
    // but are just normal characters in a filesystem path.
    for (let i = 0; i < urlDecodePatterns.length; i += 2) {
      path = path.replace(urlDecodePatterns[i], urlDecodePatterns[i + 1]);
    }
  
    // Step 3: If it's a "file://" URL, then format it consistently
    // or convert it to a local filesystem path
    let isFileUrl = path.substr(0, 7).toLowerCase() === "file://";
    if (isFileUrl) {
      // Strip-off the protocol, and the initial "/", if there is one
      path = path[7] === "/" ? path.substr(8) : path.substr(7);
  
      // insert a colon (":") after the drive letter on Windows
      if (isWindows && path[1] === "/") {
        path = path[0] + ":" + path.substr(1);
      }
  
      if (keepFileProtocol) {
        // Return the consistently-formatted "file://" URL
        path = "file:///" + path;
      }
      else {
        // Convert the "file://" URL to a local filesystem path.
        // On Windows, it will start with something like "C:/".
        // On Posix, it will start with "/"
        isFileUrl = false;
        path = isWindows ? path : "/" + path;
      }
    }
  
    // Step 4: Normalize Windows paths (unless it's a "file://" URL)
    if (isWindows && !isFileUrl) {
      // Replace forward slashes with backslashes
      path = path.replace(forwardSlashPattern, "\\");
  
      // Capitalize the drive letter
      if (path.substr(1, 2) === ":\\") {
        path = path[0].toUpperCase() + path.substr(1);
      }
    }
  
    return path;
  };
  