text:
// This is a GPU-backend specific test. It relies on static intializers to work

#include "SkTypes.h"

#if SK_SUPPORT_GPU && defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26 && defined(SK_VULKAN)

#include "GrBackendSemaphore.h"
#include "GrContext.h"
#include "GrContextFactory.h"
#include "GrContextPriv.h"
#include "GrGpu.h"
#include "GrProxyProvider.h"
#include "SkAutoMalloc.h"
#include "SkCanvas.h"
#include "SkGr.h"
#include "SkImage.h"
#include "SkSurface.h"
#include "Test.h"
#include "../tools/gpu/vk/VkTestUtils.h"
#include "gl/GrGLDefines.h"
#include "gl/GrGLUtil.h"
#include "vk/GrVkBackendContext.h"
#include "vk/GrVkExtensions.h"

#include <android/hardware_buffer.h>
#include <cinttypes>

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES/glext.h>

static const int DEV_W = 16, DEV_H = 16;

class BaseTestHelper {
public:
    virtual ~BaseTestHelper() {}

    virtual bool init(skiatest::Reporter* reporter) = 0;

    virtual void cleanup() = 0;
    virtual void releaseImage() = 0;

    virtual sk_sp<SkImage> importHardwareBufferForRead(skiatest::Reporter* reporter,
                                                       AHardwareBuffer* buffer) = 0;
    virtual sk_sp<SkSurface> importHardwareBufferForWrite(skiatest::Reporter* reporter,
                                                          AHardwareBuffer* buffer) = 0;

    virtual void doClientSync() = 0;
    virtual bool flushSurfaceAndSignalSemaphore(skiatest::Reporter* reporter, sk_sp<SkSurface>) = 0;
    virtual bool importAndWaitOnSemaphore(skiatest::Reporter* reporter, int fdHandle,
                                          sk_sp<SkSurface>) = 0;

    virtual void makeCurrent() = 0;

    virtual GrContext* grContext() = 0;

    int getFdHandle() { return fFdHandle; }

protected:
    BaseTestHelper() {}

    int fFdHandle = 0;
};

class EGLTestHelper : public BaseTestHelper {
public:
    EGLTestHelper(const GrContextOptions& options) : fFactory(options) {}

    ~EGLTestHelper() override {}

    void releaseImage() override {
        this->makeCurrent();
        if (!fGLCtx) {
            return;
        }
        if (EGL_NO_IMAGE_KHR != fImage) {
            fGLCtx->destroyEGLImage(fImage);
            fImage = EGL_NO_IMAGE_KHR;
        }
        if (fTexID) {
            GR_GL_CALL(fGLCtx->gl(), DeleteTextures(1, &fTexID));
            fTexID = 0;
        }
    }

    void cleanup() override {
        this->releaseImage();
    }

    bool init(skiatest::Reporter* reporter) override;

    sk_sp<SkImage> importHardwareBufferForRead(skiatest::Reporter* reporter,
                                               AHardwareBuffer* buffer) override;
    sk_sp<SkSurface> importHardwareBufferForWrite(skiatest::Reporter* reporter,
                                                  AHardwareBuffer* buffer) override;

    void doClientSync() override;
    bool flushSurfaceAndSignalSemaphore(skiatest::Reporter* reporter, sk_sp<SkSurface>) override;
    bool importAndWaitOnSemaphore(skiatest::Reporter* reporter, int fdHandle,
                                  sk_sp<SkSurface>) override;

    void makeCurrent() override { fGLCtx->makeCurrent(); }

    GrContext* grContext() override { return fGrContext; }

private:
    bool importHardwareBuffer(skiatest::Reporter* reporter, AHardwareBuffer* buffer);

    typedef EGLClientBuffer (*EGLGetNativeClientBufferANDROIDProc)(const struct AHardwareBuffer*);
    typedef EGLImageKHR (*EGLCreateImageKHRProc)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer,
                                                 const EGLint*);
    typedef void (*EGLImageTargetTexture2DOESProc)(EGLenum, void*);
    EGLGetNativeClientBufferANDROIDProc fEGLGetNativeClientBufferANDROID;
    EGLCreateImageKHRProc fEGLCreateImageKHR;
    EGLImageTargetTexture2DOESProc fEGLImageTargetTexture2DOES;

    PFNEGLCREATESYNCKHRPROC              fEGLCreateSyncKHR;
    PFNEGLWAITSYNCKHRPROC                fEGLWaitSyncKHR;
    PFNEGLGETSYNCATTRIBKHRPROC           fEGLGetSyncAttribKHR;
    PFNEGLDUPNATIVEFENCEFDANDROIDPROC    fEGLDupNativeFenceFDANDROID;
    PFNEGLDESTROYSYNCKHRPROC             fEGLDestroySyncKHR;

    EGLImageKHR fImage = EGL_NO_IMAGE_KHR;
    GrGLuint fTexID = 0;

    sk_gpu_test::GrContextFactory fFactory;
    sk_gpu_test::ContextInfo fGLESContextInfo;

    sk_gpu_test::GLTestContext* fGLCtx = nullptr;
    GrContext* fGrContext = nullptr;
};

bool EGLTestHelper::init(skiatest::Reporter* reporter) {
    fGLESContextInfo = fFactory.getContextInfo(sk_gpu_test::GrContextFactory::kGLES_ContextType);
    fGrContext = fGLESContextInfo.grContext();
    fGLCtx = fGLESContextInfo.glContext();
    if (!fGrContext || !fGLCtx) {
        return false;
    }

    if (kGLES_GrGLStandard != fGLCtx->gl()->fStandard) {
        return false;
    }

    // Confirm we have egl and the needed extensions
    if (!fGLCtx->gl()->hasExtension("EGL_KHR_image") ||
        !fGLCtx->gl()->hasExtension("EGL_ANDROID_get_native_client_buffer") ||
        !fGLCtx->gl()->hasExtension("GL_OES_EGL_image_external") ||
        !fGLCtx->gl()->hasExtension("GL_OES_EGL_image") ||
        !fGLCtx->gl()->hasExtension("EGL_KHR_fence_sync")) {
        return false;
    }

    fEGLGetNativeClientBufferANDROID =
        (EGLGetNativeClientBufferANDROIDProc) eglGetProcAddress("eglGetNativeClientBufferANDROID");
    if (!fEGLGetNativeClientBufferANDROID) {
        ERRORF(reporter, "Failed to get the eglGetNativeClientBufferAndroid proc");
        return false;
    }

    fEGLCreateImageKHR = (EGLCreateImageKHRProc) eglGetProcAddress("eglCreateImageKHR");
    if (!fEGLCreateImageKHR) {
        ERRORF(reporter, "Failed to get the proc eglCreateImageKHR");
        return false;
    }

    fEGLImageTargetTexture2DOES =
            (EGLImageTargetTexture2DOESProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
    if (!fEGLImageTargetTexture2DOES) {
        ERRORF(reporter, "Failed to get the proc EGLImageTargetTexture2DOES");
        return false;
    }

    fEGLCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
    if (!fEGLCreateSyncKHR) {
        ERRORF(reporter, "Failed to get the proc eglCreateSyncKHR");
        return false;

    }
    fEGLWaitSyncKHR = (PFNEGLWAITSYNCKHRPROC) eglGetProcAddress("eglWaitSyncKHR");
    if (!fEGLWaitSyncKHR) {
        ERRORF(reporter, "Failed to get the proc eglWaitSyncKHR");
        return false;

    }
    fEGLGetSyncAttribKHR = (PFNEGLGETSYNCATTRIBKHRPROC) eglGetProcAddress("eglGetSyncAttribKHR");
    if (!fEGLGetSyncAttribKHR) {
        ERRORF(reporter, "Failed to get the proc eglGetSyncAttribKHR");
        return false;

    }
    fEGLDupNativeFenceFDANDROID =
        (PFNEGLDUPNATIVEFENCEFDANDROIDPROC) eglGetProcAddress("eglDupNativeFenceFDANDROID");
    if (!fEGLDupNativeFenceFDANDROID) {
        ERRORF(reporter, "Failed to get the proc eglDupNativeFenceFDANDROID");
        return false;

    }
    fEGLDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
    if (!fEGLDestroySyncKHR) {
        ERRORF(reporter, "Failed to get the proc eglDestroySyncKHR");
        return false;

    }

    return true;
}

bool EGLTestHelper::importHardwareBuffer(skiatest::Reporter* reporter, AHardwareBuffer* buffer) {
    GrGLClearErr(fGLCtx->gl());

    EGLClientBuffer eglClientBuffer = fEGLGetNativeClientBufferANDROID(buffer);
    EGLint eglAttribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
                            EGL_NONE };
    EGLDisplay eglDisplay = eglGetCurrentDisplay();
    fImage = fEGLCreateImageKHR(eglDisplay, EGL_NO_CONTEXT,
                                EGL_NATIVE_BUFFER_ANDROID,
                                eglClientBuffer, eglAttribs);
    if (EGL_NO_IMAGE_KHR == fImage) {
        SkDebugf("Could not create EGL image, err = (%#x)\n", (int) eglGetError() );
        return false;
    }

    GR_GL_CALL(fGLCtx->gl(), GenTextures(1, &fTexID));
    if (!fTexID) {
        ERRORF(reporter, "Failed to create GL Texture");
        return false;
    }
    GR_GL_CALL_NOERRCHECK(fGLCtx->gl(), BindTexture(GR_GL_TEXTURE_2D, fTexID));
    if (GR_GL_GET_ERROR(fGLCtx->gl()) != GR_GL_NO_ERROR) {
        ERRORF(reporter, "Failed to bind GL Texture");
        return false;
    }

    fEGLImageTargetTexture2DOES(GL_TEXTURE_2D, fImage);
    GLenum status = GL_NO_ERROR;
    if ((status = glGetError()) != GL_NO_ERROR) {
        ERRORF(reporter, "EGLImageTargetTexture2DOES failed (%#x)", (int) status);
        return false;
    }

    fGrContext->resetContext(kTextureBinding_GrGLBackendState);
    return true;
}

sk_sp<SkImage> EGLTestHelper::importHardwareBufferForRead(skiatest::Reporter* reporter,
                                                          AHardwareBuffer* buffer) {
    if (!this->importHardwareBuffer(reporter, buffer)) {
        return nullptr;
    }
    GrGLTextureInfo textureInfo;
    textureInfo.fTarget = GR_GL_TEXTURE_2D;
    textureInfo.fID = fTexID;
    textureInfo.fFormat = GR_GL_RGBA8;

    GrBackendTexture backendTex(DEV_W, DEV_H, GrMipMapped::kNo, textureInfo);
    REPORTER_ASSERT(reporter, backendTex.isValid());

    sk_sp<SkImage> image = SkImage::MakeFromTexture(fGrContext,
                                                               backendTex,
                                                               kTopLeft_GrSurfaceOrigin,
                                                               kRGBA_8888_SkColorType,
                                                               kPremul_SkAlphaType,
                                                               nullptr);

    if (!image) {
        ERRORF(reporter, "Failed to make wrapped GL SkImage");
        return nullptr;
    }

    return image;
}

