private function build($resource, $params, $optParams)
    {
        $url = '';
        if (isset($optParams['option'])) {
            $option = (string) $optParams['option'];
            if (!empty($option)) {
                $url .= '/o-'.$option;
            }
        }
        if (isset($optParams['transformation'])) {
            $transformation = (string) $optParams['transformation'];
            if (!empty($transformation)) {
                $url .= '/' . trim($transformation, '/');
            }
        }
        if (isset($optParams['version'])) {
            $url .= '/v/'.$optParams['version'];
        }
        $url .= $resource;
        if (isset($optParams['format'])) {
            $url .= '.'.$optParams['format'];
        }
        if (isset($optParams['seo'])) {
            $url .= '/seo/'.$optParams['seo'];
        }
        $security = '';
        if (isset($optParams['security'])) {
            switch ($optParams['security']) {
                case 'basic':
                    if (!$this->client->apiKey || !$this->client->imageSecret) {
                        throw new InvalidConfigException('The apiKey and imageSecret must be specified!');
                    }
                    $security = '/s-b3:'.SecurityHelper::generateImageSecretSignature($this->client->imageHostname, ltrim($url, '/'), $this->client->apiKey, $this->client->imageSecret);
                    break;
                case 'token':
                    if (!$this->client->apiAccessTokenSecret){
                        throw new InvalidConfigException('The apiAccessTokenSecret must be specified!');
                    }
                    $security = '/s-token:'.$this->client->apiAccessToken.','.SecurityHelper::generateTokenHash($this->client->imageHostname, ltrim($url, '/'), $this->client->apiAccessToken, $this->client->apiAccessTokenSecret);
                    break;
            }
        }

        return $this->client->imageHost.'/'.$params['cloudId'].$security.$url;
    }