To add route

@param string $method
@param string $uri
@param string $pattern
@param array  $options
546577
public function add($method = 'GET', $uri = '/', $pattern = '', array $options = [])
    {
        $this->method[] = $method;

        $this->uri[] = $uri;

        $this->pattern[] = $pattern;

        $this->filter[$uri][$method] = (isset($options['filter'])) ? $options['filter'] : '';
    }
271569
private function call(string $method, string $pattern, string $className, string $function, array $options = []): void
    {
        if (empty($className) || empty($function)) {
            throw new Exception('Missing params, we need 2 parameters');
        }

        $route = [
            'method' => $method,
            'pattern' => $pattern,
            'className' => $className,
            'function' => $function,
        ];
        $this->collections[] = $route;

        if (array_key_exists('options', $options)) {
            $this->setOptions($route, $options);
        }

        return;
    }
1126751
public function addRoute(array $methods, array $versions, $uri, $action)
    {
        $this->createRouteCollections($versions);

        foreach ($versions as $version) {
            foreach ($this->breakUriSegments($uri) as $uri) {
                $this->routes[$version]->addRoute($methods, $uri, $action);
            }
        }
    }
1138130
private function request($method, $uri, array $options = array())
    {
        $options['auth'] = array($this->accessKey, $this->secretKey);

        return $this->httpClient->request($method, $uri, $options);
    }
968171
public function add($method, $pattern, $callback, array $params = [])
    {
        $pattern = '/' . trim($pattern, '/');

        $pattern = rtrim($this->prefix . $pattern, '/');
        $pattern = $pattern ?: '/' . $pattern;

        if (!is_array($method)) {
            $method = [$method];
        }

        $before = $this->getParam($params, 'before');
        $after  = $this->getParam($params, 'after');
        $name   = $this->getParam($params, 'name');

        $before = $before ? explode('|', $params['before']) : [];
        $after  = $after ? explode('|', $params['after']) : [];

        $this->storeRoute($method, [
            'pattern'  => $pattern,
            'name'     => $name,
            'callback' => $callback,
            'before'   => array_merge($this->before, $before),
            'after'    => array_merge($this->after, $after),
            'args'     => [],
        ]);

        return $this;
    }
45689
public function mount($pattern, $mux, array $options = array())
    {
        // Save the mount path in options array
        $options['mount_path'] = $pattern;

        if ($mux instanceof Expandable) {

            $mux = $mux->expand($options);

        } else if ($mux instanceof Closure) {

            // we pass the newly created Mux object to the builder closure to initialize routes.
            if ($ret = $mux($mux = new Mux())) {
                if ($ret instanceof Mux) {
                    $mux = $ret;
                } else {
                    throw new LogicException('Invalid object returned from Closure.');
                }
            }
        } elseif ((!is_object($mux) || !($mux instanceof self)) && is_callable($mux)) {
            $mux($mux = new self());
        }

        // Save the constructed mux object in options array, so we can fetch
        // the expanded mux object in controller object later.
        $mux->setParent($this);
        $options['mux'] = $mux;


        if ($this->expand) {
            $pcre = strpos($pattern,':') !== false;

            // rewrite submux routes
            foreach ($mux->routes as $route) {
                // process for pcre
                if ($route[0] || $pcre) {
                    $newPattern = $pattern . ( $route[0] ? $route[3]['pattern'] : $route[1] );
                    $routeArgs = PatternCompiler::compile($newPattern, 
                        array_replace_recursive($options, $route[3]) );
                    $this->appendPCRERoute( $routeArgs, $route[2] );
                } else {
                    $this->routes[] = array(
                        false,
                        $pattern . $route[1],
                        $route[2],
                        isset($route[3]) ? array_replace_recursive($options, $route[3]) : $options,
                    );
                }
            }
        } else {

            $muxId = $mux->getId();
            $this->add($pattern, $muxId, $options);
            $this->submux[ $muxId ] = $mux;

        }
    }
880595
public function addMap($pattern, $controller = null)
    {
        if (!is_string($controller)) {
            throw new \InvalidArgumentException(
                'Please give me controller name string. ' . ucfirst(gettype($controller)) . ' given.'
            );
        }

        if ($pattern instanceof Route) {
            throw new \LogicException('Do not use Route object in ' . get_called_class());
        }

        return parent::addRoute(null, $pattern, ['_controller' => $controller]);
    }