sk_sp<SkSurface> EGLTestHelper::importHardwareBufferForWrite(skiatest::Reporter* reporter,
                                                             AHardwareBuffer* buffer) {
    if (!this->importHardwareBuffer(reporter, buffer)) {
        return nullptr;
    }
    GrGLTextureInfo textureInfo;
    textureInfo.fTarget = GR_GL_TEXTURE_2D;
    textureInfo.fID = fTexID;
    textureInfo.fFormat = GR_GL_RGBA8;

    GrBackendTexture backendTex(DEV_W, DEV_H, GrMipMapped::kNo, textureInfo);
    REPORTER_ASSERT(reporter, backendTex.isValid());

    sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(fGrContext,
                                                                 backendTex,
                                                                 kTopLeft_GrSurfaceOrigin,
                                                                 0,
                                                                 kRGBA_8888_SkColorType,
                                                                 nullptr, nullptr);

    if (!surface) {
        ERRORF(reporter, "Failed to make wrapped GL SkSurface");
        return nullptr;
    }

    return surface;
}

bool EGLTestHelper::flushSurfaceAndSignalSemaphore(skiatest::Reporter* reporter,
                                                      sk_sp<SkSurface> surface) {
    EGLDisplay eglDisplay = eglGetCurrentDisplay();
    EGLSyncKHR eglsync = fEGLCreateSyncKHR(eglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
    if (EGL_NO_SYNC_KHR == eglsync) {
        ERRORF(reporter, "Failed to create EGLSync for EGL_SYNC_NATIVE_FENCE_ANDROID\n");
        return false;
    }

    surface->flush();
    GR_GL_CALL(fGLCtx->gl(), Flush());
    fFdHandle = fEGLDupNativeFenceFDANDROID(eglDisplay, eglsync);

    EGLint result = fEGLDestroySyncKHR(eglDisplay, eglsync);
    if (EGL_TRUE != result) {
        ERRORF(reporter, "Failed to delete EGLSync, error: %d\n", result);
        return false;
    }

    return true;
}

bool EGLTestHelper::importAndWaitOnSemaphore(skiatest::Reporter* reporter, int fdHandle,
                                             sk_sp<SkSurface> surface) {
    EGLDisplay eglDisplay = eglGetCurrentDisplay();
    EGLint attr[] = {
        EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fdHandle,
        EGL_NONE
    };
    EGLSyncKHR eglsync = fEGLCreateSyncKHR(eglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attr);
    if (EGL_NO_SYNC_KHR == eglsync) {
        ERRORF(reporter,
               "Failed to create EGLSync when importing EGL_SYNC_NATIVE_FENCE_FD_ANDROID\n");
        return false;
    }
    EGLint result = fEGLWaitSyncKHR(eglDisplay, eglsync, 0);
    if (EGL_TRUE != result) {
        ERRORF(reporter, "Failed called to eglWaitSyncKHR, error: %d\n", result);
        // Don't return false yet, try to delete the sync first
    }
    result = fEGLDestroySyncKHR(eglDisplay, eglsync);
    if (EGL_TRUE != result) {
        ERRORF(reporter, "Failed to delete EGLSync, error: %d\n", result);
        return false;
    }
    return true;
}

void EGLTestHelper::doClientSync() {
    sk_gpu_test::FenceSync* fenceSync = fGLCtx->fenceSync();
    sk_gpu_test::PlatformFence fence = fenceSync->insertFence();
    fenceSync->waitFence(fence);
    fenceSync->deleteFence(fence);
}

#define DECLARE_VK_PROC(name) PFN_vk##name fVk##name

#define ACQUIRE_INST_VK_PROC(name)                                                           \
    fVk##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, fBackendContext.fInstance,\
                                                       VK_NULL_HANDLE));                     \
    if (fVk##name == nullptr) {                                                              \
        ERRORF(reporter, "Function ptr for vk%s could not be acquired\n", #name);            \
        return false;                                                                        \
    }

#define ACQUIRE_DEVICE_VK_PROC(name)                                                          \
    fVk##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, VK_NULL_HANDLE, fDevice)); \
    if (fVk##name == nullptr) {                                                               \
        ERRORF(reporter, "Function ptr for vk%s could not be acquired\n", #name);             \
        return false;                                                                         \
    }

class VulkanTestHelper : public BaseTestHelper {
public:
    VulkanTestHelper() {}

    ~VulkanTestHelper() override {}

    void releaseImage() override {
        if (VK_NULL_HANDLE == fDevice) {
            return;
        }
        if (fImage != VK_NULL_HANDLE) {
            fVkDestroyImage(fDevice, fImage, nullptr);
            fImage = VK_NULL_HANDLE;
        }

        if (fMemory != VK_NULL_HANDLE) {
            fVkFreeMemory(fDevice, fMemory, nullptr);
            fMemory = VK_NULL_HANDLE;
        }
    }
    void cleanup() override {
        fGrContext.reset();
        this->releaseImage();
        if (fSignalSemaphore != VK_NULL_HANDLE) {
            fVkDestroySemaphore(fDevice, fSignalSemaphore, nullptr);
            fSignalSemaphore = VK_NULL_HANDLE;
        }
        fBackendContext.fMemoryAllocator.reset();
        if (fDevice != VK_NULL_HANDLE) {
            fVkDeviceWaitIdle(fDevice);
            fVkDestroyDevice(fDevice, nullptr);
            fDevice = VK_NULL_HANDLE;
        }
#ifdef SK_ENABLE_VK_LAYERS
        if (fDebugCallback != VK_NULL_HANDLE) {
            fDestroyDebugCallback(fBackendContext.fInstance, fDebugCallback, nullptr);
        }
#endif
        if (fBackendContext.fInstance != VK_NULL_HANDLE) {
            fVkDestroyInstance(fBackendContext.fInstance, nullptr);
            fBackendContext.fInstance = VK_NULL_HANDLE;
        }

        delete fExtensions;

        sk_gpu_test::FreeVulkanFeaturesStructs(fFeatures);
        delete fFeatures;
    }

    bool init(skiatest::Reporter* reporter) override;

    void doClientSync() override {
        if (!fGrContext) {
            return;
        }

        fGrContext->priv().getGpu()->testingOnly_flushGpuAndSync();
    }

    bool flushSurfaceAndSignalSemaphore(skiatest::Reporter* reporter, sk_sp<SkSurface>) override;
    bool importAndWaitOnSemaphore(skiatest::Reporter* reporter, int fdHandle,
                                  sk_sp<SkSurface>) override;

    sk_sp<SkImage> importHardwareBufferForRead(skiatest::Reporter* reporter,
                                               AHardwareBuffer* buffer) override;

    sk_sp<SkSurface> importHardwareBufferForWrite(skiatest::Reporter* reporter,
                                                  AHardwareBuffer* buffer) override;

    void makeCurrent() override {}

    GrContext* grContext() override { return fGrContext.get(); }

private:
    bool checkOptimalHardwareBuffer(skiatest::Reporter* reporter);

    bool importHardwareBuffer(skiatest::Reporter* reporter, AHardwareBuffer* buffer, bool forWrite,
                              GrVkImageInfo* outImageInfo);

    bool setupSemaphoreForSignaling(skiatest::Reporter* reporter, GrBackendSemaphore*);
    bool exportSemaphore(skiatest::Reporter* reporter, const GrBackendSemaphore&);

    DECLARE_VK_PROC(DestroyInstance);
    DECLARE_VK_PROC(DeviceWaitIdle);
    DECLARE_VK_PROC(DestroyDevice);

    DECLARE_VK_PROC(GetPhysicalDeviceExternalSemaphoreProperties);
    DECLARE_VK_PROC(GetPhysicalDeviceImageFormatProperties2);
    DECLARE_VK_PROC(GetPhysicalDeviceMemoryProperties2);

    DECLARE_VK_PROC(GetAndroidHardwareBufferPropertiesANDROID);

    DECLARE_VK_PROC(CreateImage);
    DECLARE_VK_PROC(GetImageMemoryRequirements2);
    DECLARE_VK_PROC(DestroyImage);

    DECLARE_VK_PROC(AllocateMemory);
    DECLARE_VK_PROC(BindImageMemory2);
    DECLARE_VK_PROC(FreeMemory);

    DECLARE_VK_PROC(CreateSemaphore);
    DECLARE_VK_PROC(GetSemaphoreFdKHR);
    DECLARE_VK_PROC(ImportSemaphoreFdKHR);
    DECLARE_VK_PROC(DestroySemaphore);

    VkImage fImage = VK_NULL_HANDLE;
    VkDeviceMemory fMemory = VK_NULL_HANDLE;

    GrVkExtensions*                     fExtensions = nullptr;
    VkPhysicalDeviceFeatures2*          fFeatures = nullptr;
    VkDebugReportCallbackEXT            fDebugCallback = VK_NULL_HANDLE;
    PFN_vkDestroyDebugReportCallbackEXT fDestroyDebugCallback = nullptr;

    // We hold on to the semaphore so we can delete once the GPU is done.
    VkSemaphore fSignalSemaphore = VK_NULL_HANDLE;

    VkDevice fDevice = VK_NULL_HANDLE;

    GrVkBackendContext fBackendContext;
    sk_sp<GrContext> fGrContext;
};

bool VulkanTestHelper::init(skiatest::Reporter* reporter) {
    PFN_vkGetInstanceProcAddr instProc;
    PFN_vkGetDeviceProcAddr devProc;
    if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
        return false;
    }
    auto getProc = [&instProc, &devProc](const char* proc_name,
                                         VkInstance instance, VkDevice device) {
        if (device != VK_NULL_HANDLE) {
            return devProc(device, proc_name);
        }
        return instProc(instance, proc_name);
    };

    fExtensions = new GrVkExtensions();
    fFeatures = new VkPhysicalDeviceFeatures2;
    memset(fFeatures, 0, sizeof(VkPhysicalDeviceFeatures2));
    fFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
    fFeatures->pNext = nullptr;

    fBackendContext.fInstance = VK_NULL_HANDLE;
    fBackendContext.fDevice = VK_NULL_HANDLE;

    if (!sk_gpu_test::CreateVkBackendContext(getProc, &fBackendContext, fExtensions,
                                             fFeatures, &fDebugCallback)) {
        return false;
    }
    fDevice = fBackendContext.fDevice;

    if (fDebugCallback != VK_NULL_HANDLE) {
        fDestroyDebugCallback = (PFN_vkDestroyDebugReportCallbackEXT) instProc(
                fBackendContext.fInstance, "vkDestroyDebugReportCallbackEXT");
    }

    ACQUIRE_INST_VK_PROC(DestroyInstance);
    ACQUIRE_INST_VK_PROC(DeviceWaitIdle);
    ACQUIRE_INST_VK_PROC(DestroyDevice);

    if (!fExtensions->hasExtension(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
                                  2)) {
        return false;
    }
    if (!fExtensions->hasExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1)) {
        return false;
    }
    if (!fExtensions->hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
        return false;
    }
    if (!fExtensions->hasExtension(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME, 1)) {
    //    return false;
    }

    ACQUIRE_INST_VK_PROC(GetPhysicalDeviceMemoryProperties2);
    ACQUIRE_INST_VK_PROC(GetPhysicalDeviceImageFormatProperties2);
    ACQUIRE_INST_VK_PROC(GetPhysicalDeviceExternalSemaphoreProperties);

    ACQUIRE_DEVICE_VK_PROC(GetAndroidHardwareBufferPropertiesANDROID);

    ACQUIRE_DEVICE_VK_PROC(CreateImage);
    ACQUIRE_DEVICE_VK_PROC(GetImageMemoryRequirements2);
    ACQUIRE_DEVICE_VK_PROC(DestroyImage);

    ACQUIRE_DEVICE_VK_PROC(AllocateMemory);
    ACQUIRE_DEVICE_VK_PROC(BindImageMemory2);
    ACQUIRE_DEVICE_VK_PROC(FreeMemory);

    ACQUIRE_DEVICE_VK_PROC(CreateSemaphore);
    ACQUIRE_DEVICE_VK_PROC(GetSemaphoreFdKHR);
    ACQUIRE_DEVICE_VK_PROC(ImportSemaphoreFdKHR);
    ACQUIRE_DEVICE_VK_PROC(DestroySemaphore);

    fGrContext = GrContext::MakeVulkan(fBackendContext);
    REPORTER_ASSERT(reporter, fGrContext.get());
    if (!fGrContext) {
        return false;
    }

    return this->checkOptimalHardwareBuffer(reporter);
}

