protected function _writeUrl($params, $pass = [], $query = [])
    {
        $pass = implode('/', array_map('rawurlencode', $pass));
        $out = $this->template;

        $search = $replace = [];
        foreach ($this->keys as $key) {
            $string = null;
            if (isset($params[$key])) {
                $string = $params[$key];
            } elseif (strpos($out, $key) != strlen($out) - strlen($key)) {
                $key .= '/';
            }
            if ($this->braceKeys) {
                $search[] = "{{$key}}";
            } else {
                $search[] = ':' . $key;
            }
            $replace[] = $string;
        }

        if (strpos($this->template, '**') !== false) {
            array_push($search, '**', '%2F');
            array_push($replace, $pass, '/');
        } elseif (strpos($this->template, '*') !== false) {
            $search[] = '*';
            $replace[] = $pass;
        }
        $out = str_replace($search, $replace, $out);

        // add base url if applicable.
        if (isset($params['_base'])) {
            $out = $params['_base'] . $out;
            unset($params['_base']);
        }

        $out = str_replace('//', '/', $out);
        if (isset($params['_scheme']) ||
            isset($params['_host']) ||
            isset($params['_port'])
        ) {
            $host = $params['_host'];

            // append the port & scheme if they exists.
            if (isset($params['_port'])) {
                $host .= ':' . $params['_port'];
            }
            $scheme = isset($params['_scheme']) ? $params['_scheme'] : 'http';
            $out = "{$scheme}://{$host}{$out}";
        }
        if (!empty($params['_ext']) || !empty($query)) {
            $out = rtrim($out, '/');
        }
        if (!empty($params['_ext'])) {
            $out .= '.' . $params['_ext'];
        }
        if (!empty($query)) {
            $out .= rtrim('?' . http_build_query($query), '?');
        }

        return $out;
    }