whole_func_string: function(baseURL, relativeURL, opts) {
        opts = opts || {};
        // remove any remaining space and CRLF
        baseURL = baseURL.trim();
        relativeURL = relativeURL.trim();
        if (!relativeURL) {
          // 2a) If the embedded URL is entirely empty, it inherits the
          // entire base URL (i.e., is set equal to the base URL)
          // and we are done.
          if (!opts.alwaysNormalize) {
            return baseURL;
          }
          var basePartsForNormalise = URLToolkit.parseURL(baseURL);
          if (!basePartsForNormalise) {
            throw new Error('Error trying to parse base URL.');
          }
          basePartsForNormalise.path = URLToolkit.normalizePath(basePartsForNormalise.path);
          return URLToolkit.buildURLFromParts(basePartsForNormalise);
        }
        var relativeParts = URLToolkit.parseURL(relativeURL);
        if (!relativeParts) {
          throw new Error('Error trying to parse relative URL.');
        }
        if (relativeParts.scheme) {
          // 2b) If the embedded URL starts with a scheme name, it is
          // interpreted as an absolute URL and we are done.
          if (!opts.alwaysNormalize) {
            return relativeURL;
          }
          relativeParts.path = URLToolkit.normalizePath(relativeParts.path);
          return URLToolkit.buildURLFromParts(relativeParts);
        }
        var baseParts = URLToolkit.parseURL(baseURL);
        if (!baseParts) {
          throw new Error('Error trying to parse base URL.');
        }
        if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== '/') {
          // If netLoc missing and path doesn't start with '/', assume everthing before the first '/' is the netLoc
          // This causes 'example.com/a' to be handled as '//example.com/a' instead of '/example.com/a'
          var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path);
          baseParts.netLoc = pathParts[1];
          baseParts.path = pathParts[2];
        }
        if (baseParts.netLoc && !baseParts.path) {
          baseParts.path = '/';
        }
        var builtParts = {
          // 2c) Otherwise, the embedded URL inherits the scheme of
          // the base URL.
          scheme: baseParts.scheme,
          netLoc: relativeParts.netLoc,
          path: null,
          params: relativeParts.params,
          query: relativeParts.query,
          fragment: relativeParts.fragment
        };
        if (!relativeParts.netLoc) {
          // 3) If the embedded URL's <net_loc> is non-empty, we skip to
          // Step 7.  Otherwise, the embedded URL inherits the <net_loc>
          // (if any) of the base URL.
          builtParts.netLoc = baseParts.netLoc;
          // 4) If the embedded URL path is preceded by a slash "/", the
          // path is not relative and we skip to Step 7.
          if (relativeParts.path[0] !== '/') {
            if (!relativeParts.path) {
              // 5) If the embedded URL path is empty (and not preceded by a
              // slash), then the embedded URL inherits the base URL path
              builtParts.path = baseParts.path;
              // 5a) if the embedded URL's <params> is non-empty, we skip to
              // step 7; otherwise, it inherits the <params> of the base
              // URL (if any) and
              if (!relativeParts.params) {
                builtParts.params = baseParts.params;
                // 5b) if the embedded URL's <query> is non-empty, we skip to
                // step 7; otherwise, it inherits the <query> of the base
                // URL (if any) and we skip to step 7.
                if (!relativeParts.query) {
                  builtParts.query = baseParts.query;
                }
              }
            } else {
              // 6) The last segment of the base URL's path (anything
              // following the rightmost slash "/", or the entire path if no
              // slash is present) is removed and the embedded URL's path is
              // appended in its place.
              var baseURLPath = baseParts.path;
              var newPath = baseURLPath.substring(0, baseURLPath.lastIndexOf('/') + 1) + relativeParts.path;
              builtParts.path = URLToolkit.normalizePath(newPath);
            }
          }
        }
        if (builtParts.path === null) {
          builtParts.path = opts.alwaysNormalize ? URLToolkit.normalizePath(relativeParts.path) : relativeParts.path;
        }
        return URLToolkit.buildURLFromParts(builtParts);
      }
