/*!
\private

Performs rawurlencode() on the path part of the URL. The rest is not touched.

\return partially encoded url
195133
function urlEncodePath( $url )
    {
        // Raw encode the path part of the URL
        $urlComponents = parse_url( $url );
        $pathParts = explode( '/', $urlComponents['path'] );
        foreach ( $pathParts as $key => $pathPart )
        {
            $pathParts[$key] = rawurlencode( $pathPart );
        }
        $encodedPath = implode( '/', $pathParts );

        // Rebuild the URL again, like this: scheme://user:pass@host/path?query#fragment
        $encodedUrl = $urlComponents['scheme'] . '://';

        if ( isset( $urlComponents['user'] ) )
        {
            $encodedUrl .= $urlComponents['user'];
            if ( isset( $urlComponents['pass'] ) )
            {
                $encodedUrl .= ':' . $urlComponents['pass'];
            }
            $encodedUrl .= '@';
        }

        $encodedUrl .= $urlComponents['host'];
        if ( isset( $urlComponents['port'] ) )
        {
            $encodedUrl .= ':' . $urlComponents['port'];
        }
        $encodedUrl .= $encodedPath;

        if ( isset( $urlComponents['query'] ) )
        {
            $encodedUrl .= '?' . $urlComponents['query'];
        }

        if ( isset( $urlComponents['fragment'] ) )
        {
            $encodedUrl .= '#' . $urlComponents['fragment'];
        }

        return $encodedUrl;
    }
212905
function build_url( $parts = null )
	{
		if (is_string($parts))
		{
			if ($parts === '' || $parts === '//')
				return $this->uri->withScheme(null);								//	'//' . $this->uri->authority . $this->uri->getPathAndQuery();
			if ($parts[0] === '/')
				return $this->uri->getLeftPart(Uri::PARTIAL_AUTHORITY) . $parts;	//	(_::is_https() ? 'https://' : 'http://') . _::request('host') . $parts;
			if ($parts === 'https' || $parts === 'http')
				return $this->uri->withScheme($parts);								//	$parts . '://' . _::request('host') . _::request('uri');
			if ($parts[0] === '?')
				return $this->uri->getLeftPart(Uri::PARTIAL_PATH) . $parts;			//	(_::is_https() ? 'https://' : 'http://') . _::request('host') . _::request('path') . $parts;
			if (strpos($parts, '=') !== false)
				return $this->uri->getLeftPart(Uri::PARTIAL_PATH) . '?' . $parts;	//	(_::is_https() ? 'https://' : 'http://') . _::request('host') . _::request('path') . '?' . $parts;
			if ($parts[0] === '#')
				return $this->uri->withFragment($parts);							//	(_::is_https() ? 'https://' : 'http://') . _::request('host') . _::request('uri') . $parts;
			throw new \Exception("Invalid call to Request::build_url('{$parts}')");
		}
		return (string) (new Uri($parts));
/*
		return	(isset($parts['scheme']) ? (empty($parts['scheme']) ? '//' : $parts['scheme'] . '://') : ($this->uri->scheme ?? 'http') : 'http://')) .	// Can set `scheme` to NULL to generate a Protocol-Relative-URL!
				'//' . (empty($parts['host']) ? $this->uri->authority : $parts['host']) .
				(empty($parts['path']) ? _::request('path') : $parts['path']) .
				(isset($parts['query']) ? (empty($parts['query']) ? null : '?' . $parts['query']) : (empty($parts['path']) && _::request('query') ? '?' . _::request('query') : null)); // NO FRAGMENT! We can append it if we really need it!
*/
	}
508312
static public function sanitizePath(string $path,
                                        string $pathEncoding = null): string {
        if ($pathEncoding === null) {
            self::detectPathEncoding();
            $pathEncoding = self::$pathEncoding;
        }
        $path = iconv($pathEncoding, 'utf-8', $path);
        $path = str_replace('\\', '/', $path);
        return $path;
    }
