public static function resolve($base, string $reference, bool $strict = true): Uri
    {
        if (!($base instanceof self)) {
            $base = static::parse($base);
        }

        preg_match(static::URI_PATTERN, $reference, $matches);
        $ref = static::componentsFromMatches($matches);

        // http://tools.ietf.org/html/rfc3986#section-5.2.2
        // A non-strict parser may ignore a scheme in the reference if it is
        // identical to the base URI's scheme
        if (!$strict && ($ref['scheme'] !== null && $base->scheme() === $ref['scheme'])) {
            $ref['scheme'] = null;
        }

        if ($ref['scheme'] !== null) {
            $scheme = $ref['scheme'];
            $authority = $ref['authority'];
            $path = static::removeDotSegments($ref['path']);
            $query = $ref['query'];
        } else {
            // http://tools.ietf.org/html/rfc3986#section-3.3
            // In addition, a URI reference (Section 4.1) may be a
            // relative-path reference, in which case the first path segment
            // cannot contain a colon (":") character.
            // START: extra check for colon in first segment
            $segments = explode('/', trim($ref['path'], '/'));
            if (isset($segments[0]) && strpos($segments[0], ':') !== false) {
                $message = sprintf('First segment in reference (%s) cannot contain a colon (":")', $reference);
                throw new DomainException($message);
            }
            // END: extra check for colon in first segment
            if ($ref['authority'] !== null) {
                $authority = $ref['authority'];
                $path = static::removeDotSegments($ref['path']);
                $query = $ref['query'];
            } else {
                if ($ref['path'] === '') {
                    $path = $base->path();
                    if ($ref['query'] !== null) {
                        $query = $ref['query'];
                    } else {
                        $query = $base->query();
                    }
                } else {
                    if ($ref['path'][0] === '/') {
                        $path = static::removeDotSegments($ref['path']);
                    } else {
                        $path = static::mergePaths($base, $ref['path']);
                        $path = static::removeDotSegments($path);
                    }
                    $query = $ref['query'];
                }
                $authority = $base->authority();
            }
            $scheme = $base->scheme();
        }
        $fragment = $ref['fragment'];

        return new static($path, $scheme, $authority, $query, $fragment);
    }