136593
public function add($pattern, $paths = null, $method = null)
    {
        return $this->_addRoute($pattern, $paths, $method);
    }
590609
protected function addRoute($method, $pattern, $callback, array $middleware = null, $name = null)
    {
        $concatenatedPattern = (!is_null($this->prefix) ? '/' . $this->prefix : '') .
            $pattern;

        $this->collector->addRoute(strtoupper($method), $concatenatedPattern, new Route($callback, $middleware));

        if ($name !== null) {
            $this->namedRoutes[$name] = $concatenatedPattern;
        }
    }
952703
public function addUriWildcards($uri, $reflection, $method): string
    {
        $refAction = $reflection->getReflectionClass()->getMethod($method);

        $parameter = '';
        $patterns = $this->router->getPattern();
        $arguments = new \CachingIterator(new \ArrayIterator($refAction->getParameters()));

        foreach ($arguments as $key => $param) {
            if (!$param->isOptional()) {
                if (array_key_exists('{:' . $param->getName() . '}', $patterns)) {
                    $slash = ($arguments->hasNext()) ? '/' : '';
                    $parameter .= '{:' . $param->getName() . '}' . $slash;
                }
            }
        }

        return $uri . '/' . $parameter;
    }
1141498
public function route(
        string $method,
        string $pattern,
        callable $callback,
        int $priority = 0
    ): RouterInterface {
        //hard requirement
        if (!is_callable($callback)) {
            throw HttpException::forInvalidRouteCallback();
        }

        if (strtoupper($method) === 'ALL') {
            $method = '[a-zA-Z0-9]+';
        }

        //find and organize all the dynamic parameters
        preg_match_all('#(\:[a-zA-Z0-9\-_]+)|(\*\*)|(\*)#s', $pattern, $matches);

        $keys = array();
        if (isset($matches[0]) && is_array($matches[0])) {
            $keys = $matches[0];
        }

        //replace the :variable-_name01
        $regex = preg_replace('#(\:[a-zA-Z0-9\-_]+)#s', '*', $pattern);

        //replace the stars
        //* -> ([^/]+)
        $regex = str_replace('*', '([^/]+)', $regex);
        //** -> ([^/]+)([^/]+) -> (.*)
        $regex = str_replace('([^/]+)([^/]+)', '(.*)', $regex);

        //now form the event pattern
        $event = '#^' . $method . '\s' . $regex . '/*$#is';

        //we need the handler for later
        $handler = $this->getEventHandler();

        $handler->on(
            $event,
            function (
                RequestInterface $request,
                ...$args
            ) use (
                $handler,
                $callback,
                $pattern,
                $keys
            ) {
                $route = $handler->getMeta();
                $variables = array();
                $parameters = array();

                //sanitize the variables
                foreach ($route['variables'] as $i => $variable) {
                    //if it's a * variable
                    if (!isset($keys[$i]) || strpos($keys[$i], '*') === 0) {
                        //it's a variable
                        if (strpos($variable, '/') === false) {
                            $variables[] = $variable;
                            continue;
                        }

                        $variables = array_merge($variables, explode('/', $variable));
                        continue;
                    }

                    //if it's a :parameter
                    if (isset($keys[$i])) {
                        $key = substr($keys[$i], 1);
                        $parameters[$key] = $variable;
                    }
                }

                $request
                    ->setStage($parameters)
                    ->setRoute(array(
                        'event' => $route['event'],
                        'variables' => $variables,
                        'parameters' => $parameters
                    ));

                return call_user_func($callback, $request, ...$args);
            },
            $priority
        );

        return $this;
    }
391017
public function add($uri, $method = Route::METHOD_ALL, $name = null, $prefix = false)
    {
        if ($prefix) {
            $uri = $this->prefix . $uri . $this->postfix;
        }

        $route = $this->parser->parse($uri, $method);
        if ($name === null || is_int($name)) {
            $name = count($this->routes);
        } elseif (!is_string($name)) {
            throw new \InvalidArgumentException('$name must be a string, integer or null.');
        }
        $this->routes[$name] = $route;
        if ($route->isStatic()) {
            if (!isset($this->staticRoutes[$uri])) {
                $this->staticRoutes[$uri] = [
                    $method => $route
                ];
            } else {
                $this->staticRoutes[$uri][$method] = $route;
            }
        }
        $route->set($this->globalValues);

        return $route;
    }