func_code_string: function(baseURL, relativeURL, opts) {
        opts = opts || {};
        // remove any remaining space and CRLF
        baseURL = baseURL.trim();
        relativeURL = relativeURL.trim();
        if (!relativeURL) {
          // 2a) If the embedded URL is entirely empty, it inherits the
          // entire base URL (i.e., is set equal to the base URL)
          // and we are done.
          if (!opts.alwaysNormalize) {
            return baseURL;
          }
          var basePartsForNormalise = URLToolkit.parseURL(baseURL);
          if (!basePartsForNormalise) {
            throw new Error('Error trying to parse base URL.');
          }
          basePartsForNormalise.path = URLToolkit.normalizePath(basePartsForNormalise.path);
          return URLToolkit.buildURLFromParts(basePartsForNormalise);
        }
        var relativeParts = URLToolkit.parseURL(relativeURL);
        if (!relativeParts) {
          throw new Error('Error trying to parse relative URL.');
        }
        if (relativeParts.scheme) {
          // 2b) If the embedded URL starts with a scheme name, it is
          // interpreted as an absolute URL and we are done.
          if (!opts.alwaysNormalize) {
            return relativeURL;
          }
          relativeParts.path = URLToolkit.normalizePath(relativeParts.path);
          return URLToolkit.buildURLFromParts(relativeParts);
        }
        var baseParts = URLToolkit.parseURL(baseURL);
        if (!baseParts) {
          throw new Error('Error trying to parse base URL.');
        }
        if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== '/') {
          // If netLoc missing and path doesn't start with '/', assume everthing before the first '/' is the netLoc
          // This causes 'example.com/a' to be handled as '//example.com/a' instead of '/example.com/a'
          var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path);
          baseParts.netLoc = pathParts[1];
          baseParts.path = pathParts[2];
        }
        if (baseParts.netLoc && !baseParts.path) {
          baseParts.path = '/';
        }
        var builtParts = {
          // 2c) Otherwise, the embedded URL inherits the scheme of
          // the base URL.
          scheme: baseParts.scheme,
          netLoc: relativeParts.netLoc,
          path: null,
          params: relativeParts.params,
          query: relativeParts.query,
          fragment: relativeParts.fragment
        };
        if (!relativeParts.netLoc) {
          // 3) If the embedded URL's <net_loc> is non-empty, we skip to
          // Step 7.  Otherwise, the embedded URL inherits the <net_loc>
          // (if any) of the base URL.
          builtParts.netLoc = baseParts.netLoc;
          // 4) If the embedded URL path is preceded by a slash "/", the
          // path is not relative and we skip to Step 7.
          if (relativeParts.path[0] !== '/') {
            if (!relativeParts.path) {
              // 5) If the embedded URL path is empty (and not preceded by a
              // slash), then the embedded URL inherits the base URL path
              builtParts.path = baseParts.path;
              // 5a) if the embedded URL's <params> is non-empty, we skip to
              // step 7; otherwise, it inherits the <params> of the base
              // URL (if any) and
              if (!relativeParts.params) {
                builtParts.params = baseParts.params;
                // 5b) if the embedded URL's <query> is non-empty, we skip to
                // step 7; otherwise, it inherits the <query> of the base
                // URL (if any) and we skip to step 7.
                if (!relativeParts.query) {
                  builtParts.query = baseParts.query;
                }
              }
            } else {
              // 6) The last segment of the base URL's path (anything
              // following the rightmost slash "/", or the entire path if no
              // slash is present) is removed and the embedded URL's path is
              // appended in its place.
              var baseURLPath = baseParts.path;
              var newPath = baseURLPath.substring(0, baseURLPath.lastIndexOf('/') + 1) + relativeParts.path;
              builtParts.path = URLToolkit.normalizePath(newPath);
            }
          }
        }
        if (builtParts.path === null) {
          builtParts.path = opts.alwaysNormalize ? URLToolkit.normalizePath(relativeParts.path) : relativeParts.path;
        }
        return URLToolkit.buildURLFromParts(builtParts);
      }
func_documentation_string: jshint ignore:line If opts.alwaysNormalize is true then the path will always be normalized even when it starts with / or // E.g With opts.alwaysNormalize = false (default, spec compliant) http://a.com/b/cd + /e/f/../g => http://a.com/e/f/../g With opts.alwaysNormalize = true (not spec compliant) http://a.com/b/cd + /e/f/../g => http://a.com/e/g