public static function create(
        $selenium_server_url = 'http://localhost:4444/wd/hub',
        $desired_capabilities = null,
        $connection_timeout_in_ms = null,
        $request_timeout_in_ms = null,
        $http_proxy = null,
        $http_proxy_port = null,
        DesiredCapabilities $required_capabilities = null
    ) {
        $selenium_server_url = preg_replace('#/+$#', '', $selenium_server_url);

        $desired_capabilities = self::castToDesiredCapabilitiesObject($desired_capabilities);

        $executor = new HttpCommandExecutor($selenium_server_url, $http_proxy, $http_proxy_port);
        if ($connection_timeout_in_ms !== null) {
            $executor->setConnectionTimeout($connection_timeout_in_ms);
        }
        if ($request_timeout_in_ms !== null) {
            $executor->setRequestTimeout($request_timeout_in_ms);
        }

        if ($required_capabilities !== null) {
            // TODO: Selenium (as of v3.0.1) does accept requiredCapabilities only as a property of desiredCapabilities.
            // This will probably change in future with the W3C WebDriver spec, but is the only way how to pass these
            // values now.
            $desired_capabilities->setCapability('requiredCapabilities', $required_capabilities->toArray());
        }

        $command = new WebDriverCommand(
            null,
            DriverCommand::NEW_SESSION,
            ['desiredCapabilities' => $desired_capabilities->toArray()]
        );

        $response = $executor->execute($command);
        $returnedCapabilities = new DesiredCapabilities($response->getValue());

        $driver = new static($executor, $response->getSessionID(), $returnedCapabilities);

        return $driver;
    }