371100
private static function encodeUrl($url)
    {
        $url_parsed = parse_url($url);
        $scheme = $url_parsed['scheme'] . '://';
        $host   = $url_parsed['host'];
        $port   = (isset($url_parsed['port']) ? $url_parsed['port'] : null);
        $path   = (isset($url_parsed['path']) ? $url_parsed['path'] : null);
        $query  = (isset($url_parsed['query']) ? $url_parsed['query'] : null);
        if ($query != null) {
            $query = '?' . http_build_query(self::getArrayFromQuerystring($url_parsed['query']));
        }
        if ($port && $port[0] != ":") {
            $port = ":" . $port;
        }
        $result = $scheme . $host . $port . $path . $query;
        return $result;
    }
1311399
private static String decodeUrl(String url) {
        if (url == null) {
            return null;
        }

        try {
            return URLDecoder.decode(url, CHARSET_UTF8);
        } catch (UnsupportedEncodingException e) {
            return url;
        }
    }
48939
public function Path($Path = NULL) {
      if (is_string($Path)) {
         $Result = $this->_ParsedRequestElement('Path', $Path);
      } else {
         $Result = $this->_ParsedRequestElement('Path');
         if ($Path === TRUE) {
            // Encode the path.
            $Parts = explode('/', $Result);
            $Parts = array_map('urlencode', $Parts);
            $Result = implode('/', $Parts);
         }
      }
      
      return $Result;
   }
983792
function encodeLink(path, value, attrs) {
    var allowedAttrs = [ 'pmin', 'pmax', 'gt', 'lt', 'st' ],
        pathType = cutils.getPathDateType(path),
        pathArray = cutils.getPathArray(path),
        oid = pathArray[0],
        attrsPayload = '',
        linkFormat = '';

    _.forEach(attrs, function (val, key) {
        if (_.includes(allowedAttrs, key) && _.isNumber(val))
            attrsPayload = attrsPayload + ';' + key + '=' + val;   // ';pmin=0;pmax=60'
    });

    path = cutils.getNumPath(path);
    linkFormat = '<' + path + '>' + attrsPayload + ',';

    switch (pathType) {
        case 'object':         // obj
            _.forEach(value, function (iobj, iid) {
                _.forEach(iobj, function (val, rid) {
                    linkFormat = linkFormat + '<' + path + '/' + iid + '/' + cutils.ridNumber(oid, rid) + '>' + ',';
                });
            });
            break;

        case 'instance':         // inst
            _.forEach(value, function (val, rid) {
                linkFormat = linkFormat + '<' + path + '/' + cutils.ridNumber(oid, rid) + '>' + ',';
            });
            break;

        case 'resource':         // resrc
            break;

        default:
            break;
    }

    if (linkFormat[linkFormat.length-1] === ',')
        linkFormat = linkFormat.slice(0, linkFormat.length - 1);

    return linkFormat;
}
702172
private function _filterPath($path)
    {
        $path = preg_replace_callback(
            '/(?:[^' . self::UNRESERVED_CHARACTERS . self::SUB_DELIMS_CHARACTERS . '%:@\/]+|%(?![A-Fa-f0-9]{2}))/',
            [$this, '_rawUrlEncode'],
            $path
        );

        if ($path && $path[0] === '/') {
            $path = '/' . ltrim($path, '/');
        }

        return $path;
    }
88222
function toString()
    {
        $uri = '';

        if ($this->getScheme())
            $uri .= $this->getScheme() . ':'. '//';

        $uri .= $this->getAuthority();
        $uri .= parent::toString();

        if ($this->getHost() && (!$this->getQuery()->isEmpty() || $this->getFragment()))
            $uri .= '/';

        $replace = function ($match) { return rawurlencode($match[0]); };
        if (\Poirot\Std\cast($this->getQuery())->toArray()) {
            $regex   = '/(?:[^' .'a-zA-Z0-9_\-\.~' .'!\$&\'\(\)\*\+,;=' .'%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/';
            $uri .= "?" . preg_replace_callback($regex, $replace, $this->getQuery()->toString());
        }

        if ($this->getFragment()) {
            $regex   = '/(?:[^' .'a-zA-Z0-9_\-\.~' .'!\$&\'\(\)\*\+,;=' .'%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/';
            $uri .= "#" . preg_replace_callback($regex, $replace, $this->getFragment());
        }

        return $uri;
    }