bool VulkanTestHelper::checkOptimalHardwareBuffer(skiatest::Reporter* reporter) {
    VkResult err;

    VkPhysicalDeviceExternalImageFormatInfo externalImageFormatInfo;
    externalImageFormatInfo.sType =
            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
    externalImageFormatInfo.pNext = nullptr;
    externalImageFormatInfo.handleType =
            VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
    //externalImageFormatInfo.handType = 0x80;

    // We will create the hardware buffer with gpu sampled so these usages should all be valid
    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
                                   VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
                                   VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    VkPhysicalDeviceImageFormatInfo2 imageFormatInfo;
    imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
    imageFormatInfo.pNext = &externalImageFormatInfo;
    imageFormatInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
    imageFormatInfo.type = VK_IMAGE_TYPE_2D;
    imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
    imageFormatInfo.usage = usageFlags;
    imageFormatInfo.flags = 0;

    VkAndroidHardwareBufferUsageANDROID hwbUsage;
    hwbUsage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
    hwbUsage.pNext = nullptr;

    VkExternalImageFormatProperties externalImgFormatProps;
    externalImgFormatProps.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
    externalImgFormatProps.pNext = &hwbUsage;

    VkImageFormatProperties2 imgFormProps;
    imgFormProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
    imgFormProps.pNext = &externalImgFormatProps;

    err = fVkGetPhysicalDeviceImageFormatProperties2(fBackendContext.fPhysicalDevice,
                                                     &imageFormatInfo, &imgFormProps);
    if (VK_SUCCESS != err) {
        ERRORF(reporter, "vkGetPhysicalDeviceImageFormatProperites failed, err: %d", err);
        return false;
    }

    const VkImageFormatProperties& imageFormatProperties = imgFormProps.imageFormatProperties;
    REPORTER_ASSERT(reporter, DEV_W <= imageFormatProperties.maxExtent.width);
    REPORTER_ASSERT(reporter, DEV_H <= imageFormatProperties.maxExtent.height);

    const VkExternalMemoryProperties& externalImageFormatProps =
            externalImgFormatProps.externalMemoryProperties;
    REPORTER_ASSERT(reporter, SkToBool(VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT &
                                       externalImageFormatProps.externalMemoryFeatures));
    REPORTER_ASSERT(reporter, SkToBool(VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT &
                                       externalImageFormatProps.externalMemoryFeatures));

    REPORTER_ASSERT(reporter, SkToBool(AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE &
                                       hwbUsage.androidHardwareBufferUsage));

    return true;
}

bool VulkanTestHelper::importHardwareBuffer(skiatest::Reporter* reporter,
                                            AHardwareBuffer* buffer,
                                            bool forWrite,
                                            GrVkImageInfo* outImageInfo) {
    VkResult err;

    VkAndroidHardwareBufferFormatPropertiesANDROID hwbFormatProps;
    hwbFormatProps.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
    hwbFormatProps.pNext = nullptr;

    VkAndroidHardwareBufferPropertiesANDROID hwbProps;
    hwbProps.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
    hwbProps.pNext = &hwbFormatProps;

    err = fVkGetAndroidHardwareBufferPropertiesANDROID(fDevice, buffer, &hwbProps);
    if (VK_SUCCESS != err) {
        ERRORF(reporter, "GetAndroidHardwareBufferPropertiesAndroid failed, err: %d", err);
        return false;
    }

    REPORTER_ASSERT(reporter, VK_FORMAT_R8G8B8A8_UNORM == hwbFormatProps.format);
    REPORTER_ASSERT(reporter,
                    SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & hwbFormatProps.formatFeatures) &&
                    SkToBool(VK_FORMAT_FEATURE_TRANSFER_SRC_BIT & hwbFormatProps.formatFeatures) &&
                    SkToBool(VK_FORMAT_FEATURE_TRANSFER_DST_BIT & hwbFormatProps.formatFeatures));
    if (forWrite) {
        REPORTER_ASSERT(reporter,
                SkToBool(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT & hwbFormatProps.formatFeatures));

    }

    bool useExternalFormat = VK_FORMAT_UNDEFINED == hwbFormatProps.format;
    const VkExternalFormatANDROID externalFormatInfo {
        VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,             // sType
        nullptr,                                               // pNext
        useExternalFormat ? hwbFormatProps.externalFormat : 0, // externalFormat
    };

    const VkExternalMemoryImageCreateInfo externalMemoryImageInfo {
        VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, // sType
        &externalFormatInfo, // pNext
        VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, // handleTypes
    };

    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT |
                                   VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
                                   VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    if (forWrite) {
        usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    }

    const VkImageCreateInfo imageCreateInfo = {
        VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,         // sType
        &externalMemoryImageInfo,                    // pNext
        0,                                           // VkImageCreateFlags
        VK_IMAGE_TYPE_2D,                            // VkImageType
        hwbFormatProps.format,                       // VkFormat
        { DEV_W, DEV_H, 1 },                         // VkExtent3D
        1,                                           // mipLevels
        1,                                           // arrayLayers
        VK_SAMPLE_COUNT_1_BIT,                       // samples
        VK_IMAGE_TILING_OPTIMAL,                     // VkImageTiling
        usageFlags,                                  // VkImageUsageFlags
        VK_SHARING_MODE_EXCLUSIVE,                   // VkSharingMode
        0,                                           // queueFamilyCount
        0,                                           // pQueueFamilyIndices
        VK_IMAGE_LAYOUT_UNDEFINED,                   // initialLayout
    };

    err = fVkCreateImage(fDevice, &imageCreateInfo, nullptr, &fImage);
    if (VK_SUCCESS != err) {
        ERRORF(reporter, "Create Image failed, err: %d", err);
        return false;
    }

    VkPhysicalDeviceMemoryProperties2 phyDevMemProps;
    phyDevMemProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
    phyDevMemProps.pNext = nullptr;

    uint32_t typeIndex = 0;
    uint32_t heapIndex = 0;
    bool foundHeap = false;
    fVkGetPhysicalDeviceMemoryProperties2(fBackendContext.fPhysicalDevice, &phyDevMemProps);
    uint32_t memTypeCnt = phyDevMemProps.memoryProperties.memoryTypeCount;
    for (uint32_t i = 0; i < memTypeCnt && !foundHeap; ++i) {
        if (hwbProps.memoryTypeBits & (1 << i)) {
            const VkPhysicalDeviceMemoryProperties& pdmp = phyDevMemProps.memoryProperties;
            uint32_t supportedFlags = pdmp.memoryTypes[i].propertyFlags &
                    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
            if (supportedFlags == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
                typeIndex = i;
                heapIndex = pdmp.memoryTypes[i].heapIndex;
                foundHeap = true;
            }
        }
    }
    if (!foundHeap) {
        ERRORF(reporter, "Failed to find valid heap for imported memory");
        return false;
    }

    VkImportAndroidHardwareBufferInfoANDROID hwbImportInfo;
    hwbImportInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
    hwbImportInfo.pNext = nullptr;
    hwbImportInfo.buffer = buffer;

    VkMemoryDedicatedAllocateInfo dedicatedAllocInfo;
    dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
    dedicatedAllocInfo.pNext = &hwbImportInfo;
    dedicatedAllocInfo.image = fImage;
    dedicatedAllocInfo.buffer = VK_NULL_HANDLE;

    VkMemoryAllocateInfo allocInfo = {
        VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,      // sType
        &dedicatedAllocInfo,                         // pNext
        hwbProps.allocationSize,                     // allocationSize
        typeIndex,                                   // memoryTypeIndex
    };

    err = fVkAllocateMemory(fDevice, &allocInfo, nullptr, &fMemory);
    if (VK_SUCCESS != err) {
        ERRORF(reporter, "AllocateMemory failed for imported buffer, err: %d", err);
        return false;
    }

    VkBindImageMemoryInfo bindImageInfo;
    bindImageInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
    bindImageInfo.pNext = nullptr;
    bindImageInfo.image = fImage;
    bindImageInfo.memory = fMemory;
    bindImageInfo.memoryOffset = 0;

    err = fVkBindImageMemory2(fDevice, 1, &bindImageInfo);
    if (VK_SUCCESS != err) {
        ERRORF(reporter, "BindImageMemory failed for imported buffer, err: %d", err);
        return false;
    }

    outImageInfo->fImage = fImage;
    outImageInfo->fAlloc = GrVkAlloc(fMemory, 0, hwbProps.allocationSize, 0);
    outImageInfo->fImageTiling = VK_IMAGE_TILING_OPTIMAL;
    outImageInfo->fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    outImageInfo->fFormat = VK_FORMAT_R8G8B8A8_UNORM;
    outImageInfo->fLevelCount = 1;
    outImageInfo->fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
    return true;
}

sk_sp<SkImage> VulkanTestHelper::importHardwareBufferForRead(skiatest::Reporter* reporter,
                                                             AHardwareBuffer* buffer) {
    GrVkImageInfo imageInfo;
    if (!this->importHardwareBuffer(reporter, buffer, false, &imageInfo)) {
        return nullptr;
    }

    GrBackendTexture backendTex(DEV_W, DEV_H, imageInfo);

    sk_sp<SkImage> wrappedImage = SkImage::MakeFromTexture(fGrContext.get(),
                                                           backendTex,
                                                           kTopLeft_GrSurfaceOrigin,
                                                           kRGBA_8888_SkColorType,
                                                           kPremul_SkAlphaType,
                                                           nullptr);

    if (!wrappedImage.get()) {
        ERRORF(reporter, "Failed to create wrapped Vulkan SkImage");
        return nullptr;
    }

    return wrappedImage;
}

bool VulkanTestHelper::flushSurfaceAndSignalSemaphore(skiatest::Reporter* reporter,
                                                      sk_sp<SkSurface> surface) {
    surface->flush();
    surface.reset();
    GrBackendSemaphore semaphore;
    if (!this->setupSemaphoreForSignaling(reporter, &semaphore)) {
        return false;
    }
    GrSemaphoresSubmitted submitted = fGrContext->flush(kNone_GrFlushFlags, 1, &semaphore);
    if (GrSemaphoresSubmitted::kNo == submitted) {
        ERRORF(reporter, "Failing call to flush on GrContext");
        return false;
    }
    SkASSERT(semaphore.isInitialized());
    if (!this->exportSemaphore(reporter, semaphore)) {
        return false;
    }
    return true;
}