945968
function Route (pattern, base, fn, options) {
    this.pattern = RoutePattern.fromString(pattern);
    this.options = options || {};
    this.fn = fn;

    if (base) {
        this.extendFrom(base);
    }
}
277892
public function requestAsync($method, $uri = null, array $options = [])
    {
        $options = $this->setRequestOptions($options);

        $query = parse_url($uri, PHP_URL_QUERY);
        if (!empty($query)) {
            $uri = substr($uri, 0, (strlen($query)+1) * -1);
            parse_str($query, $options['query']);
        }

        return parent::requestAsync($method, $uri, $options);
    }
1271332
protected function httpRequest($method, $uri, array $options = [])
    {
        if (null !== $this->proxy) {
            $options[RequestOptions::PROXY] = $this->proxy;
        }

        if (!isset($options[RequestOptions::HEADERS])) {
            $options[RequestOptions::HEADERS] = $this->getHttpHeaders();
        } else {
            $options[RequestOptions::HEADERS] = array_merge($this->getHttpHeaders(), $options[RequestOptions::HEADERS]);
        }

        if (!isset($options[RequestOptions::HTTP_ERRORS])) {
            $options[RequestOptions::HTTP_ERRORS] = false;
        }

        if (!isset($options[RequestOptions::ALLOW_REDIRECTS])) {
            $options[RequestOptions::ALLOW_REDIRECTS] = false;
        }

        if (!isset($options[RequestOptions::TIMEOUT]) && null !== $this->timeout) {
            $options[RequestOptions::TIMEOUT] = $this->timeout;
        }

        if (null !== $this->qps && null !== $this->lastRequestTime) {
            $lastInterval = floor((microtime(true) - $this->lastRequestTime) * 1000000);
            $timeout = ceil(1000000 / $this->qps);
            if ($lastInterval < $timeout) {
                usleep($timeout - $lastInterval);
            }
        }

        $response = $this->getHttpClient()->request($method, $uri, $options);
        $this->lastRequestTime = microtime(true);
        $this->history[] = [
            'method' => $method,
            'uri' => $uri,
            'time' => $this->lastRequestTime,
            'status' => $response->getStatusCode(),
        ];

        return $response;
    }
1218079
public function match($rawRoute, $method = 'GET', $options = [])
    {
        $this->triggerEvent('onRouterBeforeRouteMatch', [
            'route' => &$rawRoute,
            'method' => &$method,
            'options' => &$options,
            'router' => $this,
        ]);

        $route = parent::match($rawRoute, $method, $options);

        $this->triggerEvent('onRouterAfterRouteMatch', [
            'route' => &$rawRoute,
            'matched' => $route,
            'method' => &$method,
            'options' => &$options,
            'router' => $this,
        ]);

        $extra = $route->getExtraValues();

        $controller = Arr::get($extra, 'controller');

        // Suffix
        $suffix = $this->fetchControllerSuffix($method, Arr::get($extra, 'action', []));

        if (!$controller && !$suffix) {
            throw new \LogicException(
                'Route profile should have "controller" or "action" element, the matched route: ' . $route->getName()
            );
        }

        if (!class_exists($controller) && !class_exists($suffix)) {
            $controller = trim($controller, '\\') . '\\' . $suffix;
        } elseif (class_exists($suffix)) {
            $controller = $suffix;
        }

        if ($controller) {
            $extra['controller'] = $this->controller = $controller;
        }

        $route->setExtraValues($extra);

        // Hooks
        if (isset($extra['hook']['match'])) {
            if (!is_callable($extra['hook']['match'])) {
                throw new \LogicException(sprintf(
                    'The match hook: "%s" of route: "%s" not found',
                    implode('::', (array) $extra['hook']['match']),
                    $route->getName()
                ));
            }

            call_user_func($extra['hook']['match'], $this, $route, $method, $options);
        }

        $this->matched = $route;

        return $route;
    }
1325989
protected function makeRequest($method, $uri, $options)
    {
        $logger = $this->getLogger();

        try {
            $logger->info(sprintf('Making API %s request to %s', $method, $uri), [$options]);

            /** @var ResponseInterface $response */
            $response = $this->_doRequest($method, $uri, $options);

            $logger->debug('Response from HTTP call was status code:', [$response->getStatusCode()]);
            $logger->debug('Response JSON was:', [$response->getBody()]);

            return $response;
        } catch (\Exception $e) {
            throw $e; // Just rethrow for now
        }
    }