1245910
public function determineRequestUriFromPath($path)
    {
        if ($path instanceof Url) {
            $uri = $path;
        } elseif (stripos($path, 'http://') === 0 || stripos($path, 'https://') === 0) {
            $uri = new Url($path);
        } else {
            $path = (string) $path;
            $uri = $this->getBaseApiUri();

            if (false !== strpos($path, '?')) {
                $parts = explode('?', $path, 2);
                $path = $parts[ 0 ];
                $query = $parts[ 1 ];
                $uri->setQuery($query);
            }

            // Add path
            $uri->getPath()->append("$path");

            // Clean up double slashes
            $uri->setPath(array_filter($uri->getPath()->toArray()));
        }

        return $uri;
    }
624098
public function getNormalizedUrl() {
		$parts = parse_url( $this->url );

		$scheme = isset( $parts['scheme'] ) ? $parts['scheme'] : 'http';
		$port = isset( $parts['port'] ) ?
			$parts['port'] : ( $scheme === 'https' ? '443' : '80' );
		$host = isset( $parts['host'] ) ? strtolower( $parts['host'] ) : '';
		$path = isset( $parts['path'] ) ? $parts['path'] : '';

		if ( ( $scheme === 'https' && $port != '443' ) ||
			( $scheme === 'http' && $port != '80' )
		) {
			$host = "{$host}:{$port}";
		}
		return "{$scheme}://{$host}{$path}";
	}
300017
public function getURL(): ?string
    {
        if ($this->base !== null) {
            $list = [];
            $queryList = $this->query->getList();
            foreach ($queryList as $queryItem) {
                $list[$queryItem->name] = $queryItem->value;
            }
            return $this->base . implode('/', array_map('urlencode', explode('/', (string) $this->path))) . (empty($list) ? '' : '?' . http_build_query($list));
        }
        return null;
    }
9844
protected function devideUrl()
    {
        $parts = explode('/', $this->getPath());
        $cnt   = count($parts);
        for ($i = 0; $i < $cnt; $i++) {
            $parts[$i] = trim($parts[$i]);
        }
        return $parts;
    }
1310481
public static function getUrlEncodedPath($path): string
    {
        $entities = array('+', '%21', '%2A', '%27', '%28', '%29', '%3B', '%3A', '%40', '%26', '%3D', '%2B', '%24', '%2C', '%2F', '%3F', '%25', '%23', '%5B', '%5D');
        $replacements = array(' ', '!', '*', "'", '(', ')', ';', ':', '@', '&', '=', '+', '$', ',', '/', '?', '%', '#', '[', ']');
        $path = str_replace($entities, $replacements, urlencode($path));
        
        return $path;
    }
1290156
protected function filterPath($path)
    {
        $pathStr    = $this->filterString($path);
        $pathDecode = rawurldecode($pathStr);

        $dataPath = array_map(
            function ($value) {
                return rawurlencode($value);
            },
            explode('/', $pathDecode)
        );

        return implode('/', $dataPath);
    }
693122
public function getUrl($path)
    {
        $uri = rtrim($this->storageApiUri, '/');
        $path = $this->applyPathPrefix($path);

        // Only prepend bucket name if no custom storage uri specified
        // Default: "https://storage.googleapis.com/{my_bucket}/{path_prefix}"
        // Custom: "https://example.com/{path_prefix}"
        if ($this->getStorageApiUri() === self::STORAGE_API_URI_DEFAULT) {
            $path = $this->bucket->name() . '/' . $path;
        }

        return $uri . '/' . $path;
    }
869738
function urlEncode(data) {
  log("==================================================");
  log("Data before urlEncode");
  log("==================================================");
  log(data);

  if (data === "") {
    return data;
  }

  let find = ["~", "%20", "'"];
  let replace = ["%7E", "+", "%27"];
  let encodedData = encodeURIComponent(data);

  find.forEach((encodedChar, index) => {
    let regex = new RegExp(encodedChar, "g");
    encodedData = encodedData.replace(regex, replace[index]);
  });

  log("==================================================");
  log("Data after urlEncode");
  log("==================================================");
  log(encodedData);

  return encodedData;
}