bool VulkanTestHelper::setupSemaphoreForSignaling(skiatest::Reporter* reporter,
                                                  GrBackendSemaphore* beSemaphore) {
    // Query supported info
    VkPhysicalDeviceExternalSemaphoreInfo exSemInfo;
    exSemInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO;
    exSemInfo.pNext = nullptr;
    exSemInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;

    VkExternalSemaphoreProperties exSemProps;
    exSemProps.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES;
    exSemProps.pNext = nullptr;

    fVkGetPhysicalDeviceExternalSemaphoreProperties(fBackendContext.fPhysicalDevice, &exSemInfo,
                                                    &exSemProps);

    if (!SkToBool(exSemProps.exportFromImportedHandleTypes &
                 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)) {
        ERRORF(reporter, "HANDLE_TYPE_SYNC_FD not listed as exportFromImportedHandleTypes");
        return false;
    }
    if (!SkToBool(exSemProps.compatibleHandleTypes &
                  VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)) {
        ERRORF(reporter, "HANDLE_TYPE_SYNC_FD not listed as compatibleHandleTypes");
        return false;
    }
    if (!SkToBool(exSemProps.externalSemaphoreFeatures &
                  VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT) ||
        !SkToBool(exSemProps.externalSemaphoreFeatures &
                  VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT)) {
        ERRORF(reporter, "HANDLE_TYPE_SYNC_FD doesn't support export and import feature");
        return false;
    }

    VkExportSemaphoreCreateInfo exportInfo;
    exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
    exportInfo.pNext = nullptr;
    exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;

    VkSemaphoreCreateInfo semaphoreInfo;
    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
    semaphoreInfo.pNext = &exportInfo;
    semaphoreInfo.flags = 0;

    VkSemaphore semaphore;
    VkResult err = fVkCreateSemaphore(fDevice, &semaphoreInfo, nullptr, &semaphore);
    if (VK_SUCCESS != err) {
        ERRORF(reporter, "Failed to create signal semaphore, err: %d", err);
        return false;
    }
    beSemaphore->initVulkan(semaphore);
    return true;
}

bool VulkanTestHelper::exportSemaphore(skiatest::Reporter* reporter,
                                       const GrBackendSemaphore& beSemaphore) {
    VkSemaphore semaphore = beSemaphore.vkSemaphore();
    if (VK_NULL_HANDLE == semaphore) {
        ERRORF(reporter, "Invalid vulkan handle in export call");
        return false;
    }

    VkSemaphoreGetFdInfoKHR getFdInfo;
    getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
    getFdInfo.pNext = nullptr;
    getFdInfo.semaphore = semaphore;
    getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;

    VkResult err = fVkGetSemaphoreFdKHR(fDevice, &getFdInfo, &fFdHandle);
    if (VK_SUCCESS != err) {
        ERRORF(reporter, "Failed to export signal semaphore, err: %d", err);
        return false;
    }
    fSignalSemaphore = semaphore;
    return true;
}

bool VulkanTestHelper::importAndWaitOnSemaphore(skiatest::Reporter* reporter, int fdHandle,
                                                sk_sp<SkSurface> surface) {
    VkSemaphoreCreateInfo semaphoreInfo;
    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
    semaphoreInfo.pNext = nullptr;
    semaphoreInfo.flags = 0;

    VkSemaphore semaphore;
    VkResult err = fVkCreateSemaphore(fDevice, &semaphoreInfo, nullptr, &semaphore);
    if (VK_SUCCESS != err) {
        ERRORF(reporter, "Failed to create import semaphore, err: %d", err);
        return false;
    }

    VkImportSemaphoreFdInfoKHR importInfo;
    importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
    importInfo.pNext = nullptr;
    importInfo.semaphore = semaphore;
    importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
    importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
    importInfo.fd = fdHandle;

    err = fVkImportSemaphoreFdKHR(fDevice, &importInfo);
    if (VK_SUCCESS != err) {
        ERRORF(reporter, "Failed to import semaphore, err: %d", err);
        return false;
    }

    GrBackendSemaphore beSemaphore;
    beSemaphore.initVulkan(semaphore);
    if (!surface->wait(1, &beSemaphore)) {
        ERRORF(reporter, "Failed to add wait semaphore to surface");
        fVkDestroySemaphore(fDevice, semaphore, nullptr);
        return false;
    }
    return true;
}

sk_sp<SkSurface> VulkanTestHelper::importHardwareBufferForWrite(skiatest::Reporter* reporter,
                                                                AHardwareBuffer* buffer) {
    GrVkImageInfo imageInfo;
    if (!this->importHardwareBuffer(reporter, buffer, true, &imageInfo)) {
        return nullptr;
    }

    GrBackendTexture backendTex(DEV_W, DEV_H, imageInfo);

    sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(fGrContext.get(),
                                                                 backendTex,
                                                                 kTopLeft_GrSurfaceOrigin,
                                                                 0,
                                                                 kRGBA_8888_SkColorType,
                                                                 nullptr, nullptr);

    if (!surface.get()) {
        ERRORF(reporter, "Failed to create wrapped Vulkan SkSurface");
        return nullptr;
    }

    return surface;
}

static SkPMColor get_src_color(int x, int y) {
    SkASSERT(x >= 0 && x < DEV_W);
    SkASSERT(y >= 0 && y < DEV_H);

    U8CPU r = x;
    U8CPU g = y;
    U8CPU b = 0xc;

    U8CPU a = 0xff;
    switch ((x+y) % 5) {
        case 0:
            a = 0xff;
            break;
        case 1:
            a = 0x80;
            break;
        case 2:
            a = 0xCC;
            break;
        case 4:
            a = 0x01;
            break;
        case 3:
            a = 0x00;
            break;
    }
    a = 0xff;
    return SkPremultiplyARGBInline(a, r, g, b);
}

