public function export($sSourceSlug, $sFormatSlug, $aOptions = [])
    {
        $oSource = $this->getSourceBySlug($sSourceSlug);
        if (empty($oSource)) {
            throw new NailsException('Invalid data source "' . $sSourceSlug . '"');
        }

        $oFormat = $this->getFormatBySlug($sFormatSlug);
        if (empty($oFormat)) {
            throw new NailsException('Invalid data format "' . $sFormatSlug . '"');
        }

        $oSourceResponse = $oSource->instance->execute($aOptions);
        if (!is_array($oSourceResponse)) {
            $aSourceResponses = [$oSourceResponse];
        } else {
            $aSourceResponses = $oSourceResponse;
        }

        //  Create temporary working directory
        $sTempDir = CACHE_PATH . 'data-export-' . md5(microtime(true)) . mt_rand() . '/';
        mkdir($sTempDir);

        //  Process each file
        $aFiles = [];
        try {

            foreach ($aSourceResponses as $oSourceResponse) {

                if (!($oSourceResponse instanceof SourceResponse)) {
                    throw new NailsException('Source must return an instance of SourceResponse');
                }

                //  Create a new file
                $sFile    = $sTempDir . $oSourceResponse->getFilename() . '.' . $oFormat->instance->getFileExtension();
                $aFiles[] = $sFile;
                $rFile    = fopen($sFile, 'w+');
                //  Write to the file
                $oSourceResponse->reset();
                $oFormat->instance->execute($oSourceResponse, $rFile);
                //  Close the file
                fclose($rFile);
            }

            //  Compress if > 1
            if (count($aFiles) > 1) {
                $sArchiveFile = $sTempDir . 'export.zip';
                $oZip         = Factory::service('Zip');
                foreach ($aFiles as $sFile) {
                    $oZip->read_file($sFile);
                }
                $oZip->archive($sArchiveFile);
                $aFiles[] = $sArchiveFile;
            }
            $sFile = end($aFiles);

            //  Save to CDN
            $oCdn    = Factory::service('Cdn', 'nails/module-cdn');
            $oObject = $oCdn->objectCreate($sFile, 'data-export');

            if (empty($oObject)) {
                throw new NailsException('Failed to upload exported file. ' . $oCdn->lastError());
            }
        } finally {
            //  Tidy up
            foreach ($aFiles as $sFile) {
                if (file_exists($sFile)) {
                    unlink($sFile);
                }
            }
            rmdir($sTempDir);
        }

        return $oObject->id;
    }