protected static string Merge(UniformResourceIdentifier2 baseUri, string relativePathReference)
        {
            if (baseUri.Authority != null && baseUri.path == string.Empty)
            {
                return("/" + relativePathReference);
            }

            int rightMostSlash = baseUri.path.LastIndexOf('/');

            if (rightMostSlash == -1)
            {
                return(relativePathReference);
            }

            return(baseUri.path.Substring(0, rightMostSlash + 1) + relativePathReference);
        }
        public UniformResourceIdentifier2(string uriReference, UniformResourceIdentifier2 baseUri)
        {
            Match match =
                new Regex(
                    @"(?<relativeRef>^(?<relativePart>(?://(?<authority>(?:(?<userInfo>(?:(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|:)*)@)?(?<host>(?<ipLiteral>\[(?:(?<ipV6Address>(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){6}(?<ls32>(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):(?<h16>(?<hexDig>[a-fA-F\d]){1,4}))|(?<ipV4Address>(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])))|::(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){5}(?<ls32>(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):(?<h16>(?<hexDig>[a-fA-F\d]){1,4}))|(?<ipV4Address>(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])))|(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}))?::(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){4}(?<ls32>(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):(?<h16>(?<hexDig>[a-fA-F\d]){1,4})|(?<ipV4Address>(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35]))))?|(?:(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){0,1}(?<h16>(?<hexDig>[a-fA-F\d]){1,4}))?::(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){3}(?<ls32>(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):(?<h16>(?<hexDig>[a-fA-F\d]){1,4})|(?<ipV4Address>(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35]))))?|(?:(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){0,2}(?<h16>(?<hexDig>[a-fA-F\d]){1,4}))?::(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){2}(?<ls32>(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):(?<h16>(?<hexDig>[a-fA-F\d]){1,4})|(?<ipV4Address>(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35]))))?|(?:(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){0,3}(?<h16>(?<hexDig>[a-fA-F\d]){1,4}))?::(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):(?<ls32>(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):(?<h16>(?<hexDig>[a-fA-F\d]){1,4})|(?<ipV4Address>(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35]))))?|(?:(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){0,4}(?<h16>(?<hexDig>[a-fA-F\d]){1,4}))?::(?<ls32>(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):(?<h16>(?<hexDig>[a-fA-F\d]){1,4})|(?<ipV4Address>(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35]))))?|(?:(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){0,5}(?<h16>(?<hexDig>[a-fA-F\d]){1,4}))?::(?<h16>(?<hexDig>[a-fA-F\d]){1,4})|(?:(?:(?<h16>(?<hexDig>[a-fA-F\d]){1,4}):){0,2}(?<h16>(?<hexDig>[a-fA-F\d]){1,6}))?::)|(?<ipVFuture>v(?<hexDig>[a-fA-F\d])+\.(?:(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|:)+))])|(?<ipV4Address>(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35])\.(?<decOctet>\d|[\x31-\x39]\d|1\d{2}|2[\x30-\x34]|25[\x30-\x35]))|(?<regName>(?:(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=]))*))(?::(?<port>\d*))?)(?<path>(?<pathAbEmpty>(?:/(?<segment>(?<pchar>(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|:|@)*))*)))|(?<path>(?<pathAbsolute>/(?:(?<segmentNz>(?<pchar>(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|:|@)+)+(?:/(?<segment>(?<pchar>(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|:|@)*))*)?)|(?<pathNoScheme>(?:(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|@)+(?:/(?<segment>(?<pchar>(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|:|@)*))*)|(?<pathEmpty>(?<pchar>(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|:|@){0})))(?:\?(?<query>(?:(?<pchar>(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|:|@)|/|\?)*))?(?:#(?<fragment>(?:(?<pchar>(?<unreserved>[-a-zA-Z\d._~])|(?<pctEncoded>%[a-fA-F0-9]{2})|(?<subDelims>[!$&'()*+,;=])|:|@)|/|\?)*))?$)")
                .Match(uriReference);

            if (match.Success)
            {
                if (match.Groups["authority"].Success)
                {
                    authority       = GetGroupValueByName(match, "authority");
                    userInformation = GetGroupValueByName(match, "userInfo");
                    host            = GetGroupValueByName(match, "host");
                    hostType        = GetHostTypeByRegExMatch(match);
                    port            = GetGroupValueByName(match, "port");
                    path            = RemoveDotSegments(GetPathByRegExMatch(match));
                    query           = GetGroupValueByName(match, "query");
                }
                else
                {
                    if (match.Groups["pathEmpty"].Success)
                    {
                        path = baseUri.path;
                        if (match.Groups["query"].Success)
                        {
                            query = GetGroupValueByName(match, "query");
                        }
                        else
                        {
                            query = baseUri.query;
                        }
                    }
                    else
                    {
                        string pathByRegExMatch = GetPathByRegExMatch(match);
                        if (pathByRegExMatch.StartsWith("/"))
                        {
                            path = RemoveDotSegments(pathByRegExMatch);
                        }
                        else
                        {
                            path = RemoveDotSegments(Merge(baseUri, pathByRegExMatch));
                        }
                        query = GetGroupValueByName(match, "query");
                    }
                    authority       = baseUri.authority;
                    userInformation = baseUri.userInformation;
                    host            = baseUri.host;
                    hostType        = baseUri.hostType;
                    port            = baseUri.port;
                }
                scheme = baseUri.scheme;

                StringBuilder builder = new StringBuilder();

                if (authority != null)
                {
                    builder.Append("//");
                    builder.Append(authority);
                }
                builder.Append(path);
                hierarchicalPart = builder.ToString();

                builder.Insert(0, scheme + ':');
                if (query != null)
                {
                    builder.Append('?');
                    builder.Append(query);
                }
                absoluteUri = builder.ToString();

                fragment = GetGroupValueByName(match, "fragment");
            }
            else
            {
                Parse(uriReference);
            }
        }
 public bool Equals(UniformResourceIdentifier2 uri)
 {
     return(Normalize().ToString() == uri.Normalize().ToString());
 }