static SkBitmap make_src_bitmap() {
    static SkBitmap bmp;
    if (bmp.isNull()) {
        bmp.allocN32Pixels(DEV_W, DEV_H);
        intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
        for (int y = 0; y < DEV_H; ++y) {
            for (int x = 0; x < DEV_W; ++x) {
                SkPMColor* pixel = reinterpret_cast<SkPMColor*>(
                        pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
                *pixel = get_src_color(x, y);
            }
        }
    }
    return bmp;
}

static bool check_read(skiatest::Reporter* reporter, const SkBitmap& srcBitmap,
                       const SkBitmap& dstBitmap) {
    bool result = true;
    for (int y = 0; y < DEV_H && result; ++y) {
        for (int x = 0; x < DEV_W && result; ++x) {
            const uint32_t srcPixel = *srcBitmap.getAddr32(x, y);
            const uint32_t dstPixel = *dstBitmap.getAddr32(x, y);
            if (srcPixel != dstPixel) {
                ERRORF(reporter, "Expected readback pixel (%d, %d) value 0x%08x, got 0x%08x.",
                       x, y,  srcPixel, dstPixel);
                result = false;
            } /*else {
                ERRORF(reporter, "Got good readback pixel (%d, %d) value 0x%08x, got 0x%08x.",
                       x, y,  srcPixel, dstPixel);

            }*/
        }
    }
    return result;
}

static void cleanup_resources(BaseTestHelper* srcHelper, BaseTestHelper* dstHelper,
                              AHardwareBuffer* buffer) {
    if (srcHelper) {
        srcHelper->cleanup();
    }
    if (dstHelper) {
        dstHelper->cleanup();
    }
    if (buffer) {
        AHardwareBuffer_release(buffer);
    }
}

enum class SrcType {
    kCPU,
    kEGL,
    kVulkan,
};

enum class DstType {
    kEGL,
    kVulkan,
};

void run_test(skiatest::Reporter* reporter, const GrContextOptions& options,
              SrcType srcType, DstType dstType, bool shareSyncs) {
    if (SrcType::kCPU == srcType && shareSyncs) {
        // We don't currently test this since we don't do any syncs in this case.
        return;
    }
    std::unique_ptr<BaseTestHelper> srcHelper;
    std::unique_ptr<BaseTestHelper> dstHelper;
    AHardwareBuffer* buffer = nullptr;
    if (SrcType::kVulkan == srcType) {
        srcHelper.reset(new VulkanTestHelper());
    } else if (SrcType::kEGL == srcType) {
        srcHelper.reset(new EGLTestHelper(options));
    }
    if (srcHelper) {
        if (!srcHelper->init(reporter)) {
            cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
            return;
        }
    }

    if (DstType::kVulkan == dstType) {
        dstHelper.reset(new VulkanTestHelper());
    } else {
        SkASSERT(DstType::kEGL == dstType);
        dstHelper.reset(new EGLTestHelper(options));
    }
    if (dstHelper) {
        if (!dstHelper->init(reporter)) {
            cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
            return;
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // Setup SkBitmaps
    ///////////////////////////////////////////////////////////////////////////

    SkBitmap srcBitmap = make_src_bitmap();
    SkBitmap dstBitmapSurface;
    dstBitmapSurface.allocN32Pixels(DEV_W, DEV_H);
    SkBitmap dstBitmapFinal;
    dstBitmapFinal.allocN32Pixels(DEV_W, DEV_H);

    ///////////////////////////////////////////////////////////////////////////
    // Setup AHardwareBuffer
    ///////////////////////////////////////////////////////////////////////////

    AHardwareBuffer_Desc hwbDesc;
    hwbDesc.width = DEV_W;
    hwbDesc.height = DEV_H;
    hwbDesc.layers = 1;
    if (SrcType::kCPU == srcType) {
        hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
                        AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
                        AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
    } else {
        hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER |
                        AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER |
                        AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
                        AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
    }
    hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
    // The following three are not used in the allocate
    hwbDesc.stride = 0;
    hwbDesc.rfu0= 0;
    hwbDesc.rfu1= 0;

    if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) {
        ERRORF(reporter, "Failed to allocated hardware buffer, error: %d", error);
        cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
        return;
    }

    if (SrcType::kCPU == srcType) {
        // Get actual desc for allocated buffer so we know the stride for uploading cpu data.
        AHardwareBuffer_describe(buffer, &hwbDesc);

        uint32_t* bufferAddr;
        if (AHardwareBuffer_lock(buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, nullptr,
                                 reinterpret_cast<void**>(&bufferAddr))) {
            ERRORF(reporter, "Failed to lock hardware buffer");
            cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
            return;
        }

        int bbp = srcBitmap.bytesPerPixel();
        uint32_t* src = (uint32_t*)srcBitmap.getPixels();
        uint32_t* dst = bufferAddr;
        for (int y = 0; y < DEV_H; ++y) {
            memcpy(dst, src, DEV_W * bbp);
            src += DEV_W;
            dst += hwbDesc.stride;
        }

        for (int y = 0; y < DEV_H; ++y) {
            for (int x = 0; x < DEV_W; ++x) {
                const uint32_t srcPixel = *srcBitmap.getAddr32(x, y);
                uint32_t dstPixel = bufferAddr[y * hwbDesc.stride + x];
                if (srcPixel != dstPixel) {
                    ERRORF(reporter, "CPU HWB Expected readpix (%d, %d) value 0x%08x, got 0x%08x.",
                           x, y, srcPixel, dstPixel);
                }
            }
        }

        AHardwareBuffer_unlock(buffer, nullptr);

    } else {
        srcHelper->makeCurrent();
        sk_sp<SkSurface> surface = srcHelper->importHardwareBufferForWrite(reporter, buffer);

        if (!surface) {
            cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
            return;
        }

        sk_sp<SkImage> srcBmpImage = SkImage::MakeFromBitmap(srcBitmap);
        surface->getCanvas()->drawImage(srcBmpImage, 0, 0);

        // If we are testing sharing of syncs, don't do a read here since it forces sychronization
        // to occur.
        if (!shareSyncs) {
            bool readResult = surface->readPixels(dstBitmapSurface, 0, 0);
            if (!readResult) {
                ERRORF(reporter, "Read Pixels on surface failed");
                surface.reset();
                cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
                return;
            }
            REPORTER_ASSERT(reporter, check_read(reporter, srcBitmap, dstBitmapSurface));
        }

        ///////////////////////////////////////////////////////////////////////////
        // Cleanup GL/EGL and add syncs
        ///////////////////////////////////////////////////////////////////////////

        if (shareSyncs) {
            if (!srcHelper->flushSurfaceAndSignalSemaphore(reporter, std::move(surface))) {
                cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
                return;
            }
        } else {
            surface.reset();
            srcHelper->doClientSync();
            srcHelper->releaseImage();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // Import the HWB into backend and draw it to a surface
    ///////////////////////////////////////////////////////////////////////////

    dstHelper->makeCurrent();
    sk_sp<SkImage> wrappedImage = dstHelper->importHardwareBufferForRead(reporter, buffer);

    if (!wrappedImage) {
        cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
        return;
    }

    GrContext* grContext = dstHelper->grContext();

    // Make SkSurface to render wrapped HWB into.
    SkImageInfo imageInfo = SkImageInfo::Make(DEV_W, DEV_H, kRGBA_8888_SkColorType,
                                              kPremul_SkAlphaType, nullptr);

    sk_sp<SkSurface> dstSurf = SkSurface::MakeRenderTarget(grContext,
                                                           SkBudgeted::kNo, imageInfo, 0,
                                                           kTopLeft_GrSurfaceOrigin,
                                                           nullptr, false);
    if (!dstSurf.get()) {
        ERRORF(reporter, "Failed to create destination SkSurface");
        wrappedImage.reset();
        cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
        return;
    }

    if (shareSyncs) {
        if (!dstHelper->importAndWaitOnSemaphore(reporter, srcHelper->getFdHandle(), dstSurf)) {
            wrappedImage.reset();
            cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
            return;
        }
    }
    dstSurf->getCanvas()->drawImage(wrappedImage, 0, 0);

    bool readResult = dstSurf->readPixels(dstBitmapFinal, 0, 0);
    if (!readResult) {
        ERRORF(reporter, "Read Pixels failed");
        wrappedImage.reset();
        dstSurf.reset();
        dstHelper->doClientSync();
        cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
        return;
    }

    REPORTER_ASSERT(reporter, check_read(reporter, srcBitmap, dstBitmapFinal));

    dstSurf.reset();
    wrappedImage.reset();
    dstHelper->doClientSync();
    cleanup_resources(srcHelper.get(), dstHelper.get(), buffer);
}

DEF_GPUTEST(VulkanHardwareBuffer_CPU_Vulkan, reporter, options) {
    run_test(reporter, options, SrcType::kCPU, DstType::kVulkan, false);
}

DEF_GPUTEST(VulkanHardwareBuffer_EGL_Vulkan, reporter, options) {
    run_test(reporter, options, SrcType::kEGL, DstType::kVulkan, false);
}

DEF_GPUTEST(VulkanHardwareBuffer_Vulkan_Vulkan, reporter, options) {
    run_test(reporter, options, SrcType::kVulkan, DstType::kVulkan, false);
}

DEF_GPUTEST(VulkanHardwareBuffer_CPU_EGL, reporter, options) {
    run_test(reporter, options, SrcType::kCPU, DstType::kEGL, false);
}

DEF_GPUTEST(VulkanHardwareBuffer_EGL_EGL, reporter, options) {
    run_test(reporter, options, SrcType::kEGL, DstType::kEGL, false);
}

DEF_GPUTEST(VulkanHardwareBuffer_Vulkan_EGL, reporter, options) {
    run_test(reporter, options, SrcType::kVulkan, DstType::kEGL, false);
}

DEF_GPUTEST(VulkanHardwareBuffer_EGL_EGL_Syncs, reporter, options) {
    run_test(reporter, options, SrcType::kEGL, DstType::kEGL, true);
}

DEF_GPUTEST(VulkanHardwareBuffer_Vulkan_EGL_Syncs, reporter, options) {
    run_test(reporter, options, SrcType::kVulkan, DstType::kEGL, true);
}

DEF_GPUTEST(VulkanHardwareBuffer_EGL_Vulkan_Syncs, reporter, options) {
    run_test(reporter, options, SrcType::kEGL, DstType::kVulkan, true);
}

DEF_GPUTEST(VulkanHardwareBuffer_Vulkan_Vulkan_Syncs, reporter, options) {
    run_test(reporter, options, SrcType::kVulkan, DstType::kVulkan, true);
}

#endif


text:
Stay In Touch

 Some description goes here E

							 <?php echo form_open("home/subscribe", array('class'=>'form-subscribe','method'=>'post'));?>

                                	<input type="hidden" name="search_page" value="1">
                                    <input type="text" name="subscriber_email" placeholder="Enter Email Address" class="form-control ">

                                	<button type="submit" class="subscribe-button"> </button>

							<?php echo form_close();?>

					<?php echo "
".form_error('subscriber_email')."
";
                    echo "
".$this->session->flashdata('success_msg')."
";
                    echo "
".$this->session->flashdata('fail_msg')."
";
                    ?>

redpajama_set_name: RedPajamaGithub


text:
/*
 * notifIt! by @naoxink
 */
(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(factory);
    } else {
        // Browser globals
        var package = factory(root.b);
        root.notif = package.notif;
        root.notif_confirm = package.notif_confirm;
        root.notif_prompt  = package.notif_prompt;
    }
}(this, function() {

    // Notification
    function notif(config) {
        // Util stuff
        var create_close_button = function() {
            return $('<span>', {
                'id': 'notifIt_close',
                'html': '&times'
            });
        }
        var create_notification = function() {
                var div = $('<div>', {
                    'id': 'ui_notifIt'
                });
                var p = $('<p>', {
                    html: defaults.msg
                });
                div.append(p);
                return div;
        }
        // We love jQuery
        var $ = jQuery;
        var destroy = function() {
            $("#ui_notifIt").remove();
            clearTimeout(window.notifit_timeout);
        }
        var dismiss = function(){
            clearTimeout(window.notifit_timeout);
            if (!defaults.fade) {
                // Set animations
                if (defaults.animations &&
                    defaults.animations[defaults.animation] &&
                    defaults.animations[defaults.animation][defaults.position] &&
                    defaults.animations[defaults.animation][defaults.position].out &&
                    defaults.animations[defaults.animation][defaults.position].out.start &&
                    defaults.animations[defaults.animation][defaults.position].out.end) {
                    animation1 = defaults.animations[defaults.animation][defaults.position].out.start
                    animation2 = defaults.animations[defaults.animation][defaults.position].out.end
                } else if (defaults.animations[defaults.available_animations[0]] &&
                    defaults.animations[defaults.available_animations[0]][defaults.position] &&
                    defaults.animations[defaults.available_animations[0]][defaults.position].out &&
                    defaults.animations[defaults.available_animations[0]][defaults.position].out.start &&
                    defaults.animations[defaults.available_animations[0]][defaults.position].out.end) {
                    animation1 = defaults.animations[defaults.available_animations[0]][defaults.position].out.start
                    animation2 = defaults.animations[defaults.available_animations[0]][defaults.position].out.end
                } else {
                    throw new Error('Invalid animation')
                }
                // Execute animations
                $("#ui_notifIt").animate(animation1, 100, function() {
                    $("#ui_notifIt").animate(animation2, 100, function() {
                        $("#ui_notifIt").remove();
                        if (defaults.callback) {
                            defaults.callback();
                        }
                    });
                });
            } else {
                // jQuery's fade, why create my own?
                $("#ui_notifIt").fadeOut("slow", function() {
                    $("#ui_notifIt").remove();
                    if (defaults.callback) {
                        defaults.callback();
                    }
                });
            }
        }
        destroy()
        // Global timeout
        window.notifit_timeout = null;
        // Mid position
        var mid = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) / 2;
        // Available positions
        var available_positions = ['left', 'center', 'right', 'bottom'];
        // Default config
        var defaults = {
            type: "default",
            width: 400,
            height: 60,
            position: "right",
            autohide: 1,
            msg: "This is my default message",
            opacity: 1,
            multiline: 0,
            fade: 0,
            bgcolor: "",
            color: "",
            timeout: 5000,
            zindex: null,
            offset: 0,
            callback: null,
            clickable: false,
            animation: 'slide'
        };
        // Extend with new params
        $.extend(defaults, config);
        // Animation config
        // ** Maybe create an external js with only animations for easier customizing? **
        defaults.animations = {}
        // Slide animation [DEFAULT]
        defaults.animations.slide = {
            'center': {
                'css_start': {
                    "top": parseInt(0 - (defaults.height + 10)),
                    "left": mid - parseInt(defaults.width / 2)
                },
                'in': {
                    'top': parseInt(10 + defaults.offset)
                },
                'out': {
                    'start': {
                        'top': parseInt(defaults.height - (defaults.height / 2))
                    },
                    'end': {
                        'top': parseInt(0 - (defaults.height * 2))
                    }
                }
            },
            'bottom': {
                'css_start': {
                    "top": 'auto',
                    "bottom": parseInt(0 - (defaults.height + 10)),
                    "left": mid - parseInt(defaults.width / 2)
                },
                'in': {
                    'bottom': parseInt(10 + defaults.offset)
                },
                'out': {
                    'start': {
                        'bottom': parseInt(defaults.height - (defaults.height / 2))
                    },
                    'end': {
                        'bottom': parseInt(0 - (defaults.height * 2))
                    }
                }
            },
            'right': {
                'css_start': {
                    "right": parseInt(0 - (defaults.width + 10)),
                    "right": parseInt(0 - (defaults.width * 2))
                },
                'in': {
                    'right': parseInt(10 + defaults.offset)
                },
                'out': {
                    'start': {
                        'right': parseFloat(defaults.width - (defaults.width * 0.9))
                    },
                    'end': {
                        'right': parseInt(0 - (defaults.width * 2))
                    }
                }
            },
            'left': {
                'css_start': {
                    "left": parseInt(0 - (defaults.width + 10))
                },
                'in': {
                    'left': parseInt(10 + defaults.offset)
                },
                'out': {
                    'start': {
                        'left': parseFloat(defaults.width - (defaults.width * 0.9))
                    },
                    'end': {
                        'left': parseInt(0 - (defaults.width * 2))
                    }
                }
            }
        };
        // Zoom animation
        defaults.animations.zoom = {
            'center': { // Not working well
                'css_start': {
                    "top": 10,
                    "left": mid - parseInt(defaults.width / 2),
                    "zoom": 0.01
                },
                'in': {
                    'zoom': 1
                },
                'out': {
                    'start': {
                        'zoom': 1.3
                    },
                    'end': {
                        'zoom': 0.01
                    }
                }
            },
            'bottom': { // Not working well
                'css_start': {
                    "top": 'auto',
                    "bottom": 10,
                    "left": mid - parseInt(defaults.width / 2),
                    "zoom": 0.01
                },
                'in': {
                    'zoom': 1
                },
                'out': {
                    'start': {
                        'zoom': 1.3
                    },
                    'end': {
                        'zoom': 0.01
                    }
                }
            },
            'right': {
                'css_start': {
                    'right': 10,
                    'zoom': 0.01
                },
                'in': {
                    'right': parseInt(10 + defaults.offset),
                    'zoom': 1
                },
                'out': {
                    'start': {
                        'zoom': 1.3
                    },
                    'end': {
                        'zoom': 0.01
                    }
                }
            },
            'left': {
                'css_start': {
                    'left': 10,
                    'zoom': 0.01
                },
                'in': {
                    'zoom': 1
                },
                'out': {
                    'start': {
                        'zoom': 1.3
                    },
                    'end': {
                        'zoom': 0.01
                    }
                }
            }
        };
        // Check if animation exists
        defaults.available_animations = Object.keys(defaults.animations)
        if (!defaults.available_animations.length) {
            throw new Error('No animations')
        }
        if (!available_positions.length) {
            throw new Error('No available positions')
        }
        if (available_positions.indexOf(defaults.position) === -1) {
            defaults.position = available_positions[0]
        }
        if (defaults.available_animations.indexOf(defaults.animation) === -1) {
            defaults.animation = defaults.available_animations[0]
        }
        // Check callback
        if (typeof defaults.callback !== 'function') {
            defaults.callback = null;
        }
        // Width & Height
        if (defaults.width > 0) {
            defaults.width = defaults.width;
        } else if (defaults.width === "all") {
            defaults.width = screen.width - 60;
        } else {
            defaults.width = 400;
        }
        if (defaults.height > 100 || defaults.height < 0) {
            defaults.height = 60;
        }
        // Create notification itself
        var div = create_notification()
            // If clickable add close button
        if (defaults.clickable) {
            div.append(create_close_button())
        }
        $("body").append(div);
        // Set z-index
        if (defaults.zindex) {
            $("#ui_notifIt").css("z-index", defaults.zindex);
        }
        // If multiline we have to set the padding instead line-height
        if (defaults.multiline) {
            $("#ui_notifIt").css("padding", 15);
        } else {
            $("#ui_notifIt").css("height", defaults.height);
            $("#ui_notifIt p").css("line-height", defaults.height + "px");
        }
        // Basic css
        $("#ui_notifIt").css({
            "width": defaults.width,
            "opacity": defaults.opacity,
            "background-color": defaults.bgcolor,
            "color": defaults.color
        });
        // Class 'success', 'error', 'warning', 'info'..
        $("#ui_notifIt").addClass(defaults.type);
        // Set entry animation
        if (defaults.animations[defaults.animation][defaults.position].css_start) {
            $("#ui_notifIt").css(defaults.animations[defaults.animation][defaults.position].css_start);
        } else {
            $("#ui_notifIt").css(defaults.animations[defaults.available_animations[0]][defaults.position].css_start);
        }
        // Execute entry animation
        $("#ui_notifIt").animate(defaults.animations[defaults.animation][defaults.position].in);
        // Events
        if (!defaults.clickable) {
            $("#ui_notifIt").click(function(e) {
                e.stopPropagation();
                dismiss(defaults);
            });
        }
        $('body').on('click', '#ui_notifIt #notifIt_close', function() {
            dismiss(defaults);
        });
        if (defaults.autohide) {
            if (!isNaN(defaults.timeout)) {
                window.notifit_timeout = setTimeout(function() {
                    dismiss(defaults);
                }, defaults.timeout);
            }
        }
        return {
            'destroy': destroy,
            'dismiss': dismiss
        }
    }

    // Confirm
    function notif_confirm(config){
        var $ = jQuery
        var _config = {
            'textaccept': 'Accept',
            'textcancel': 'Cancel',
            'message': 'Is that what you want to do?',
            'fullscreen': false,
            'callback': null
        }
        var settings = $.extend({  }, _config, config)
        var $confirm = $('.notifit_confirm')[0] ? $('.notifit_confirm') : null;
        var $bg = $('.notifit_confirm_bg')[0] ? $('.notifit_confirm_bg') : null;

        function _create(){
            if($confirm !== null){
                return $confirm
            }
            var $acceptButton = $('<button>', {
                'class': 'notifit_confirm_accept',
                'text': settings.textaccept
            })
            var $cancelButton = $('<button>', {
                'class': 'notifit_confirm_cancel',
                'text': settings.textcancel
            })
            var $message = $('<div>', {
                'class': 'notifit_confirm_message',
                'text': settings.message
            })
            $confirm = $('<div>', {
                'class': 'notifit_confirm'
            })
            $confirm
                .append($message)
                .append($acceptButton)
                .append($cancelButton)
            $bg = $('<div>', { 'class': 'notifit_confirm_bg' })
            return $confirm
        }
        function _show(){
            if($confirm){
                if(settings.fullscreen){
                    $bg.hide()
                    $confirm.hide()
                    $('body').append($bg)
                    $('body').append($confirm)
                    $confirm.css({
                        'top': $bg.outerHeight() / 2 - ($confirm.outerHeight() / 2),
                        'left': $bg.outerWidth() / 2 - ($confirm.outerWidth() / 2)
                    })
                    $bg.fadeIn('fast', function(){ $confirm.slideDown('fast') })
                }else{
                    $confirm.css({
                        'top': '20px',
                        'left': 'auto',
                        'right': '20px',
                        'display': 'none'
                    })
                    $('body').append($confirm)
                    $confirm.slideDown('fast')
                }
            }
        }
        function _hide(){
            if($confirm){
                $confirm.slideUp('fast', function(){
                    $confirm.remove()
                })
            }
            if($bg){
                $bg.fadeOut('fast', function(){
                    $bg.remove()
                })
            }
        }
        function _callback(){
            _hide()
            var response = null
            if($(this).hasClass('notifit_confirm_accept')){
                response = true
            }else if($(this).hasClass('notifit_confirm_cancel')){
                response = false
            }
            if(typeof settings.callback === 'function'){
                return settings.callback(response)
            }
            return response
        }
        function _setListeners(){
            $('html').one('click', '.notifit_confirm_accept, .notifit_confirm_cancel', _callback)
        }

        // Get the party started! \o/
        _create()
        _show()
        _setListeners()
    }

    // Prompt
    function notif_prompt(config){
        var $ = jQuery
        var _config = {
            'message': 'Tell me something',
            'default_value': '',
            'textaccept': 'Accept',
            'textcancel': 'Cancel',
            'fullscreen': false,
            'callback': null
        }
        var settings = $.extend({  }, _config, config)
        var $prompt = $('.notifit_prompt')[0] ? $('.notifit_prompt') : null;
        var $bg = $('.notifit_prompt_bg')[0] ? $('.notifit_prompt_bg') : null;
        function _create(){
            if($prompt !== null){ return $prompt }
            var $acceptButton = $('<button>', {
                'class': 'notifit_prompt_accept',
                'text': settings.textaccept
            })
            var $cancelButton = $('<button>', {
                'class': 'notifit_prompt_cancel',
                'text': settings.textcancel
            })
            var $message = $('<p>', {
                'class': 'notifit_prompt_message',
                'text': settings.message
            })
            var $input = $('<input>', {
                'type': 'text',
                'class': 'notifit_prompt_input',
                'value': settings.default_value
            })
            $prompt = $('<div>', {
                'class': 'notifit_prompt'
            })
            $prompt
                .append($message)
                .append($input)
                .append($cancelButton)
                .append($acceptButton)
            $bg = $('<div>', { 'class': 'notifit_prompt_bg' })
            return $prompt
        }
        function _show(){
            if($prompt){
                if(settings.fullscreen){
                    $bg.hide()
                    $prompt.hide()
                    $('body').append($bg)
                    $('body').append($prompt)
                    $prompt.css({
                        'top': $bg.outerHeight() / 2 - ($prompt.outerHeight() / 2),
                        'left': $bg.outerWidth() / 2 - ($prompt.outerWidth() / 2)
                    })
                    $bg.fadeIn('fast', function(){ $prompt.slideDown('fast', function(){ $(this).find('.notifit_prompt_input').focus() }) })
                }else{
                    $prompt.css({
                        'top': '20px',
                        'left': 'auto',
                        'right': '20px',
                        'display': 'none'
                    })
                    $('body').append($prompt)
                    $prompt.slideDown('fast', function(){ $(this).find('.notifit_prompt_input').focus() })
                }
            }
        }
        function _hide(){
            if($prompt){
                $prompt.slideUp('fast', function(){
                    $prompt.remove()
                })
            }
            if($bg){
                $bg.fadeOut('fast', function(){
                    $bg.remove()
                })
            }
        }
        function _callback(){
            _hide()
            var response = null
            if($(this).hasClass('notifit_prompt_accept')){
                response = $(this).parents('.notifit_prompt').find('.notifit_prompt_input').val()
            }else if($(this).hasClass('notifit_prompt_cancel')){
                response = false
            }
            if(typeof settings.callback === 'function'){
                return settings.callback(response)
            }
            return response
        }
        function _setListeners(){
            $('html').one('click', '.notifit_prompt_accept, .notifit_prompt_cancel', _callback)
        }

        // Get the party started! Again! \o/
        _create()
        _show()
        _setListeners()
    }

    return {
        notif: notif,
        notif_confirm: notif_confirm,
        notif_prompt: notif_prompt
    };
}));


text:
package org.jkiss.dbeaver.tools.transfer.database;

import org.jkiss.dbeaver.model.DBPImage;
import org.jkiss.dbeaver.model.DBPNamedObject;
import org.jkiss.dbeaver.model.struct.DBSObject;

/**
* DatabaseMappingContainer
*/
public interface DatabaseMappingObject {

    DBPImage getIcon();

    DBPNamedObject getSource();

    DBSObject getTarget();

    String getTargetName();

    DatabaseMappingType getMappingType();

}


text:
from selenium.common import exceptions

from lib import base
from lib.constants import url
from lib.constants import locator
from lib import environment
from lib import decorator
from lib.page import widget_bar
from lib.page import lhn

class UserList(base.Component):
  locators = locator.PageHeader

  def __init__(self, driver):
    super(UserList, self).__init__(driver)
    self.button_my_work = base.Button(self._driver,
                                      self.locators.BUTTON_MY_WORK)
    self.button_admin_dashboard = base.Button(
        self._driver, self.locators.BUTTON_ADMIN_DASHBOARD)
    self.button_data_import = base.Button(
        self._driver, self.locators.BUTTON_DATA_IMPORT)
    self.button_data_export = base.Button(
        self._driver, self.locators.BUTTON_DATA_EXPORT)
    self.button_logout = base.Button(
        self._driver, self.locators.BUTTON_LOGOUT)
    self.notifications = base.Label(
        self._driver, self.locators.NOTIFICATIONS)
    self.checkbox_daily_digest = base.Checkbox(
        self._driver, self.locators.CHECKBOX_DAILY_DIGEST)

  def select_my_work(self):
    """
    Returns:
        widget.DataAssets
    """
    self.button_my_work.click()
    return Dashboard(self._driver)

  def select_admin_dashboard(self):
    """
    Returns:
        admin_dashboard.AdminDashboard
    """
    self.button_my_work.click()
    return AdminDashboard(self._driver)

  def select_import_data(self):
    raise NotImplementedError

  def select_export_data(self):
    raise NotImplementedError

  @decorator.wait_for_redirect
  def select_logout(self):
    raise NotImplementedError

  def check_daily_email_digest(self):
    """Checks the daily checkbox"""
    self.checkbox_daily_digest.check()

  def uncheck_daily_email_digest(self):
    """Unchecks the daily checkbox"""
    self.checkbox_daily_digest.uncheck()

class Header(base.Component):
  """Header of the page"""
  locators = locator.PageHeader

  def __init__(self, driver):
    super(Header, self).__init__(driver)
    self.toggle_lhn_menu = None
    self.button_dashboard = None
    self.button_search = None
    self.button_my_tasks = None
    self.button_all_objects = None
    self.toggle_user_dropdown = None
    self._refresh_elements()

  def _refresh_elements(self):
    self.button_dashboard = base.Button(self._driver,
                                        self.locators.BUTTON_DASHBOARD)
    self.button_search = base.Button(self._driver,
                                     self.locators.BUTTON_SEARCH)
    self.button_my_tasks = base.Button(self._driver,
                                       self.locators.BUTTON_MY_TASKS)
    self.button_all_objects = base.Button(
        self._driver, self.locators.BUTTON_ALL_OBJECTS)
    self.toggle_user_dropdown = base.Toggle(
        self._driver, self.locators.TOGGLE_USER_DROPDOWN)
    self.toggle_lhn_menu = base.Toggle(self._driver,
                                       self.locators.TOGGLE_LHN)

  def open_lhn_menu(self):
    """Opens LHN on the Dashboard.
    For some reason, after creating 2 objects via LHN (and clicking 2x on the
    LHN button), the third time the toggle_lhn_menu signals it's not a part of
    the DOM anymore. For this reason we're refreshing the elements.

    Returns:
        LhnMenu
    """
    try:
      self.toggle_lhn_menu.toggle()
      return lhn.Menu(self._driver)
    except exceptions.StaleElementReferenceException:
      self._refresh_elements()
      return self.open_lhn_menu()

  def close_lhn_menu(self):
    """Closes LHN on the Dashboard

    Returns:
        LhnMenu
    """
    try:
      self.toggle_lhn_menu.toggle(on=False)
    except exceptions.WebDriverException:
      self._refresh_elements()
      self.close_lhn_menu()

  def click_on_logo(self):
    """
    Returns:
        widget.DataAssets
    """
    raise NotImplementedError

  def open_user_list(self):
    """
    Returns:
        UserList
    """
    self.toggle_user_dropdown.click()
    return UserList(self._driver)

class Dashboard(widget_bar.Dashboard, Header):
  """The main dashboard page"""
  URL = environment.APP_URL + url.DASHBOARD

  def __init__(self, driver):
    super(Dashboard, self).__init__(driver)
    self.button_help = base.Button(self._driver, self.locators.BUTTON_HELP)

class AdminDashboard(widget_bar.AdminDashboard,
                     Header):
  """Admin dashboard page model"""
  URL = environment.APP_URL + url.ADMIN_DASHBOARD

  def __init__(self, driver):
    super(AdminDashboard, self).__init__(driver)


text:
@echo off
set PATH=%Path%;%WINDIR%\Microsoft.NET\Framework\v2.0.50727
if not "%1"=="/u" (
	regasm /codebase Sagem.MorphoKit.dll
	regasm /codebase Sagem.ImageLibrary.dll
	regasm /codebase Sagem.MorphoKit.AcquisitionComponent.dll
	regasm /codebase ActiveMKit_Enroll.dll
	regasm /codebase Morpho.MorphoKit_FVP.dll
	regasm /codebase Morpho.MorphoAcquisition.dll
) else (
	regasm /unregister Morpho.MorphoAcquisition.dll
	regasm /unregister Morpho.MorphoKit_FVP.dll
	regasm /unregister ActiveMKit_Enroll.dll
	regasm /unregister Sagem.MorphoKit.AcquisitionComponent.dll
	regasm /unregister Sagem.ImageLibrary.dll
	regasm /unregister Sagem.MorphoKit.dll
)
pause


text:
#ifndef _ES3FINTERNALFORMATQUERYTESTS_HPP
#define _ES3FINTERNALFORMATQUERYTESTS_HPP
/*!
 * \file
 * \brief Internal Format Query tests.
 *//*--------------------------------------------------------------------*/

#include "tcuDefs.hpp"
#include "tes3TestCase.hpp"

namespace deqp
{
namespace gles3
{
namespace Functional
{

class InternalFormatQueryTests : public TestCaseGroup
{
public:
									InternalFormatQueryTests	(Context& context);

	void							init						(void);

private:
									InternalFormatQueryTests	(const InternalFormatQueryTests& other);
	InternalFormatQueryTests&		operator=					(const InternalFormatQueryTests& other);
};

} // Functional
} // gles3
} // deqp

#endif // _ES3FINTERNALFORMATQUERYTESTS_HPP


text:
using System;
using System.Collections.Generic;
using System.Reflection;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Services.Connectors;

using OpenMetaverse;
using log4net;
using Mono.Addins;
using Nini.Config;

namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MuteList
{
    [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteMuteListServicesConnector")]
    public class RemoteMuteListServicesConnector : ISharedRegionModule, IMuteListService
    {
        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        #region ISharedRegionModule

        private bool m_Enabled = false;

        private IMuteListService m_remoteConnector;

        public Type ReplaceableInterface
        {
            get { return null; }
        }

        public string Name
        {
            get { return "RemoteMuteListServicesConnector"; }
        }

        public void Initialise(IConfigSource source)
        {
           // only active for core mute lists module
            IConfig moduleConfig = source.Configs["Messaging"];
            if (moduleConfig == null)
                return;

            if (moduleConfig.GetString("MuteListModule", "None") != "MuteListModule")
                return;

            moduleConfig = source.Configs["Modules"];
            if (moduleConfig != null)
            {
                string name = moduleConfig.GetString("MuteListService", "");
                if (name == Name)
                {
                    m_remoteConnector = new MuteListServicesConnector(source);
                    m_Enabled = true;
                }
            }
        }

        public void PostInitialise()
        {
        }

        public void Close()
        {
        }

        public void AddRegion(Scene scene)
        {
            if (!m_Enabled)
                return;

            scene.RegisterModuleInterface<IMuteListService>(this);
            m_log.InfoFormat("[MUTELIST CONNECTOR]: Enabled for region {0}", scene.RegionInfo.RegionName);
        }

        public void RemoveRegion(Scene scene)
        {
            if (!m_Enabled)
                return;
        }

        public void RegionLoaded(Scene scene)
        {
            if (!m_Enabled)
                return;
        }

        #endregion

        #region IMuteListService
        public Byte[] MuteListRequest(UUID agentID, uint crc)
        {
            if (!m_Enabled)
                return null;
            return m_remoteConnector.MuteListRequest(agentID, crc);
        }

        public bool UpdateMute(MuteData mute)
        {
            if (!m_Enabled)
                return false;
            return m_remoteConnector.UpdateMute(mute);
        }

        public bool RemoveMute(UUID agentID, UUID muteID, string muteName)
        {
            if (!m_Enabled)
                return false;
            return m_remoteConnector.RemoveMute(agentID, muteID, muteName);
        }

        #endregion IMuteListService

    }
}


text:
"""Token provider interface."""

import datetime
import sys

from oslo_log import log
from oslo_utils import timeutils
import six

from keystone.common import cache
from keystone.common import dependency
from keystone.common import manager
import keystone.conf
from keystone import exception
from keystone.i18n import _
from keystone.models import token_model
from keystone import notifications
from keystone.token import persistence

CONF = keystone.conf.CONF
LOG = log.getLogger(__name__)

TOKENS_REGION = cache.create_region(name='tokens')
MEMOIZE_TOKENS = cache.get_memoization_decorator(
    group='token',
    region=TOKENS_REGION)

# NOTE(morganfainberg): This is for compatibility in case someone was relying
# on the old location of the UnsupportedTokenVersionException for their code.
UnsupportedTokenVersionException = exception.UnsupportedTokenVersionException

# supported token versions
V2 = token_model.V2
V3 = token_model.V3
VERSIONS = token_model.VERSIONS

@dependency.provider('token_provider_api')
@dependency.requires('assignment_api', 'revoke_api')
class Manager(manager.Manager):
    """Default pivot point for the token provider backend.

    See :mod:`keystone.common.manager.Manager` for more details on how this
    dynamically calls the backend.

    """

    driver_namespace = 'keystone.token.provider'

    V2 = V2
    V3 = V3
    VERSIONS = VERSIONS
    INVALIDATE_PROJECT_TOKEN_PERSISTENCE = 'invalidate_project_tokens'
    INVALIDATE_USER_TOKEN_PERSISTENCE = 'invalidate_user_tokens'
    _persistence_manager = None

    def __init__(self):
        super(Manager, self).__init__(CONF.token.provider)
        self._register_callback_listeners()

    def _register_callback_listeners(self):
        # This is used by the @dependency.provider decorator to register the
        # provider (token_provider_api) manager to listen for trust deletions.
        callbacks = {
            notifications.ACTIONS.deleted: [
                ['OS-TRUST:trust', self._trust_deleted_event_callback],
                ['user', self._delete_user_tokens_callback],
                ['domain', self._delete_domain_tokens_callback],
            ],
            notifications.ACTIONS.disabled: [
                ['user', self._delete_user_tokens_callback],
                ['domain', self._delete_domain_tokens_callback],
                ['project', self._delete_project_tokens_callback],
            ],
            notifications.ACTIONS.internal: [
                [notifications.INVALIDATE_USER_TOKEN_PERSISTENCE,
                    self._delete_user_tokens_callback],
                [notifications.INVALIDATE_USER_PROJECT_TOKEN_PERSISTENCE,
                    self._delete_user_project_tokens_callback],
                [notifications.INVALIDATE_USER_OAUTH_CONSUMER_TOKENS,
                    self._delete_user_oauth_consumer_tokens_callback],
            ]
        }

        for event, cb_info in callbacks.items():
            for resource_type, callback_fns in cb_info:
                notifications.register_event_callback(event, resource_type,
                                                      callback_fns)

    @property
    def _needs_persistence(self):
        return self.driver.needs_persistence()

    @property
    def _persistence(self):
        # NOTE(morganfainberg): This should not be handled via __init__ to
        # avoid dependency injection oddities circular dependencies (where
        # the provider manager requires the token persistence manager, which
        # requires the token provider manager).
        if self._persistence_manager is None:
            self._persistence_manager = persistence.PersistenceManager()
        return self._persistence_manager

    def _create_token(self, token_id, token_data):
        try:
            if isinstance(token_data['expires'], six.string_types):
                token_data['expires'] = timeutils.normalize_time(
                    timeutils.parse_isotime(token_data['expires']))
            self._persistence.create_token(token_id, token_data)
        except Exception:
            exc_info = sys.exc_info()
            # an identical token may have been created already.
            # if so, return the token_data as it is also identical
            try:
                self._persistence.get_token(token_id)
            except exception.TokenNotFound:
                six.reraise(*exc_info)

    def check_revocation_v2(self, token):
        try:
            token_data = token['access']
        except KeyError:
            raise exception.TokenNotFound(_('Failed to validate token'))

        token_values = self.revoke_api.model.build_token_values_v2(
            token_data, CONF.identity.default_domain_id)
        self.revoke_api.check_token(token_values)

    def check_revocation_v3(self, token):
        try:
            token_data = token['token']
        except KeyError:
            raise exception.TokenNotFound(_('Failed to validate token'))
        token_values = self.revoke_api.model.build_token_values(token_data)
        self.revoke_api.check_token(token_values)

    def check_revocation(self, token):
        version = self.get_token_version(token)
        if version == V2:
            return self.check_revocation_v2(token)
        else:
            return self.check_revocation_v3(token)

    def validate_token(self, token_id, window_seconds=0):
        if not token_id:
            raise exception.TokenNotFound(_('No token in the request'))

        try:
            # NOTE(lbragstad): Only go to persistent storage if we have a token
            # to fetch from the backend (the driver persists the token).
            # Otherwise the information about the token must be in the token
            # id.
            if self._needs_persistence:
                token_ref = self._persistence.get_token(token_id)
                # Overload the token_id variable to be a token reference
                # instead.
                token_id = token_ref
            token_ref = self._validate_token(token_id)
            self._is_valid_token(token_ref, window_seconds=window_seconds)
            return token_ref
        except exception.Unauthorized as e:
            LOG.debug('Unable to validate token: %s', e)
            raise exception.TokenNotFound(token_id=token_id)

    @MEMOIZE_TOKENS
    def _validate_token(self, token_id):
        return self.driver.validate_token(token_id)

    def _is_valid_token(self, token, window_seconds=0):
        """Verify the token is valid format and has not expired."""
        current_time = timeutils.normalize_time(timeutils.utcnow())

        try:
            # Get the data we need from the correct location (V2 and V3 tokens
            # differ in structure, Try V3 first, fall back to V2 second)
            token_data = token.get('token', token.get('access'))
            expires_at = token_data.get('expires_at',
                                        token_data.get('expires'))
            if not expires_at:
                expires_at = token_data['token']['expires']

            expiry = timeutils.parse_isotime(expires_at)
            expiry = timeutils.normalize_time(expiry)

            # add a window in which you can fetch a token beyond expiry
            expiry += datetime.timedelta(seconds=window_seconds)

        except Exception:
            LOG.exception('Unexpected error or malformed token '
                          'determining token expiry: %s', token)
            raise exception.TokenNotFound(_('Failed to validate token'))

        if current_time < expiry:
            self.check_revocation(token)
            # Token has not expired and has not been revoked.
            return None
        else:
            raise exception.TokenNotFound(_('Failed to validate token'))

    def issue_token(self, user_id, method_names, expires_at=None,
                    project_id=None, is_domain=False, domain_id=None,
                    auth_context=None, trust=None, include_catalog=True,
                    parent_audit_id=None):
        token_id, token_data = self.driver.issue_token(
            user_id, method_names, expires_at, project_id, domain_id,
            auth_context, trust, include_catalog, parent_audit_id)

        data = dict(key=token_id,
                    id=token_id,
                    expires=token_data['token']['expires_at'],
                    user=token_data['token']['user'],
                    tenant=token_data['token'].get('project'),
                    is_domain=is_domain,
                    token_data=token_data,
                    trust_id=trust['id'] if trust else None,
                    token_version=self.V3)
        if self._needs_persistence:
            self._create_token(token_id, data)

        if CONF.token.cache_on_issue:
            # NOTE(amakarov): here and above TOKENS_REGION is to be passed
            # to serve as required positional "self" argument. It's ignored,
            # so I've put it here for convenience - any placeholder is fine.
            self._validate_token.set(token_data, TOKENS_REGION, token_id)

        return token_id, token_data

    def invalidate_individual_token_cache(self, token_id):
        # NOTE(morganfainberg): invalidate takes the exact same arguments as
        # the normal method, this means we need to pass "self" in (which gets
        # stripped off).

        # FIXME(morganfainberg): Does this cache actually need to be
        # invalidated? We maintain a cached revocation list, which should be
        # consulted before accepting a token as valid.  For now we will
        # do the explicit individual token invalidation.

        self._validate_token.invalidate(self, token_id)

    def revoke_token(self, token_id, revoke_chain=False):
        token_ref = token_model.KeystoneToken(
            token_id=token_id,
            token_data=self.validate_token(token_id))

        project_id = token_ref.project_id if token_ref.project_scoped else None
        domain_id = token_ref.domain_id if token_ref.domain_scoped else None

        if revoke_chain:
            self.revoke_api.revoke_by_audit_chain_id(token_ref.audit_chain_id,
                                                     project_id=project_id,
                                                     domain_id=domain_id)
        else:
            self.revoke_api.revoke_by_audit_id(token_ref.audit_id)

        if CONF.token.revoke_by_id and self._needs_persistence:
            self._persistence.delete_token(token_id=token_id)

        # FIXME(morganfainberg): Does this cache actually need to be
        # invalidated? We maintain a cached revocation list, which should be
        # consulted before accepting a token as valid.  For now we will
        # do the explicit individual token invalidation.
        self.invalidate_individual_token_cache(token_id)

    def list_revoked_tokens(self):
        return self._persistence.list_revoked_tokens()

    def _trust_deleted_event_callback(self, service, resource_type, operation,
                                      payload):
        if CONF.token.revoke_by_id:
            trust_id = payload['resource_info']
            trust = self.trust_api.get_trust(trust_id, deleted=True)
            self._persistence.delete_tokens(user_id=trust['trustor_user_id'],
                                            trust_id=trust_id)
        if CONF.token.cache_on_issue:
            # NOTE(amakarov): preserving behavior
            TOKENS_REGION.invalidate()

    def _delete_user_tokens_callback(self, service, resource_type, operation,
                                     payload):
        if CONF.token.revoke_by_id:
            user_id = payload['resource_info']
            self._persistence.delete_tokens_for_user(user_id)
        if CONF.token.cache_on_issue:
            # NOTE(amakarov): preserving behavior
            TOKENS_REGION.invalidate()

    def _delete_domain_tokens_callback(self, service, resource_type,
                                       operation, payload):
        if CONF.token.revoke_by_id:
            domain_id = payload['resource_info']
            self._persistence.delete_tokens_for_domain(domain_id=domain_id)
        if CONF.token.cache_on_issue:
            # NOTE(amakarov): preserving behavior
            TOKENS_REGION.invalidate()

    def _delete_user_project_tokens_callback(self, service, resource_type,
                                             operation, payload):
        if CONF.token.revoke_by_id:
            user_id = payload['resource_info']['user_id']
            project_id = payload['resource_info']['project_id']
            self._persistence.delete_tokens_for_user(user_id=user_id,
                                                     project_id=project_id)
        if CONF.token.cache_on_issue:
            # NOTE(amakarov): preserving behavior
            TOKENS_REGION.invalidate()

    def _delete_project_tokens_callback(self, service, resource_type,
                                        operation, payload):
        if CONF.token.revoke_by_id:
            project_id = payload['resource_info']
            self._persistence.delete_tokens_for_users(
                self.assignment_api.list_user_ids_for_project(project_id),
                project_id=project_id)
        if CONF.token.cache_on_issue:
            # NOTE(amakarov): preserving behavior
            TOKENS_REGION.invalidate()

    def _delete_user_oauth_consumer_tokens_callback(self, service,
                                                    resource_type, operation,
                                                    payload):
        if CONF.token.revoke_by_id:
            user_id = payload['resource_info']['user_id']
            consumer_id = payload['resource_info']['consumer_id']
            self._persistence.delete_tokens(user_id=user_id,
                                            consumer_id=consumer_id)
        if CONF.token.cache_on_issue:
            # NOTE(amakarov): preserving behavior
            TOKENS_REGION.invalidate()


text:
package dk.teachus.frontend.components.form;

import org.apache.wicket.markup.html.panel.Panel;

public abstract class FormElement extends Panel {
	private static final long serialVersionUID = 1L;

	public FormElement() {
		super(FormPanel.ELEMENT_ID);
	}

}


text:
#include <iostream>
#include <string.h>

extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#include <luasocket.h>
#include <oilbit.h>
}

#ifndef TOLUA_API
#define TOLUA_API
#endif

#include "hello.hpp"
#include "bind.hpp"

////////////////////////////////////////////////////////////////////////////////

static bool callfield(lua_State *L, const char *name, int narg, int nres);
static void pushfield(lua_State *L, const char *name);

lua_State *newstate()
{
	lua_State *L = lua_open();

	luaL_openlibs(L);
	luaopen_socket_core(L);
#ifndef PRELOAD
	luaopen_oil_bit(L);   // open the OiL bit library (only OiL C library)
#else
	luapreload_oilall(L); // preload all OiL libraries
#endif

	return L;
}

int main(int argc, char* argv[])
{
	Hello::HelloWorld *hello = new Hello::HelloWorld(true);

	lua_State *L = newstate();

	// require "oil"
	lua_pushliteral(L, "oil");
	callfield(L, "require", 1, 0);

	// oil.loadidl("interface Hello { ... }")
	lua_pushliteral(L,
		"interface Hello {"
		"  attribute boolean quiet;"
		"  readonly attribute long count;"
		"  string say_hello_to(in string name);"
		"};");
	callfield(L, "oil.loadidl", 1, 0);

	// oil.writeto('...ref', oil.tostring(oil.newservant(<hello>, "::Hello")))
	lua_pushliteral(L, "../hello/hello.ref");
	tolua_pushusertype(L, (void*)hello, "Hello::HelloWorld");
	lua_pushliteral(L, "::Hello");
	callfield(L, "oil.newservant", 2, 1);
	callfield(L, "oil.tostring", 1, 1);
	callfield(L, "oil.writeto", 2, 0);

	// oil.main(oil.run())
	pushfield(L, "oil.run");
	callfield(L, "oil.main", 1, 0);

	return 0;
}

////////////////////////////////////////////////////////////////////////////////

static void pushfield(lua_State *L, const char *name)
{
	const char *end = strchr(name, '.');
	lua_pushvalue(L, LUA_GLOBALSINDEX);
	while (end) {
		lua_pushlstring(L, name, end - name);
		lua_gettable(L, -2);
		lua_remove(L, -2);
		if (lua_isnil(L, -1)) return;
		name = end+1;
		end = strchr(name, '.');
	}
	lua_pushstring(L, name);
	lua_gettable(L, -2);
	lua_remove(L, -2);
}

static int traceback (lua_State *L) {
	lua_getfield(L, LUA_GLOBALSINDEX, "debug");
	if (!lua_istable(L, -1)) {
		lua_pop(L, 1);
		return 1;
	}
	lua_getfield(L, -1, "traceback");
	if (!lua_isfunction(L, -1)) {
		lua_pop(L, 2);
		return 1;
	}
	lua_pushvalue(L, 1);  /* pass error message */
	lua_pushinteger(L, 2);  /* skip this function and traceback */
	lua_call(L, 2, 1);  /* call debug.traceback */
	return 1;
}

static bool callfield(lua_State *L, const char *name, int narg, int nres)
{
	pushfield(L, name);
	int base = lua_gettop(L) - narg;  /* 1st arg index */
	lua_insert(L, base);  /* put function under args */
	lua_pushcfunction(L, traceback);  /* push traceback function */
	lua_insert(L, base);  /* put traceback under function and args */
	int status = lua_pcall(L, narg, nres, base);
	lua_remove(L, base);  /* remove traceback function */
	if (status && !lua_isnil(L, -1)) {
		const char *msg;
		if (lua_istable(L, -1)) {
			lua_getfield(L, LUA_GLOBALSINDEX, "tostring");
			lua_insert(L, -2);
			lua_call(L, 1, 1);
		}
		msg = lua_tostring(L, -1);
		if (msg == NULL) msg = "(error object is not a string)";
		fprintf(stderr, "%s\n", msg);
		lua_pop(L, 1);
		return false;
	}
	return true;
}


text:
For a DB instance that has been bound with an EIP, you can access it through the EIP.

## DB Instance Not Bound with an EIP

-   Enable a VPN in a VPC and use the VPN to connect to the RDS DB instance.
-   Create an RDS and an ECS in the same VPC and access RDS through the ECS.