text:
package org.apache.orc.impl;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.BytesWritable;
import org.apache.orc.EncryptionAlgorithm;
import org.apache.orc.InMemoryKeystore;
import org.apache.orc.OrcConf;
import org.apache.orc.OrcProto;
import org.apache.orc.impl.reader.ReaderEncryptionVariant;
import org.junit.Test;

import java.io.IOException;
import java.security.Key;
import java.util.List;
import java.util.Random;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

public class TestCryptoUtils {

  @Test
  public void testCreateStreamIv() throws Exception {
    EncryptionAlgorithm aes128 = EncryptionAlgorithm.AES_CTR_128;
    byte[] iv = new byte[aes128.getIvLength()];
    CryptoUtils.modifyIvForStream(0x234567, OrcProto.Stream.Kind.BLOOM_FILTER_UTF8,
        0x123456).accept(iv);
    assertEquals(16, iv.length);
    assertEquals(0x23, iv[0]);
    assertEquals(0x45, iv[1]);
    assertEquals(0x67, iv[2]);
    assertEquals(0x0, iv[3]);
    assertEquals(0x8, iv[4]);
    assertEquals(0x12, iv[5]);
    assertEquals(0x34, iv[6]);
    assertEquals(0x56, iv[7]);
  }

  @Test
  public void testMemoryKeyProvider() throws IOException {
    Configuration conf = new Configuration();
    OrcConf.KEY_PROVIDER.setString(conf, "memory");
    // Hard code the random so that we know the bytes that will come out.
    InMemoryKeystore provider =
        (InMemoryKeystore) CryptoUtils.getKeyProvider(conf, new Random(24));
    byte[] piiKey = new byte[]{0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf};
    provider.addKey("pii", EncryptionAlgorithm.AES_CTR_128, piiKey);
    byte[] piiKey2 = new byte[]{0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
        0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f};
    provider.addKey("pii", 1, EncryptionAlgorithm.AES_CTR_128, piiKey2);
    byte[] secretKey = new byte[]{0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
        0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f};
    provider.addKey("secret", EncryptionAlgorithm.AES_CTR_128, secretKey);

    List<String> keyNames = provider.getKeyNames();
    assertEquals(2, keyNames.size());
    assertEquals(true, keyNames.contains("pii"));
    assertEquals(true, keyNames.contains("secret"));
    HadoopShims.KeyMetadata meta = provider.getCurrentKeyVersion("pii");
    assertEquals(1, meta.getVersion());
    LocalKey localKey = provider.createLocalKey(meta);
    byte[] encrypted = localKey.getEncryptedKey();
    // make sure that we get exactly what we expect to test the encryption
    assertEquals("c7 ab 4f bb 38 f4 de ad d0 b3 59 e2 21 2a 95 32",
        new BytesWritable(encrypted).toString());
    // now check to make sure that we get the expected bytes back
    assertEquals("c7 a1 d0 41 7b 24 72 44 1a 58 c7 72 4a d4 be b3",
        new BytesWritable(localKey.getDecryptedKey().getEncoded()).toString());
    Key key = provider.decryptLocalKey(meta, encrypted);
    assertEquals(new BytesWritable(localKey.getDecryptedKey().getEncoded()).toString(),
        new BytesWritable(key.getEncoded()).toString());
  }

  @Test
  public void testInvalidKeyProvider() throws IOException {
    Configuration conf = new Configuration();
    OrcConf.KEY_PROVIDER.setString(conf, "");
    assertNull(CryptoUtils.getKeyProvider(conf, new Random()));
  }
}


text:
describe('Default', () => {
  it('should render the default component correctly', () => {
    cy.visit('/iframe.html?id=badge--default')
    cy.get('#root').should('be.visible').compareSnapshot('default')
  })
})

describe('Custom border colour', () => {
  it('should render the custom border colour component correctly', () => {
    cy.visit('/iframe.html?id=badge--custom-border-colour')
    cy.get('#root').should('be.visible').compareSnapshot('custom-border-colour')
  })
})

describe('Custom text colour', () => {
  it('should render the custom text colour component correctly', () => {
    cy.visit('/iframe.html?id=badge--custom-text-colour')
    cy.get('#root').should('be.visible').compareSnapshot('custom-text-colour')
  })
})

describe('Custom font size', () => {
  it('should render the custom font size component correctly', () => {
    cy.visit('/iframe.html?id=badge--custom-font-size')
    cy.get('#root').should('be.visible').compareSnapshot('custom-font-size')
  })
})

describe('HTML content', () => {
  it('should render the HTML content component correctly', () => {
    cy.visit('/iframe.html?id=badge--html-content')
    cy.get('#root').should('be.visible').compareSnapshot('html-content')
  })
})

redpajama_set_name: RedPajamaGithub


text:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "SDL_test_common.h"

#if defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__)

int main(int argc, char *argv[])
{
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Vulkan support on this system\n");
    return 1;
}

#else

#define VK_NO_PROTOTYPES
#ifdef HAVE_VULKAN_H
#include <vulkan/vulkan.h>
#else
/* SDL includes a copy for building on systems without the Vulkan SDK */
#include "../src/video/khronos/vulkan/vulkan.h"
#endif
#include "SDL_vulkan.h"

#ifndef UINT64_MAX /* VS2008 */
#define UINT64_MAX 18446744073709551615
#endif

#define VULKAN_FUNCTIONS()                                              \
    VULKAN_DEVICE_FUNCTION(vkAcquireNextImageKHR)                       \
    VULKAN_DEVICE_FUNCTION(vkAllocateCommandBuffers)                    \
    VULKAN_DEVICE_FUNCTION(vkBeginCommandBuffer)                        \
    VULKAN_DEVICE_FUNCTION(vkCmdClearColorImage)                        \
    VULKAN_DEVICE_FUNCTION(vkCmdPipelineBarrier)                        \
    VULKAN_DEVICE_FUNCTION(vkCreateCommandPool)                         \
    VULKAN_DEVICE_FUNCTION(vkCreateFence)                               \
    VULKAN_DEVICE_FUNCTION(vkCreateImageView)                           \
    VULKAN_DEVICE_FUNCTION(vkCreateSemaphore)                           \
    VULKAN_DEVICE_FUNCTION(vkCreateSwapchainKHR)                        \
    VULKAN_DEVICE_FUNCTION(vkDestroyCommandPool)                        \
    VULKAN_DEVICE_FUNCTION(vkDestroyDevice)                             \
    VULKAN_DEVICE_FUNCTION(vkDestroyFence)                              \
    VULKAN_DEVICE_FUNCTION(vkDestroyImageView)                          \
    VULKAN_DEVICE_FUNCTION(vkDestroySemaphore)                          \
    VULKAN_DEVICE_FUNCTION(vkDestroySwapchainKHR)                       \
    VULKAN_DEVICE_FUNCTION(vkDeviceWaitIdle)                            \
    VULKAN_DEVICE_FUNCTION(vkEndCommandBuffer)                          \
    VULKAN_DEVICE_FUNCTION(vkFreeCommandBuffers)                        \
    VULKAN_DEVICE_FUNCTION(vkGetDeviceQueue)                            \
    VULKAN_DEVICE_FUNCTION(vkGetFenceStatus)                            \
    VULKAN_DEVICE_FUNCTION(vkGetSwapchainImagesKHR)                     \
    VULKAN_DEVICE_FUNCTION(vkQueuePresentKHR)                           \
    VULKAN_DEVICE_FUNCTION(vkQueueSubmit)                               \
    VULKAN_DEVICE_FUNCTION(vkResetCommandBuffer)                        \
    VULKAN_DEVICE_FUNCTION(vkResetFences)                               \
    VULKAN_DEVICE_FUNCTION(vkWaitForFences)                             \
    VULKAN_GLOBAL_FUNCTION(vkCreateInstance)                            \
    VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceExtensionProperties)      \
    VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceLayerProperties)          \
    VULKAN_INSTANCE_FUNCTION(vkCreateDevice)                            \
    VULKAN_INSTANCE_FUNCTION(vkDestroyInstance)                         \
    VULKAN_INSTANCE_FUNCTION(vkDestroySurfaceKHR)                       \
    VULKAN_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties)      \
    VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices)                \
    VULKAN_INSTANCE_FUNCTION(vkGetDeviceProcAddr)                       \
    VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures)               \
    VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties)             \
    VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties)  \
    VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
    VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR)      \
    VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR) \
    VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR)

#define VULKAN_DEVICE_FUNCTION(name) static PFN_##name name = NULL;
#define VULKAN_GLOBAL_FUNCTION(name) static PFN_##name name = NULL;
#define VULKAN_INSTANCE_FUNCTION(name) static PFN_##name name = NULL;
VULKAN_FUNCTIONS()
#undef VULKAN_DEVICE_FUNCTION
#undef VULKAN_GLOBAL_FUNCTION
#undef VULKAN_INSTANCE_FUNCTION
static PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;

/* Based on the headers found in
 * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers
 */
#if VK_HEADER_VERSION < 22
enum
{
    VK_ERROR_FRAGMENTED_POOL = -12,
};
#endif
#if VK_HEADER_VERSION < 38
enum {
    VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000
};
#endif

static const char *getVulkanResultString(VkResult result)
{
    switch((int) result)
    {
        #define RESULT_CASE(x) case x: return #x
        RESULT_CASE(VK_SUCCESS);
        RESULT_CASE(VK_NOT_READY);
        RESULT_CASE(VK_TIMEOUT);
        RESULT_CASE(VK_EVENT_SET);
        RESULT_CASE(VK_EVENT_RESET);
        RESULT_CASE(VK_INCOMPLETE);
        RESULT_CASE(VK_ERROR_OUT_OF_HOST_MEMORY);
        RESULT_CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY);
        RESULT_CASE(VK_ERROR_INITIALIZATION_FAILED);
        RESULT_CASE(VK_ERROR_DEVICE_LOST);
        RESULT_CASE(VK_ERROR_MEMORY_MAP_FAILED);
        RESULT_CASE(VK_ERROR_LAYER_NOT_PRESENT);
        RESULT_CASE(VK_ERROR_EXTENSION_NOT_PRESENT);
        RESULT_CASE(VK_ERROR_FEATURE_NOT_PRESENT);
        RESULT_CASE(VK_ERROR_INCOMPATIBLE_DRIVER);
        RESULT_CASE(VK_ERROR_TOO_MANY_OBJECTS);
        RESULT_CASE(VK_ERROR_FORMAT_NOT_SUPPORTED);
        RESULT_CASE(VK_ERROR_FRAGMENTED_POOL);
        RESULT_CASE(VK_ERROR_SURFACE_LOST_KHR);
        RESULT_CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
        RESULT_CASE(VK_SUBOPTIMAL_KHR);
        RESULT_CASE(VK_ERROR_OUT_OF_DATE_KHR);
        RESULT_CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
        RESULT_CASE(VK_ERROR_VALIDATION_FAILED_EXT);
        RESULT_CASE(VK_ERROR_OUT_OF_POOL_MEMORY_KHR);
        RESULT_CASE(VK_ERROR_INVALID_SHADER_NV);
        #undef RESULT_CASE
        default: break;
    }
    return (result < 0) ? "VK_ERROR_<Unknown>" : "VK_<Unknown>";
}

typedef struct VulkanContext
{
    SDL_Window *window;
    VkInstance instance;
    VkDevice device;
    VkSurfaceKHR surface;
    VkSwapchainKHR swapchain;
    VkPhysicalDeviceProperties physicalDeviceProperties;
    VkPhysicalDeviceFeatures physicalDeviceFeatures;
    uint32_t graphicsQueueFamilyIndex;
    uint32_t presentQueueFamilyIndex;
    VkPhysicalDevice physicalDevice;
    VkQueue graphicsQueue;
    VkQueue presentQueue;
    VkSemaphore imageAvailableSemaphore;
    VkSemaphore renderingFinishedSemaphore;
    VkSurfaceCapabilitiesKHR surfaceCapabilities;
    VkSurfaceFormatKHR *surfaceFormats;
    uint32_t surfaceFormatsAllocatedCount;
    uint32_t surfaceFormatsCount;
    uint32_t swapchainDesiredImageCount;
    VkSurfaceFormatKHR surfaceFormat;
    VkExtent2D swapchainSize;
    VkCommandPool commandPool;
    uint32_t swapchainImageCount;
    VkImage *swapchainImages;
    VkCommandBuffer *commandBuffers;
    VkFence *fences;
} VulkanContext;

static SDLTest_CommonState *state;
static VulkanContext *vulkanContexts = NULL;  // an array of state->num_windows items
static VulkanContext *vulkanContext = NULL;  // for the currently-rendering window

static void shutdownVulkan(SDL_bool doDestroySwapchain);

/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
static void quit(int rc)
{
    shutdownVulkan(SDL_TRUE);
    SDLTest_CommonQuit(state);
    exit(rc);
}

static void loadGlobalFunctions(void)
{
    vkGetInstanceProcAddr = SDL_Vulkan_GetVkGetInstanceProcAddr();
    if (!vkGetInstanceProcAddr) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s\n",
                     SDL_GetError());
        quit(2);
    }

#define VULKAN_DEVICE_FUNCTION(name)
#define VULKAN_GLOBAL_FUNCTION(name)                                                   \
    name = (PFN_##name)vkGetInstanceProcAddr(VK_NULL_HANDLE, #name);                   \
    if (!name) {                                                                       \
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,                                     \
                     "vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed\n"); \
        quit(2);                                                                       \
    }
#define VULKAN_INSTANCE_FUNCTION(name)
    VULKAN_FUNCTIONS()
#undef VULKAN_DEVICE_FUNCTION
#undef VULKAN_GLOBAL_FUNCTION
#undef VULKAN_INSTANCE_FUNCTION
}

static void createInstance(void)
{
    VkApplicationInfo appInfo = {0};
    VkInstanceCreateInfo instanceCreateInfo = {0};
    const char **extensions = NULL;
    unsigned extensionCount = 0;
    VkResult result;

    appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
    appInfo.apiVersion = VK_API_VERSION_1_0;
    instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    instanceCreateInfo.pApplicationInfo = &appInfo;
    if (!SDL_Vulkan_GetInstanceExtensions(NULL, &extensionCount, NULL)) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "SDL_Vulkan_GetInstanceExtensions(): %s\n",
                     SDL_GetError());
        quit(2);
    }
    extensions = (const char **) SDL_malloc(sizeof(const char *) * extensionCount);
    if (!extensions) {
        SDL_OutOfMemory();
        quit(2);
    }
    if (!SDL_Vulkan_GetInstanceExtensions(NULL, &extensionCount, extensions)) {
        SDL_free((void*)extensions);
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "SDL_Vulkan_GetInstanceExtensions(): %s\n",
                     SDL_GetError());
        quit(2);
    }
    instanceCreateInfo.enabledExtensionCount = extensionCount;
    instanceCreateInfo.ppEnabledExtensionNames = extensions;
    result = vkCreateInstance(&instanceCreateInfo, NULL, &vulkanContext->instance);
    SDL_free((void*)extensions);
    if (result != VK_SUCCESS) {
        vulkanContext->instance = VK_NULL_HANDLE;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkCreateInstance(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
}

static void loadInstanceFunctions(void)
{
#define VULKAN_DEVICE_FUNCTION(name)
#define VULKAN_GLOBAL_FUNCTION(name)
#define VULKAN_INSTANCE_FUNCTION(name)                                           \
    name = (PFN_##name)vkGetInstanceProcAddr(vulkanContext->instance, #name);    \
    if (!name) {                                                                 \
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,                               \
                     "vkGetInstanceProcAddr(instance, \"" #name "\") failed\n"); \
        quit(2);                                                                 \
    }
    VULKAN_FUNCTIONS()
#undef VULKAN_DEVICE_FUNCTION
#undef VULKAN_GLOBAL_FUNCTION
#undef VULKAN_INSTANCE_FUNCTION
}

static void createSurface(void)
{
    if (!SDL_Vulkan_CreateSurface(vulkanContext->window,
                                 vulkanContext->instance,
                                 &vulkanContext->surface)) {
        vulkanContext->surface = VK_NULL_HANDLE;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Vulkan_CreateSurface(): %s\n", SDL_GetError());
        quit(2);
    }
}

static void findPhysicalDevice(void)
{
    uint32_t physicalDeviceCount = 0;
    VkPhysicalDevice *physicalDevices;
    VkQueueFamilyProperties *queueFamiliesProperties = NULL;
    uint32_t queueFamiliesPropertiesAllocatedSize = 0;
    VkExtensionProperties *deviceExtensions = NULL;
    uint32_t deviceExtensionsAllocatedSize = 0;
    uint32_t physicalDeviceIndex;
    VkResult result;

    result = vkEnumeratePhysicalDevices(vulkanContext->instance, &physicalDeviceCount, NULL);
    if (result != VK_SUCCESS) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkEnumeratePhysicalDevices(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
    if (physicalDeviceCount == 0) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkEnumeratePhysicalDevices(): no physical devices\n");
        quit(2);
    }
    physicalDevices = (VkPhysicalDevice *) SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
    if (!physicalDevices) {
        SDL_OutOfMemory();
        quit(2);
    }
    result = vkEnumeratePhysicalDevices(vulkanContext->instance, &physicalDeviceCount, physicalDevices);
    if (result != VK_SUCCESS) {
        SDL_free(physicalDevices);
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkEnumeratePhysicalDevices(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
    vulkanContext->physicalDevice = NULL;
    for (physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; physicalDeviceIndex++) {
        uint32_t queueFamiliesCount = 0;
        uint32_t queueFamilyIndex;
        uint32_t deviceExtensionCount = 0;
        SDL_bool hasSwapchainExtension = SDL_FALSE;
        uint32_t i;

        VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex];
        vkGetPhysicalDeviceProperties(physicalDevice, &vulkanContext->physicalDeviceProperties);
        if(VK_VERSION_MAJOR(vulkanContext->physicalDeviceProperties.apiVersion) < 1) {
            continue;
        }
        vkGetPhysicalDeviceFeatures(physicalDevice, &vulkanContext->physicalDeviceFeatures);
        vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, NULL);
        if (queueFamiliesCount == 0) {
            continue;
        }
        if (queueFamiliesPropertiesAllocatedSize < queueFamiliesCount) {
            SDL_free(queueFamiliesProperties);
            queueFamiliesPropertiesAllocatedSize = queueFamiliesCount;
            queueFamiliesProperties = (VkQueueFamilyProperties *) SDL_malloc(sizeof(VkQueueFamilyProperties) * queueFamiliesPropertiesAllocatedSize);
            if (!queueFamiliesProperties) {
                SDL_free(physicalDevices);
                SDL_free(deviceExtensions);
                SDL_OutOfMemory();
                quit(2);
            }
        }
        vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, queueFamiliesProperties);
        vulkanContext->graphicsQueueFamilyIndex = queueFamiliesCount;
        vulkanContext->presentQueueFamilyIndex = queueFamiliesCount;
        for (queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; queueFamilyIndex++) {
            VkBool32 supported = 0;

            if (queueFamiliesProperties[queueFamilyIndex].queueCount == 0) {
                continue;
            }

            if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
                vulkanContext->graphicsQueueFamilyIndex = queueFamilyIndex;
            }

            result = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, vulkanContext->surface, &supported);
            if (result != VK_SUCCESS) {
                SDL_free(physicalDevices);
                SDL_free(queueFamiliesProperties);
                SDL_free(deviceExtensions);
                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                             "vkGetPhysicalDeviceSurfaceSupportKHR(): %s\n",
                             getVulkanResultString(result));
                quit(2);
            }
            if (supported) {
                vulkanContext->presentQueueFamilyIndex = queueFamilyIndex;
                if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
                    break; // use this queue because it can present and do graphics
                }
            }
        }

        if (vulkanContext->graphicsQueueFamilyIndex == queueFamiliesCount) {  // no good queues found
            continue;
        }
        if (vulkanContext->presentQueueFamilyIndex == queueFamiliesCount) {  // no good queues found
            continue;
        }
        result = vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, NULL);
        if (result != VK_SUCCESS)
        {
            SDL_free(physicalDevices);
            SDL_free(queueFamiliesProperties);
            SDL_free(deviceExtensions);
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                         "vkEnumerateDeviceExtensionProperties(): %s\n",
                         getVulkanResultString(result));
            quit(2);
        }
        if (deviceExtensionCount == 0) {
            continue;
        }
        if (deviceExtensionsAllocatedSize < deviceExtensionCount) {
            SDL_free(deviceExtensions);
            deviceExtensionsAllocatedSize = deviceExtensionCount;
            deviceExtensions = SDL_malloc(sizeof(VkExtensionProperties) * deviceExtensionsAllocatedSize);
            if (!deviceExtensions) {
                SDL_free(physicalDevices);
                SDL_free(queueFamiliesProperties);
                SDL_OutOfMemory();
                quit(2);
            }
        }
        result = vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, deviceExtensions);
        if (result != VK_SUCCESS) {
            SDL_free(physicalDevices);
            SDL_free(queueFamiliesProperties);
            SDL_free(deviceExtensions);
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                         "vkEnumerateDeviceExtensionProperties(): %s\n",
                         getVulkanResultString(result));
            quit(2);
        }
        for (i = 0; i < deviceExtensionCount; i++) {
            if(SDL_strcmp(deviceExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
                hasSwapchainExtension = SDL_TRUE;
                break;
            }
        }
        if (!hasSwapchainExtension) {
            continue;
        }
        vulkanContext->physicalDevice = physicalDevice;
        break;
    }
    SDL_free(physicalDevices);
    SDL_free(queueFamiliesProperties);
    SDL_free(deviceExtensions);
    if (!vulkanContext->physicalDevice) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Vulkan: no viable physical devices found");
        quit(2);
    }
}

static void createDevice(void)
{
    VkDeviceQueueCreateInfo deviceQueueCreateInfo[1] = { {0} };
    static const float queuePriority[] = {1.0f};
    VkDeviceCreateInfo deviceCreateInfo = {0};
    static const char *const deviceExtensionNames[] = {
        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
    };
    VkResult result;

    deviceQueueCreateInfo->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    deviceQueueCreateInfo->queueFamilyIndex = vulkanContext->graphicsQueueFamilyIndex;
    deviceQueueCreateInfo->queueCount = 1;
    deviceQueueCreateInfo->pQueuePriorities = &queuePriority[0];

    deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    deviceCreateInfo.queueCreateInfoCount = 1;
    deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo;
    deviceCreateInfo.pEnabledFeatures = NULL;
    deviceCreateInfo.enabledExtensionCount = SDL_arraysize(deviceExtensionNames);
    deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames;
    result = vkCreateDevice(vulkanContext->physicalDevice, &deviceCreateInfo, NULL, &vulkanContext->device);
    if (result != VK_SUCCESS) {
        vulkanContext->device = VK_NULL_HANDLE;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkCreateDevice(): %s\n", getVulkanResultString(result));
        quit(2);
    }
}

static void loadDeviceFunctions(void)
{
#define VULKAN_DEVICE_FUNCTION(name)                                         \
    name = (PFN_##name)vkGetDeviceProcAddr(vulkanContext->device, #name);    \
    if (!name) {                                                             \
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,                           \
                     "vkGetDeviceProcAddr(device, \"" #name "\") failed\n"); \
        quit(2);                                                             \
    }
#define VULKAN_GLOBAL_FUNCTION(name)
#define VULKAN_INSTANCE_FUNCTION(name)
    VULKAN_FUNCTIONS()
#undef VULKAN_DEVICE_FUNCTION
#undef VULKAN_GLOBAL_FUNCTION
#undef VULKAN_INSTANCE_FUNCTION
}

#undef VULKAN_FUNCTIONS

static void getQueues(void)
{
    vkGetDeviceQueue(vulkanContext->device,
                     vulkanContext->graphicsQueueFamilyIndex,
                     0,
                     &vulkanContext->graphicsQueue);
    if (vulkanContext->graphicsQueueFamilyIndex != vulkanContext->presentQueueFamilyIndex) {
        vkGetDeviceQueue(vulkanContext->device,
                         vulkanContext->presentQueueFamilyIndex,
                         0,
                         &vulkanContext->presentQueue);
    } else {
        vulkanContext->presentQueue = vulkanContext->graphicsQueue;
    }
}

static void createSemaphore(VkSemaphore *semaphore)
{
    VkResult result;

    VkSemaphoreCreateInfo createInfo = {0};
    createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
    result = vkCreateSemaphore(vulkanContext->device, &createInfo, NULL, semaphore);
    if (result != VK_SUCCESS) {
        *semaphore = VK_NULL_HANDLE;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkCreateSemaphore(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
}

static void createSemaphores(void)
{
    createSemaphore(&vulkanContext->imageAvailableSemaphore);
    createSemaphore(&vulkanContext->renderingFinishedSemaphore);
}

static void getSurfaceCaps(void)
{
    VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulkanContext->physicalDevice, vulkanContext->surface, &vulkanContext->surfaceCapabilities);
    if (result != VK_SUCCESS) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }

    // check surface usage
    if (!(vulkanContext->surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "Vulkan surface doesn't support VK_IMAGE_USAGE_TRANSFER_DST_BIT\n");
        quit(2);
    }
}

static void getSurfaceFormats(void)
{
    VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(vulkanContext->physicalDevice,
                                                           vulkanContext->surface,
                                                           &vulkanContext->surfaceFormatsCount,
                                                           NULL);
    if (result != VK_SUCCESS) {
        vulkanContext->surfaceFormatsCount = 0;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
    if (vulkanContext->surfaceFormatsCount > vulkanContext->surfaceFormatsAllocatedCount) {
        vulkanContext->surfaceFormatsAllocatedCount = vulkanContext->surfaceFormatsCount;
        SDL_free(vulkanContext->surfaceFormats);
        vulkanContext->surfaceFormats = (VkSurfaceFormatKHR *) SDL_malloc(sizeof(VkSurfaceFormatKHR) * vulkanContext->surfaceFormatsAllocatedCount);
        if (!vulkanContext->surfaceFormats) {
            vulkanContext->surfaceFormatsCount = 0;
            SDL_OutOfMemory();
            quit(2);
        }
    }
    result = vkGetPhysicalDeviceSurfaceFormatsKHR(vulkanContext->physicalDevice,
                                                  vulkanContext->surface,
                                                  &vulkanContext->surfaceFormatsCount,
                                                  vulkanContext->surfaceFormats);
    if (result != VK_SUCCESS) {
        vulkanContext->surfaceFormatsCount = 0;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
}

static void getSwapchainImages(void)
{
    VkResult result;

    SDL_free(vulkanContext->swapchainImages);
    vulkanContext->swapchainImages = NULL;
    result = vkGetSwapchainImagesKHR(vulkanContext->device, vulkanContext->swapchain, &vulkanContext->swapchainImageCount, NULL);
    if (result != VK_SUCCESS) {
        vulkanContext->swapchainImageCount = 0;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkGetSwapchainImagesKHR(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
    vulkanContext->swapchainImages = SDL_malloc(sizeof(VkImage) * vulkanContext->swapchainImageCount);
    if (!vulkanContext->swapchainImages) {
        SDL_OutOfMemory();
        quit(2);
    }
    result = vkGetSwapchainImagesKHR(vulkanContext->device,
                                     vulkanContext->swapchain,
                                     &vulkanContext->swapchainImageCount,
                                     vulkanContext->swapchainImages);
    if (result != VK_SUCCESS) {
        SDL_free(vulkanContext->swapchainImages);
        vulkanContext->swapchainImages = NULL;
        vulkanContext->swapchainImageCount = 0;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkGetSwapchainImagesKHR(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
}

static SDL_bool createSwapchain(void)
{
    uint32_t i;
    int w, h;
    VkSwapchainCreateInfoKHR createInfo = {0};
    VkResult result;

    // pick an image count
    vulkanContext->swapchainDesiredImageCount = vulkanContext->surfaceCapabilities.minImageCount + 1;
    if ( (vulkanContext->swapchainDesiredImageCount > vulkanContext->surfaceCapabilities.maxImageCount) &&
         (vulkanContext->surfaceCapabilities.maxImageCount > 0) ) {
        vulkanContext->swapchainDesiredImageCount = vulkanContext->surfaceCapabilities.maxImageCount;
    }

    // pick a format
    if ( (vulkanContext->surfaceFormatsCount == 1) &&
         (vulkanContext->surfaceFormats[0].format == VK_FORMAT_UNDEFINED) ) {
        // aren't any preferred formats, so we pick
        vulkanContext->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
        vulkanContext->surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM;
    } else {
        vulkanContext->surfaceFormat = vulkanContext->surfaceFormats[0];
        for (i = 0; i < vulkanContext->surfaceFormatsCount; i++) {
            if(vulkanContext->surfaceFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM) {
                vulkanContext->surfaceFormat = vulkanContext->surfaceFormats[i];
                break;
            }
        }
    }

    // get size
    SDL_Vulkan_GetDrawableSize(vulkanContext->window, &w, &h);

    // Clamp the size to the allowable image extent.
    // SDL_Vulkan_GetDrawableSize()'s result it not always in this range (bug #3287)
    vulkanContext->swapchainSize.width = SDL_clamp((uint32_t) w,
                                                  vulkanContext->surfaceCapabilities.minImageExtent.width,
                                                  vulkanContext->surfaceCapabilities.maxImageExtent.width);

    vulkanContext->swapchainSize.height = SDL_clamp((uint32_t) h,
                                                   vulkanContext->surfaceCapabilities.minImageExtent.height,
                                                   vulkanContext->surfaceCapabilities.maxImageExtent.height);

    if (w == 0 || h == 0) {
        return SDL_FALSE;
    }

    getSurfaceCaps();

    createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    createInfo.surface = vulkanContext->surface;
    createInfo.minImageCount = vulkanContext->swapchainDesiredImageCount;
    createInfo.imageFormat = vulkanContext->surfaceFormat.format;
    createInfo.imageColorSpace = vulkanContext->surfaceFormat.colorSpace;
    createInfo.imageExtent = vulkanContext->swapchainSize;
    createInfo.imageArrayLayers = 1;
    createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
    createInfo.preTransform = vulkanContext->surfaceCapabilities.currentTransform;
    createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
    createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
    createInfo.clipped = VK_TRUE;
    createInfo.oldSwapchain = vulkanContext->swapchain;
    result = vkCreateSwapchainKHR(vulkanContext->device, &createInfo, NULL, &vulkanContext->swapchain);

    if (createInfo.oldSwapchain) {
        vkDestroySwapchainKHR(vulkanContext->device, createInfo.oldSwapchain, NULL);
    }

    if(result != VK_SUCCESS) {
        vulkanContext->swapchain = VK_NULL_HANDLE;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkCreateSwapchainKHR(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }

    getSwapchainImages();
    return SDL_TRUE;
}

static void destroySwapchain(void)
{
    if (vulkanContext->swapchain) {
        vkDestroySwapchainKHR(vulkanContext->device, vulkanContext->swapchain, NULL);
        vulkanContext->swapchain = VK_NULL_HANDLE;
    }
    SDL_free(vulkanContext->swapchainImages);
    vulkanContext->swapchainImages = NULL;
}

static void destroyCommandBuffers(void)
{
    if (vulkanContext->commandBuffers) {
        vkFreeCommandBuffers(vulkanContext->device,
                             vulkanContext->commandPool,
                             vulkanContext->swapchainImageCount,
                             vulkanContext->commandBuffers);
        SDL_free(vulkanContext->commandBuffers);
        vulkanContext->commandBuffers = NULL;
    }
}

static void destroyCommandPool(void)
{
    if (vulkanContext->commandPool) {
        vkDestroyCommandPool(vulkanContext->device, vulkanContext->commandPool, NULL);
    }
    vulkanContext->commandPool = VK_NULL_HANDLE;
}

static void createCommandPool(void)
{
    VkResult result;
    VkCommandPoolCreateInfo createInfo = {0};
    createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
    createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
    createInfo.queueFamilyIndex = vulkanContext->graphicsQueueFamilyIndex;
    result = vkCreateCommandPool(vulkanContext->device, &createInfo, NULL, &vulkanContext->commandPool);
    if (result != VK_SUCCESS) {
        vulkanContext->commandPool = VK_NULL_HANDLE;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkCreateCommandPool(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
}

static void createCommandBuffers(void)
{
    VkResult result;
    VkCommandBufferAllocateInfo allocateInfo = {0};
    allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
    allocateInfo.commandPool = vulkanContext->commandPool;
    allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
    allocateInfo.commandBufferCount = vulkanContext->swapchainImageCount;
    vulkanContext->commandBuffers = (VkCommandBuffer *) SDL_malloc(sizeof(VkCommandBuffer) * vulkanContext->swapchainImageCount);
    result = vkAllocateCommandBuffers(vulkanContext->device, &allocateInfo, vulkanContext->commandBuffers);
    if(result != VK_SUCCESS) {
        SDL_free(vulkanContext->commandBuffers);
        vulkanContext->commandBuffers = NULL;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkAllocateCommandBuffers(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
}

static void createFences(void)
{
    uint32_t i;

    vulkanContext->fences = SDL_malloc(sizeof(VkFence) * vulkanContext->swapchainImageCount);
    if (!vulkanContext->fences) {
        SDL_OutOfMemory();
        quit(2);
    }
    for (i = 0; i < vulkanContext->swapchainImageCount; i++) {
        VkResult result;
        VkFenceCreateInfo createInfo = {0};
        createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
        createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
        result = vkCreateFence(vulkanContext->device, &createInfo, NULL, &vulkanContext->fences[i]);
        if(result != VK_SUCCESS) {
            for(; i > 0; i--) {
                vkDestroyFence(vulkanContext->device, vulkanContext->fences[i - 1], NULL);
            }
            SDL_free(vulkanContext->fences);
            vulkanContext->fences = NULL;
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                         "vkCreateFence(): %s\n",
                         getVulkanResultString(result));
            quit(2);
        }
    }
}

static void destroyFences(void)
{
    uint32_t i;

    if (!vulkanContext->fences) {
        return;
    }

    for (i = 0; i < vulkanContext->swapchainImageCount; i++) {
        vkDestroyFence(vulkanContext->device, vulkanContext->fences[i], NULL);
    }
    SDL_free(vulkanContext->fences);
    vulkanContext->fences = NULL;
}

static void recordPipelineImageBarrier(VkCommandBuffer commandBuffer,
                                       VkAccessFlags sourceAccessMask,
                                       VkAccessFlags destAccessMask,
                                       VkImageLayout sourceLayout,
                                       VkImageLayout destLayout,
                                       VkImage image)
{
    VkImageMemoryBarrier barrier = {0};
    barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
    barrier.srcAccessMask = sourceAccessMask;
    barrier.dstAccessMask = destAccessMask;
    barrier.oldLayout = sourceLayout;
    barrier.newLayout = destLayout;
    barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    barrier.image = image;
    barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    barrier.subresourceRange.baseMipLevel = 0;
    barrier.subresourceRange.levelCount = 1;
    barrier.subresourceRange.baseArrayLayer = 0;
    barrier.subresourceRange.layerCount = 1;
    vkCmdPipelineBarrier(commandBuffer,
                         VK_PIPELINE_STAGE_TRANSFER_BIT,
                         VK_PIPELINE_STAGE_TRANSFER_BIT,
                         0,
                         0,
                         NULL,
                         0,
                         NULL,
                         1,
                         &barrier);
}

static void rerecordCommandBuffer(uint32_t frameIndex, const VkClearColorValue *clearColor)
{
    VkCommandBuffer commandBuffer = vulkanContext->commandBuffers[frameIndex];
    VkImage image = vulkanContext->swapchainImages[frameIndex];
    VkCommandBufferBeginInfo beginInfo = {0};
    VkImageSubresourceRange clearRange = {0};

    VkResult result = vkResetCommandBuffer(commandBuffer, 0);
    if(result != VK_SUCCESS) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkResetCommandBuffer(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
    beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
    result = vkBeginCommandBuffer(commandBuffer, &beginInfo);
    if (result != VK_SUCCESS) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkBeginCommandBuffer(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
    recordPipelineImageBarrier(commandBuffer,
                               0,
                               VK_ACCESS_TRANSFER_WRITE_BIT,
                               VK_IMAGE_LAYOUT_UNDEFINED,
                               VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                               image);
    clearRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
    clearRange.baseMipLevel = 0;
    clearRange.levelCount = 1;
    clearRange.baseArrayLayer = 0;
    clearRange.layerCount = 1;
    vkCmdClearColorImage(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clearColor, 1, &clearRange);
    recordPipelineImageBarrier(commandBuffer,
                               VK_ACCESS_TRANSFER_WRITE_BIT,
                               VK_ACCESS_MEMORY_READ_BIT,
                               VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                               VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
                               image);
    result = vkEndCommandBuffer(commandBuffer);
    if (result != VK_SUCCESS) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkEndCommandBuffer(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
}

static void destroySwapchainAndSwapchainSpecificStuff(SDL_bool doDestroySwapchain)
{
    vkDeviceWaitIdle(vulkanContext->device);
    destroyFences();
    destroyCommandBuffers();
    destroyCommandPool();
    if (doDestroySwapchain) {
        destroySwapchain();
    }
}

static SDL_bool createNewSwapchainAndSwapchainSpecificStuff(void)
{
    destroySwapchainAndSwapchainSpecificStuff(SDL_FALSE);
    getSurfaceCaps();
    getSurfaceFormats();
    if(!createSwapchain()) {
        return SDL_FALSE;
    }
    createCommandPool();
    createCommandBuffers();
    createFences();
    return SDL_TRUE;
}

static void initVulkan(void)
{
    int i;

    SDL_Vulkan_LoadLibrary(NULL);

    vulkanContexts = (VulkanContext *) SDL_calloc(state->num_windows, sizeof (VulkanContext));
    if (!vulkanContexts) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
        quit(2);
    }

    for (i = 0; i < state->num_windows; ++i) {
        vulkanContext = &vulkanContexts[i];
        vulkanContext->window = state->windows[i];
        loadGlobalFunctions();
        createInstance();
        loadInstanceFunctions();
        createSurface();
        findPhysicalDevice();
        createDevice();
        loadDeviceFunctions();
        getQueues();
        createSemaphores();
        createNewSwapchainAndSwapchainSpecificStuff();
    }
}

static void shutdownVulkan(SDL_bool doDestroySwapchain)
{
    if (vulkanContexts) {
        int i;
        for (i = 0; i < state->num_windows; ++i) {
            vulkanContext = &vulkanContexts[i];
            if (vulkanContext->device && vkDeviceWaitIdle) {
                vkDeviceWaitIdle(vulkanContext->device);
            }

            destroySwapchainAndSwapchainSpecificStuff(doDestroySwapchain);

            if (vulkanContext->imageAvailableSemaphore && vkDestroySemaphore) {
                vkDestroySemaphore(vulkanContext->device, vulkanContext->imageAvailableSemaphore, NULL);
            }

            if (vulkanContext->renderingFinishedSemaphore && vkDestroySemaphore) {
                vkDestroySemaphore(vulkanContext->device, vulkanContext->renderingFinishedSemaphore, NULL);
            }

            if (vulkanContext->device && vkDestroyDevice) {
                vkDestroyDevice(vulkanContext->device, NULL);
            }

            if (vulkanContext->surface && vkDestroySurfaceKHR) {
                vkDestroySurfaceKHR(vulkanContext->instance, vulkanContext->surface, NULL);
            }

            if (vulkanContext->instance && vkDestroyInstance) {
                vkDestroyInstance(vulkanContext->instance, NULL);
            }

            SDL_free(vulkanContext->surfaceFormats);
        }
        SDL_free(vulkanContexts);
        vulkanContexts = NULL;
    }

    SDL_Vulkan_UnloadLibrary();
}

static SDL_bool render(void)
{
    uint32_t frameIndex;
    VkResult result;
    double currentTime;
    VkClearColorValue clearColor = { {0} };
    VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
    VkSubmitInfo submitInfo = {0};
    VkPresentInfoKHR presentInfo = {0};
    int w, h;

    if (!vulkanContext->swapchain) {
        SDL_bool retval = createNewSwapchainAndSwapchainSpecificStuff();
        if(!retval)
            SDL_Delay(100);
        return retval;
    }
    result = vkAcquireNextImageKHR(vulkanContext->device,
                                            vulkanContext->swapchain,
                                            UINT64_MAX,
                                            vulkanContext->imageAvailableSemaphore,
                                            VK_NULL_HANDLE,
                                            &frameIndex);
    if (result == VK_ERROR_OUT_OF_DATE_KHR) {
        return createNewSwapchainAndSwapchainSpecificStuff();
    }

    if ((result != VK_SUBOPTIMAL_KHR) && (result != VK_SUCCESS)) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkAcquireNextImageKHR(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
    result = vkWaitForFences(vulkanContext->device, 1, &vulkanContext->fences[frameIndex], VK_FALSE, UINT64_MAX);
    if (result != VK_SUCCESS) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkWaitForFences(): %s\n", getVulkanResultString(result));
        quit(2);
    }
    result = vkResetFences(vulkanContext->device, 1, &vulkanContext->fences[frameIndex]);
    if (result != VK_SUCCESS) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkResetFences(): %s\n", getVulkanResultString(result));
        quit(2);
    }
    currentTime = (double)SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency();
    clearColor.float32[0] = (float)(0.5 + 0.5 * SDL_sin(currentTime));
    clearColor.float32[1] = (float)(0.5 + 0.5 * SDL_sin(currentTime + M_PI * 2 / 3));
    clearColor.float32[2] = (float)(0.5 + 0.5 * SDL_sin(currentTime + M_PI * 4 / 3));
    clearColor.float32[3] = 1;
    rerecordCommandBuffer(frameIndex, &clearColor);
    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    submitInfo.waitSemaphoreCount = 1;
    submitInfo.pWaitSemaphores = &vulkanContext->imageAvailableSemaphore;
    submitInfo.pWaitDstStageMask = &waitDestStageMask;
    submitInfo.commandBufferCount = 1;
    submitInfo.pCommandBuffers = &vulkanContext->commandBuffers[frameIndex];
    submitInfo.signalSemaphoreCount = 1;
    submitInfo.pSignalSemaphores = &vulkanContext->renderingFinishedSemaphore;
    result = vkQueueSubmit(vulkanContext->graphicsQueue, 1, &submitInfo, vulkanContext->fences[frameIndex]);

    if (result != VK_SUCCESS) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkQueueSubmit(): %s\n", getVulkanResultString(result));
        quit(2);
    }
    presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
    presentInfo.waitSemaphoreCount = 1;
    presentInfo.pWaitSemaphores = &vulkanContext->renderingFinishedSemaphore;
    presentInfo.swapchainCount = 1;
    presentInfo.pSwapchains = &vulkanContext->swapchain;
    presentInfo.pImageIndices = &frameIndex;
    result = vkQueuePresentKHR(vulkanContext->presentQueue, &presentInfo);
    if ((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR)) {
        return createNewSwapchainAndSwapchainSpecificStuff();
    }

    if (result != VK_SUCCESS) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "vkQueuePresentKHR(): %s\n",
                     getVulkanResultString(result));
        quit(2);
    }
    SDL_Vulkan_GetDrawableSize(vulkanContext->window, &w, &h);
    if(w != (int)vulkanContext->swapchainSize.width || h != (int)vulkanContext->swapchainSize.height) {
        return createNewSwapchainAndSwapchainSpecificStuff();
    }
    return SDL_TRUE;
}

int main(int argc, char **argv)
{
    int done;
    SDL_DisplayMode mode;
    SDL_Event event;
    Uint32 then, now, frames;
    int dw, dh;

    /* Enable standard application logging */
    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);

    /* Initialize test framework */
    state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
    if(!state) {
        return 1;
    }

    /* Set Vulkan parameters */
    state->window_flags |= SDL_WINDOW_VULKAN;
    state->skip_renderer = 1;

    if (!SDLTest_CommonDefaultArgs(state, argc, argv) || !SDLTest_CommonInit(state)) {
        SDLTest_CommonQuit(state);
        return 1;
    }

    SDL_GetCurrentDisplayMode(0, &mode);
    SDL_Log("Screen BPP    : %d\n", SDL_BITSPERPIXEL(mode.format));
    SDL_GetWindowSize(state->windows[0], &dw, &dh);
    SDL_Log("Window Size   : %d,%d\n", dw, dh);
    SDL_Vulkan_GetDrawableSize(state->windows[0], &dw, &dh);
    SDL_Log("Draw Size     : %d,%d\n", dw, dh);
    SDL_Log("\n");

    initVulkan();

    /* Main render loop */
    frames = 0;
    then = SDL_GetTicks();
    done = 0;
    while (!done) {
        /* Check for events */
        frames++;
        while(SDL_PollEvent(&event)) {
            /* Need to destroy the swapchain before the window created
             * by SDL.
             */
            if (event.type == SDL_WINDOWEVENT_CLOSE) {
                destroySwapchainAndSwapchainSpecificStuff(SDL_TRUE);
            }
            SDLTest_CommonEvent(state, &event, &done);
        }

        if (!done) {
            int i;
            for (i = 0; i < state->num_windows; ++i) {
                if (state->windows[i]) {
                    vulkanContext = &vulkanContexts[i];
                    render();
                }
            }
        }
    }

    /* Print out some timing information */
    now = SDL_GetTicks();
    if (now > then) {
        SDL_Log("%2.2f frames per second\n", ((double)frames * 1000) / (now - then));
    }

    shutdownVulkan(SDL_TRUE);
    SDLTest_CommonQuit(state);
    return 0;
}

#endif


text:
module SSH.Debug where

import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as LBS
import Debug.Trace
import Numeric (showHex)

debugging :: Bool
debugging = False

-- debug :: (Show a, Show b) => b -> a -> a
-- debug s v
--     | debugging = trace (show s ++ ": " ++ show v) v
--     | otherwise = v

dump :: (Monad m, Show a) => a -> m ()
dump x
    | debugging = trace (show x) (return ())
    | otherwise = return ()

showHexLazyByteString :: ByteString -> [String]
showHexLazyByteString = map (flip showHex "") . LBS.unpack


text:
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')

describe "Migration.descendants" do
  before do
    Sequel::Migration.descendants.clear
  end

  specify "should include Migration subclasses" do
    @class = Class.new(Sequel::Migration)

    Sequel::Migration.descendants.should == [@class]
  end

  specify "should include Migration subclasses in order of creation" do
    @c1 = Class.new(Sequel::Migration)
    @c2 = Class.new(Sequel::Migration)
    @c3 = Class.new(Sequel::Migration)

    Sequel::Migration.descendants.should == [@c1, @c2, @c3]
  end

  specify "should include SimpleMigration instances created by migration DSL" do
    i1 = Sequel.migration{}
    i2 = Sequel.migration{}
    i3 = Sequel.migration{}

    Sequel::Migration.descendants.should == [i1, i2, i3]
  end
end

describe "Migration.apply" do
  before do
    @c = Class.new do
      define_method(:one) {|x| [1111, x]}
      define_method(:two) {|x| [2222, x]}
    end
    @db = @c.new
  end

  specify "should raise for an invalid direction" do
    proc {Sequel::Migration.apply(@db, :hahaha)}.should raise_error(ArgumentError)
  end

  specify "should apply the up and down directions correctly" do
    m = Class.new(Sequel::Migration) do
      define_method(:up) {one(3333)}
      define_method(:down) {two(4444)}
    end
    m.apply(@db, :up).should == [1111, 3333]
    m.apply(@db, :down).should == [2222, 4444]
  end

  specify "should have default up and down actions that do nothing" do
    m = Class.new(Sequel::Migration)
    m.apply(@db, :up).should == nil
    m.apply(@db, :down).should == nil
  end
end

describe "SimpleMigration#apply" do
  before do
    @c = Class.new do
      define_method(:one) {|x| [1111, x]}
      define_method(:two) {|x| [2222, x]}
    end
    @db = @c.new
  end

  specify "should raise for an invalid direction" do
    proc {Sequel.migration{}.apply(@db, :hahaha)}.should raise_error(ArgumentError)
  end

  specify "should apply the up and down directions correctly" do
    m = Sequel.migration do
      up{one(3333)}
      down{two(4444)}
    end
    m.apply(@db, :up).should == [1111, 3333]
    m.apply(@db, :down).should == [2222, 4444]
  end

  specify "should have default up and down actions that do nothing" do
    m = Sequel.migration{}
    m.apply(@db, :up).should == nil
    m.apply(@db, :down).should == nil
  end
end

describe "Reversible Migrations with Sequel.migration{change{}}" do
  before do
    @c = Class.new do
      self::AT = Class.new do
        attr_reader :actions
        def initialize(&block)
          @actions = []
          instance_eval(&block)
        end
        def method_missing(*args)
          @actions << args
        end
        self
      end
      attr_reader :actions
      def initialize
        @actions = []
      end
      def method_missing(*args)
        @actions << args
      end
      def alter_table(*args, &block)
        @actions << [:alter_table, self.class::AT.new(&block).actions]
      end
    end
    @db = @c.new
    @p = Proc.new do
      create_table(:a){Integer :a}
      add_column :a, :b, String
      add_index :a, :b
      rename_column :a, :b, :c
      rename_table :a, :b
      alter_table(:b) do
        add_column :d, String
        add_constraint :blah, 'd IS NOT NULL'
        add_foreign_key :e, :b
        add_primary_key :f, :b
        add_index :e, :name=>'e_n'
        add_full_text_index :e, :name=>'e_ft'
        add_spatial_index :e, :name=>'e_s'
        rename_column :e, :g
      end
      create_view(:c, 'SELECT * FROM b')
      create_join_table(:cat_id=>:cats, :dog_id=>:dogs)
    end
  end

  specify "should apply up with normal actions in normal order" do
    p = @p
    Sequel.migration{change(&p)}.apply(@db, :up)
    @db.actions.should == [[:create_table, :a],
      [:add_column, :a, :b, String],
      [:add_index, :a, :b],
      [:rename_column, :a, :b, :c],
      [:rename_table, :a, :b],
      [:alter_table, [
        [:add_column, :d, String],
        [:add_constraint, :blah, "d IS NOT NULL"],
        [:add_foreign_key, :e, :b],
        [:add_primary_key, :f, :b],
        [:add_index, :e, {:name=>"e_n"}],
        [:add_full_text_index, :e, {:name=>"e_ft"}],
        [:add_spatial_index, :e, {:name=>"e_s"}],
        [:rename_column, :e, :g]]
      ],
      [:create_view, :c, "SELECT * FROM b"],
      [:create_join_table, {:cat_id=>:cats, :dog_id=>:dogs}]]
  end

  specify "should execute down with reversing actions in reverse order" do
    p = @p
    Sequel.migration{change(&p)}.apply(@db, :down)
    @db.actions.should == [
      [:drop_join_table, {:cat_id=>:cats, :dog_id=>:dogs}],
      [:drop_view, :c],
      [:alter_table, [
        [:rename_column, :g, :e],
        [:drop_index, :e, {:name=>"e_s"}],
        [:drop_index, :e, {:name=>"e_ft"}],
        [:drop_index, :e, {:name=>"e_n"}],
        [:drop_column, :f],
        [:drop_column, :e],
        [:drop_constraint, :blah],
        [:drop_column, :d]]
      ],
      [:rename_table, :b, :a],
      [:rename_column, :a, :c, :b],
      [:drop_index, :a, :b],
      [:drop_column, :a, :b],
      [:drop_table, :a]]
  end

  specify "should raise in the down direction if migration uses unsupported method" do
    m = Sequel.migration{change{run 'SQL'}}
    proc{m.apply(@db, :up)}.should_not raise_error(Sequel::Error)
    proc{m.apply(@db, :down)}.should raise_error(Sequel::Error)
  end

  specify "should raise in the down direction if migration uses add_primary_key with an array" do
    m = Sequel.migration{change{alter_table(:a){add_primary_key [:b]}}}
    proc{m.apply(@db, :up)}.should_not raise_error(Sequel::Error)
    proc{m.apply(@db, :down)}.should raise_error(Sequel::Error)
  end

  specify "should raise in the down direction if migration uses add_foreign_key with an array" do
    m = Sequel.migration{change{alter_table(:a){add_foreign_key [:b]}}}
    proc{m.apply(@db, :up)}.should_not raise_error(Sequel::Error)
    proc{m.apply(@db, :down)}.should raise_error(Sequel::Error)
  end
end

describe "Sequel::IntegerMigrator" do
  before do
    dbc = Class.new(Sequel::Mock::Database) do
      attr_reader :drops, :tables_created, :columns_created, :versions
      def initialize(*args)
        super
        @drops = []
        @tables_created = []
        @columns_created = []
        @versions = Hash.new{|h,k| h[k.to_sym]}
      end

      def version; versions.values.first || 0; end
      def creates; @tables_created.map{|x| y = x.to_s; y !~ /\Asm(\d+)/; $1.to_i if $1}.compact; end
      def drop_table(*a); super; @drops.concat(a.map{|x| y = x.to_s; y !~ /\Asm(\d+)/; $1.to_i if $1}.compact); end

      def create_table(name, opts={}, &block)
        super
        @columns_created << / \(?(\w+) integer.*\)?\z/.match(@sqls.last)[1].to_sym
        @tables_created << name.to_sym
      end

      def dataset(opts={})
        ds = super
        ds.extend(Module.new do
          def count; 1; end
          def columns; db.columns_created end
          def insert(h); db.versions.merge!(h); db.run insert_sql(h) end
          def update(h); db.versions.merge!(h); db.run update_sql(h) end
          def fetch_rows(sql); db.execute(sql); yield(db.versions) unless db.versions.empty? end
        end)
        ds
      end

      def table_exists?(name)
        @tables_created.include?(name.to_sym)
      end
    end
    @db = dbc.new

    @dirname = "spec/files/integer_migrations"
  end

  after do
    Object.send(:remove_const, "CreateSessions") if Object.const_defined?("CreateSessions")
  end

  specify "should raise and error if there is a missing integer migration version" do
    proc{Sequel::Migrator.apply(@db, "spec/files/missing_integer_migrations")}.should raise_error(Sequel::Migrator::Error)
  end

  specify "should raise and error if there is a duplicate integer migration version" do
    proc{Sequel::Migrator.apply(@db, "spec/files/duplicate_integer_migrations")}.should raise_error(Sequel::Migrator::Error)
  end

  specify "should add a column name if it doesn't already exist in the schema_info table" do
    @db.create_table(:schema_info){Integer :v}
    @db.should_receive(:alter_table).with('schema_info')
    Sequel::Migrator.apply(@db, @dirname)
  end

  specify "should automatically create the schema_info table with the version column" do
    @db.table_exists?(:schema_info).should be_false
    Sequel::Migrator.run(@db, @dirname, :target=>0)
    @db.table_exists?(:schema_info).should be_true
    @db.dataset.columns.should == [:version]
  end

  specify "should allow specifying the table and columns" do
    @db.table_exists?(:si).should be_false
    Sequel::Migrator.run(@db, @dirname, :target=>0, :table=>:si, :column=>:sic)
    @db.table_exists?(:si).should be_true
    @db.dataset.columns.should == [:sic]
  end

  specify "should apply migrations correctly in the up direction if no target is given" do
    Sequel::Migrator.apply(@db, @dirname)
    @db.creates.should == [1111, 2222, 3333]
    @db.version.should == 3
    @db.sqls.map{|x| x =~ /\AUPDATE.*(\d+)/ ? $1.to_i : nil}.compact.should == [1, 2, 3]
  end

  specify "should be able to tell whether there are outstanding migrations" do
    Sequel::Migrator.is_current?(@db, @dirname).should be_false
    Sequel::Migrator.apply(@db, @dirname)
    Sequel::Migrator.is_current?(@db, @dirname).should be_true
  end

  specify "should have #check_current raise an exception if the migrator is not current" do
    proc{Sequel::Migrator.check_current(@db, @dirname)}.should raise_error(Sequel::Migrator::NotCurrentError)
    Sequel::Migrator.apply(@db, @dirname)
    proc{Sequel::Migrator.check_current(@db, @dirname)}.should_not raise_error
  end

  specify "should apply migrations correctly in the up direction with target" do
    Sequel::Migrator.apply(@db, @dirname, 2)
    @db.creates.should == [1111, 2222]
    @db.version.should == 2
    @db.sqls.map{|x| x =~ /\AUPDATE.*(\d+)/ ? $1.to_i : nil}.compact.should == [1, 2]
  end

  specify "should apply migrations correctly in the up direction with target and existing" do
    Sequel::Migrator.apply(@db, @dirname, 2, 1)
    @db.creates.should == [2222]
    @db.version.should == 2
    @db.sqls.map{|x| x =~ /\AUPDATE.*(\d+)/ ? $1.to_i : nil}.compact.should == [2]
  end

  specify "should apply migrations correctly in the down direction with target" do
    @db.create_table(:schema_info){Integer :version, :default=>0}
    @db[:schema_info].insert(:version=>3)
    @db.version.should == 3
    Sequel::Migrator.apply(@db, @dirname, 0)
    @db.drops.should == [3333, 2222, 1111]
    @db.version.should == 0
    @db.sqls.map{|x| x =~ /\AUPDATE.*(\d+)/ ? $1.to_i : nil}.compact.should == [2, 1, 0]
  end

  specify "should apply migrations correctly in the down direction with target and existing" do
    Sequel::Migrator.apply(@db, @dirname, 1, 2)
    @db.drops.should == [2222]
    @db.version.should == 1
    @db.sqls.map{|x| x =~ /\AUPDATE.*(\d+)/ ? $1.to_i : nil}.compact.should == [1]
  end

  specify "should return the target version" do
    Sequel::Migrator.apply(@db, @dirname, 3, 2).should == 3
    Sequel::Migrator.apply(@db, @dirname, 0).should == 0
    Sequel::Migrator.apply(@db, @dirname).should == 3
  end

  specify "should use IntegerMigrator if IntegerMigrator.apply called, even for timestamped migration directory" do
    proc{Sequel::IntegerMigrator.apply(@db, "spec/files/timestamped_migrations")}.should raise_error(Sequel::Migrator::Error)
  end

  specify "should not use transactions by default" do
    Sequel::Migrator.apply(@db, "spec/files/transaction_unspecified_migrations")
    @db.sqls.should == ["CREATE TABLE schema_info (version integer DEFAULT 0 NOT NULL)", "SELECT 1 AS one FROM schema_info LIMIT 1", "INSERT INTO schema_info (version) VALUES (0)", "SELECT version FROM schema_info LIMIT 1", "CREATE TABLE sm11111 (smc1 integer)", "UPDATE schema_info SET version = 1", "CREATE TABLE sm (smc1 integer)", "UPDATE schema_info SET version = 2"]
  end

  specify "should use transactions by default if the database supports transactional ddl" do
    @db.meta_def(:supports_transactional_ddl?){true}
    Sequel::Migrator.apply(@db, "spec/files/transaction_unspecified_migrations")
    @db.sqls.should == ["CREATE TABLE schema_info (version integer DEFAULT 0 NOT NULL)", "SELECT 1 AS one FROM schema_info LIMIT 1", "INSERT INTO schema_info (version) VALUES (0)", "SELECT version FROM schema_info LIMIT 1", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "UPDATE schema_info SET version = 1", "COMMIT", "BEGIN", "CREATE TABLE sm (smc1 integer)", "UPDATE schema_info SET version = 2", "COMMIT"]
  end

  specify "should respect transaction use on a per migration basis" do
    @db.meta_def(:supports_transactional_ddl?){true}
    Sequel::Migrator.apply(@db, "spec/files/transaction_specified_migrations")
    @db.sqls.should == ["CREATE TABLE schema_info (version integer DEFAULT 0 NOT NULL)", "SELECT 1 AS one FROM schema_info LIMIT 1", "INSERT INTO schema_info (version) VALUES (0)", "SELECT version FROM schema_info LIMIT 1", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "UPDATE schema_info SET version = 1", "COMMIT", "CREATE TABLE sm (smc1 integer)", "UPDATE schema_info SET version = 2"]
  end

  specify "should force transactions if enabled in the migrator" do
    Sequel::Migrator.run(@db, "spec/files/transaction_specified_migrations", :use_transactions=>true)
    @db.sqls.should == ["CREATE TABLE schema_info (version integer DEFAULT 0 NOT NULL)", "SELECT 1 AS one FROM schema_info LIMIT 1", "INSERT INTO schema_info (version) VALUES (0)", "SELECT version FROM schema_info LIMIT 1", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "UPDATE schema_info SET version = 1", "COMMIT", "BEGIN", "CREATE TABLE sm (smc1 integer)", "UPDATE schema_info SET version = 2", "COMMIT"]
  end

  specify "should not use transactions if disabled in the migrator" do
    Sequel::Migrator.run(@db, "spec/files/transaction_unspecified_migrations", :use_transactions=>false)
    @db.sqls.should == ["CREATE TABLE schema_info (version integer DEFAULT 0 NOT NULL)", "SELECT 1 AS one FROM schema_info LIMIT 1", "INSERT INTO schema_info (version) VALUES (0)", "SELECT version FROM schema_info LIMIT 1", "CREATE TABLE sm11111 (smc1 integer)", "UPDATE schema_info SET version = 1", "CREATE TABLE sm (smc1 integer)", "UPDATE schema_info SET version = 2"]
  end
end

describe "Sequel::TimestampMigrator" do
  before do
    sequel_migration_version = 0
    @dsc = dsc = Class.new(Sequel::Mock::Dataset) do
      self::FILES =[]
      define_method(:sequel_migration_version){sequel_migration_version}
      define_method(:sequel_migration_version=){|v| sequel_migration_version = v}

      def columns
        super
        case opts[:from].first
        when :schema_info, 'schema_info'
          [:version]
        when :schema_migrations, 'schema_migrations'
          [:filename]
        when :sm, 'sm'
          [:fn]
        end
      end

      def fetch_rows(sql)
        super
        case opts[:from].first
        when :schema_info, 'schema_info'
          yield({:version=>sequel_migration_version})
        when :schema_migrations, 'schema_migrations'
          self.class::FILES.sort.each{|f| yield(:filename=>f)}
        when :sm, 'sm'
          self.class::FILES.sort.each{|f| yield(:fn=>f)}
        end
      end

      def insert(h={})
        super
        case opts[:from].first
        when :schema_info, 'schema_info'
          self.sequel_migration_version = h.values.first
        when :schema_migrations, :sm, 'schema_migrations', 'sm'
          self.class::FILES << h.values.first
        end
      end

      def update(h={})
        super
        case opts[:from].first
        when :schema_info, 'schema_info'
          self.sequel_migration_version = h.values.first
        end
      end

      def delete
        super
        case opts[:from].first
        when :schema_migrations, :sm, 'schema_migrations', 'sm'
          self.class::FILES.delete(opts[:where].args.last)
        end
      end
    end
    dbc = Class.new(Sequel::Mock::Database) do
      self::Tables = tables= {}
      define_method(:dataset){|*a| dsc.new(self, *a)}
      def create_table(name, *args, &block)
        super
        self.class::Tables[name.to_sym] = true
      end
      define_method(:drop_table){|*names| super(*names); names.each{|n| tables.delete(n.to_sym)}}
      define_method(:table_exists?){|name| super(name); tables.has_key?(name.to_sym)}
    end
    @db = dbc.new
    @m = Sequel::Migrator
  end

  after do
    Object.send(:remove_const, "CreateSessions") if Object.const_defined?("CreateSessions")
    Object.send(:remove_const, "CreateArtists") if Object.const_defined?("CreateArtists")
    Object.send(:remove_const, "CreateAlbums") if Object.const_defined?("CreateAlbums")
  end

  specify "should handle migrating up or down all the way" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir)
    [:schema_migrations, :sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253851_create_nodes.rb 1273253853_3_create_users.rb'
    @m.apply(@db, @dir, 0)
    [:sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == []
  end

  specify "should handle migrating up or down to specific timestamps" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir, 1273253851)
    [:schema_migrations, :sm1111, :sm2222].each{|n| @db.table_exists?(n).should be_true}
    @db.table_exists?(:sm3333).should be_false
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253851_create_nodes.rb'
    @m.apply(@db, @dir, 1273253849)
    [:sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_false}
    @db.table_exists?(:sm1111).should be_true
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb'
  end

  specify "should not be current when there are migrations to apply" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir)
    @m.is_current?(@db, @dir).should be_true
    @dir = 'spec/files/interleaved_timestamped_migrations'
    @m.is_current?(@db, @dir).should be_false
  end

  specify "should raise an exception if the migrator is not current" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir)
    proc{@m.check_current(@db, @dir)}.should_not raise_error
    @dir = 'spec/files/interleaved_timestamped_migrations'
    proc{@m.check_current(@db, @dir)}.should raise_error(Sequel::Migrator::NotCurrentError)
  end

  specify "should apply all missing files when migrating up" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir)
    @dir = 'spec/files/interleaved_timestamped_migrations'
    @m.apply(@db, @dir)
    [:schema_migrations, :sm1111, :sm1122, :sm2222, :sm2233, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253850_create_artists.rb 1273253851_create_nodes.rb 1273253852_create_albums.rb 1273253853_3_create_users.rb'
  end

  specify "should not apply down action to migrations where up action hasn't been applied" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir)
    @dir = 'spec/files/interleaved_timestamped_migrations'
    @m.apply(@db, @dir, 0)
    [:sm1111, :sm1122, :sm2222, :sm2233, :sm3333].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == []
  end

  specify "should handle updating to a specific timestamp when interleaving migrations" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir)
    @dir = 'spec/files/interleaved_timestamped_migrations'
    @m.apply(@db, @dir, 1273253851)
    [:schema_migrations, :sm1111, :sm1122, :sm2222].each{|n| @db.table_exists?(n).should be_true}
    [:sm2233, :sm3333].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253850_create_artists.rb 1273253851_create_nodes.rb'
  end

  specify "should correctly update schema_migrations table when an error occurs when migrating up or down" do
    @dir = 'spec/files/bad_timestamped_migrations'
    proc{@m.apply(@db, @dir)}.should raise_error
    [:schema_migrations, :sm1111, :sm2222].each{|n| @db.table_exists?(n).should be_true}
    @db.table_exists?(:sm3333).should be_false
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253851_create_nodes.rb'
    proc{@m.apply(@db, @dir, 0)}.should raise_error
    [:sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_false}
    @db.table_exists?(:sm1111).should be_true
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb'
  end

  specify "should handle multiple migrations with the same timestamp correctly" do
    @dir = 'spec/files/duplicate_timestamped_migrations'
    @m.apply(@db, @dir)
    [:schema_migrations, :sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253853_create_nodes.rb 1273253853_create_users.rb'
    @m.apply(@db, @dir, 1273253853)
    [:sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253853_create_nodes.rb 1273253853_create_users.rb'
    @m.apply(@db, @dir, 1273253849)
    [:sm1111].each{|n| @db.table_exists?(n).should be_true}
    [:sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb'
    @m.apply(@db, @dir, 1273253848)
    [:sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == []
  end

  specify "should convert schema_info table to schema_migrations table" do
    @dir = 'spec/files/integer_migrations'
    @m.apply(@db, @dir)
    [:schema_info, :sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    [:schema_migrations, :sm1122, :sm2233].each{|n| @db.table_exists?(n).should be_false}

    @dir = 'spec/files/convert_to_timestamp_migrations'
    @m.apply(@db, @dir)
    [:schema_info, :sm1111, :sm2222, :sm3333, :schema_migrations, :sm1122, :sm2233].each{|n| @db.table_exists?(n).should be_true}
    @db[:schema_migrations].select_order_map(:filename).should == %w'001_create_sessions.rb 002_create_nodes.rb 003_3_create_users.rb 1273253850_create_artists.rb 1273253852_create_albums.rb'

    @m.apply(@db, @dir, 4)
    [:schema_info, :schema_migrations, :sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    [:sm1122, :sm2233].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == %w'001_create_sessions.rb 002_create_nodes.rb 003_3_create_users.rb'

    @m.apply(@db, @dir, 0)
    [:schema_info, :schema_migrations].each{|n| @db.table_exists?(n).should be_true}
    [:sm1111, :sm2222, :sm3333, :sm1122, :sm2233].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == []
  end

  specify "should handle unapplied migrations when migrating schema_info table to schema_migrations table" do
    @dir = 'spec/files/integer_migrations'
    @m.apply(@db, @dir, 2)
    [:schema_info, :sm1111, :sm2222].each{|n| @db.table_exists?(n).should be_true}
    [:schema_migrations, :sm3333, :sm1122, :sm2233].each{|n| @db.table_exists?(n).should be_false}

    @dir = 'spec/files/convert_to_timestamp_migrations'
    @m.apply(@db, @dir, 1273253850)
    [:schema_info, :sm1111, :sm2222, :sm3333, :schema_migrations, :sm1122].each{|n| @db.table_exists?(n).should be_true}
    [:sm2233].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == %w'001_create_sessions.rb 002_create_nodes.rb 003_3_create_users.rb 1273253850_create_artists.rb'
  end

  specify "should handle unapplied migrations when migrating schema_info table to schema_migrations table and target is less than last integer migration version" do
    @dir = 'spec/files/integer_migrations'
    @m.apply(@db, @dir, 1)
    [:schema_info, :sm1111].each{|n| @db.table_exists?(n).should be_true}
    [:schema_migrations, :sm2222, :sm3333, :sm1122, :sm2233].each{|n| @db.table_exists?(n).should be_false}

    @dir = 'spec/files/convert_to_timestamp_migrations'
    @m.apply(@db, @dir, 2)
    [:schema_info, :sm1111, :sm2222, :schema_migrations].each{|n| @db.table_exists?(n).should be_true}
    [:sm3333, :sm1122, :sm2233].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == %w'001_create_sessions.rb 002_create_nodes.rb'

    @m.apply(@db, @dir)
    [:schema_info, :sm1111, :sm2222, :schema_migrations, :sm3333, :sm1122, :sm2233].each{|n| @db.table_exists?(n).should be_true}
    @db[:schema_migrations].select_order_map(:filename).should == %w'001_create_sessions.rb 002_create_nodes.rb 003_3_create_users.rb 1273253850_create_artists.rb 1273253852_create_albums.rb'
  end

  specify "should raise error for applied migrations not in file system" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir)
    [:schema_migrations, :sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253851_create_nodes.rb 1273253853_3_create_users.rb'

    @dir = 'spec/files/missing_timestamped_migrations'
    proc{@m.apply(@db, @dir, 0)}.should raise_error(Sequel::Migrator::Error)
    [:schema_migrations, :sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253851_create_nodes.rb 1273253853_3_create_users.rb'
  end

  specify "should raise error missing column name in existing schema_migrations table" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir)
    proc{@m.run(@db, @dir, :column=>:fn)}.should raise_error(Sequel::Migrator::Error)
  end

  specify "should handle migration filenames in a case insensitive manner" do
    @dir = 'spec/files/uppercase_timestamped_migrations'
    @m.apply(@db, @dir)
    [:schema_migrations, :sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    @db[:schema_migrations].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253851_create_nodes.rb 1273253853_3_create_users.rb'
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir, 0)
    [:sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_false}
    @db[:schema_migrations].select_order_map(:filename).should == []
  end

  specify "should :table and :column options" do
    @dir = 'spec/files/timestamped_migrations'
    @m.run(@db, @dir, :table=>:sm, :column=>:fn)
    [:sm, :sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_true}
    @db[:sm].select_order_map(:filename).should == %w'1273253849_create_sessions.rb 1273253851_create_nodes.rb 1273253853_3_create_users.rb'
    @m.run(@db, @dir, :target=>0, :table=>:sm, :column=>:fn)
    [:sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).should be_false}
    @db[:sm].select_order_map(:fn).should == []
  end

  specify "should return nil" do
    @dir = 'spec/files/timestamped_migrations'
    @m.apply(@db, @dir, 1273253850).should == nil
    @m.apply(@db, @dir, 0).should == nil
    @m.apply(@db, @dir).should == nil
  end

  specify "should use TimestampMigrator if TimestampMigrator.apply is called even for integer migrations directory" do
    Sequel::TimestampMigrator.apply(@db, "spec/files/integer_migrations")
    @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "CREATE TABLE sm1111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_sessions.rb')", "CREATE TABLE sm2222 (smc2 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_nodes.rb')", "CREATE TABLE sm3333 (smc3 integer)", "INSERT INTO schema_migrations (filename) VALUES ('003_3_create_users.rb')"]
  end

  specify "should not use transactions by default" do
    Sequel::TimestampMigrator.apply(@db, "spec/files/transaction_unspecified_migrations")
    @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')"]
  end

  specify "should use transactions by default if database supports transactional ddl" do
    @db.meta_def(:supports_transactional_ddl?){true}
    Sequel::TimestampMigrator.apply(@db, "spec/files/transaction_unspecified_migrations")
    @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "COMMIT", "BEGIN", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')", "COMMIT"]
  end

  specify "should support transaction use on a per migration basis" do
    Sequel::TimestampMigrator.apply(@db, "spec/files/transaction_specified_migrations")
    @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "COMMIT", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')"]
  end

  specify "should force transactions if enabled by the migrator" do
    Sequel::TimestampMigrator.run(@db, "spec/files/transaction_specified_migrations", :use_transactions=>true)
    @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "BEGIN", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "COMMIT", "BEGIN", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')", "COMMIT"]
  end

  specify "should not use transactions if disabled in the migrator" do
    Sequel::TimestampMigrator.run(@db, "spec/files/transaction_unspecified_migrations", :use_transactions=>false)
    @db.sqls.should == ["SELECT NULL FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')"]
  end
end


text:
var global = require('../internals/global');
var getBuiltIn = require('../internals/get-built-in');
var isCallable = require('../internals/is-callable');
var isPrototypeOf = require('../internals/object-is-prototype-of');
var USE_SYMBOL_AS_UID = require('../internals/use-symbol-as-uid');

var Object = global.Object;

module.exports = USE_SYMBOL_AS_UID ? function (it) {
  return typeof it == 'symbol';
} : function (it) {
  var $Symbol = getBuiltIn('Symbol');
  return isCallable($Symbol) && isPrototypeOf($Symbol.prototype, Object(it));
};


text:
Contact Me

                    <form action="https://formspree.io/mail@liam-conroy.com" method="POST">

                                Name
                                <input type="text" class="form-control" placeholder="Name" name="name" id="name" required data-validation-required-message="Please enter your name.">

                                Email Address
                                <input type="email" class="form-control" placeholder="Email Address" name="email" id="email" required data-validation-required-message="Please enter your email address.">

                                Phone Number
                                <input type="tel" class="form-control" placeholder="Phone Number" name="phone" id="phone" required data-validation-required-message="Please enter your phone number.">

                                Message
                                <textarea rows="5" class="form-control" placeholder="Message" name="message" id="message" required data-validation-required-message="Please enter a message."></textarea>

                                <button type="submit" class="btn btn-success btn-lg">Send</button>

                    </form>


text:
module ApplicationHelper
  def main_menu
    active_year, active_conference =
      if @conference
        [@conference.year, @conference]
      elsif @year
        [@year, nil]
      else
        [MainMenu.last_year, nil]
      end
    next_conference, previous_conference =
      if active_conference
        [
          next_conference_for(active_conference),
          previous_conference_for(active_conference)
        ]
      else
        [nil, nil]
      end

    content_tag(:div, class: 'main-menu') do
      concat(
        content_tag(:div, class: 'col-lg-12') do
          concat(
            content_tag(:ul, class: 'nav nav-pills', id: 'conference_nav_buttons') do
              MainMenu.years.map do |year|
                concat(
                  content_tag(:li, class: active_year == year ? 'active' : nil) do
                    link_to year.name.to_s, year_events_path(year.name)
                  end
                )
              end
            end
          )
        end
      )

      #navigation
      concat(
        content_tag(:div, class: 'row') do
          content_tag(:div, class: 'col-lg-12') do
            content_tag(:ul, class: 'navigation') do
              if previous_conference
                concat(
                  content_tag(:li, class: 'previous') do
                    link_to about_conference_path(previous_conference.route) do
                      content_tag(:div)
                    end
                  end
                )
              end
              concat(
                content_tag(:ul, class: 'conferences') do
                  Conference.year(active_year).by_date_asc.each do |conf|
                    if can? :read, conf
                      concat(
                        link_to(about_conference_path(conf.route)) do
                          content_tag(:li, class: [conf == active_conference ? 'active' : nil, publishing_status(conf)]) do
                            content_tag(:span, conf.name, class: 'vertical-center')
                          end
                        end
                      )
                    end
                  end
                end
              )
              if next_conference
                concat(
                  content_tag(:li, class: 'next') do
                    link_to about_conference_path(next_conference.route) do
                      content_tag(:div)
                    end
                  end
                )
              end
            end
          end
        end
      )
    end
  end

  def title
    title_str = 'Pacemaker'
    if content_for?(:title)
      "#{title_str} | #{ content_for(:title) }"
    end
  end
end


text:
using System;
using System.Configuration;
using System.IO;
using Clock.Logic.Implementations;
using Clock.Logic.Implementations.GuildWars;
using Clock.Models.GuildWars;
using Clock.Repositories;
using Microsoft.Azure.WebJobs;

namespace Clock.GuildWarsDataJob
{
	public class Functions
	{
	    public static void GuildWars2ImportItems([TimerTrigger("0 5 11 * * 3")] TimerInfo timerInfo, TextWriter log)
	    {
	        var redisConnection = ConfigurationManager.AppSettings["RedisConnectionString"];
		    var databaseConnection = ConfigurationManager.AppSettings["DatabaseConnectionString"];
	        if (string.IsNullOrWhiteSpace(redisConnection))
	        {
	            Console.Error.WriteLine("No RedisConnection found in app.config");
	            return;
	        }
	        var azureSettings = new AzureSettingsService();
            azureSettings.Load();
		    var sessionFactory = SessionFactory.CreateSessionFactory(databaseConnection);
            var itemService = new ItemService(azureSettings, new RedisService(redisConnection), new BaseRepository<Item>(sessionFactory));
            itemService.LoadItems();
	    }
	}
}


text:
package org.apache.hive.hcatalog.cli;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Properties;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.Parser;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hive.common.io.SessionStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.hive.cli.CliSessionState;
import org.apache.hadoop.hive.common.LogUtils;
import org.apache.hadoop.hive.common.LogUtils.LogInitializationException;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
import org.apache.hadoop.hive.ql.processors.CommandProcessorException;
import org.apache.hadoop.hive.ql.processors.DfsProcessor;
import org.apache.hadoop.hive.ql.processors.SetProcessor;
import org.apache.hadoop.hive.ql.session.SessionState;
import org.apache.hive.hcatalog.cli.SemanticAnalysis.HCatSemanticAnalyzer;
import org.apache.hive.hcatalog.common.HCatConstants;
import org.apache.hive.hcatalog.common.HCatUtil;

public class HCatCli {
  private static Logger LOG = null;

  @SuppressWarnings("static-access")
  public static void main(String[] args) {

    try {
      LogUtils.initHiveLog4j();
    } catch (LogInitializationException e) {

    }
    LOG = LoggerFactory.getLogger(HCatCli.class);

    CliSessionState ss = new CliSessionState(new HiveConf(SessionState.class));
    ss.in = System.in;
    try {
      ss.out = new SessionStream(System.out, true, "UTF-8");
      ss.err = new SessionStream(System.err, true, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      System.exit(1);
    }

    HiveConf conf = ss.getConf();

    HiveConf.setVar(conf, ConfVars.SEMANTIC_ANALYZER_HOOK, HCatSemanticAnalyzer.class.getName());
    String engine = HiveConf.getVar(conf, ConfVars.HIVE_EXECUTION_ENGINE);
    final String MR_ENGINE = "mr";
    if(!MR_ENGINE.equalsIgnoreCase(engine)) {
      HiveConf.setVar(conf, ConfVars.HIVE_EXECUTION_ENGINE, MR_ENGINE);
      LOG.info("Forcing " + ConfVars.HIVE_EXECUTION_ENGINE + " to " + MR_ENGINE);
    }

    Options options = new Options();

    // -e 'quoted-query-string'
    options.addOption(OptionBuilder
        .hasArg()
        .withArgName("exec")
        .withDescription("hcat command given from command line")
        .create('e'));

    // -f <query-file>
    options.addOption(OptionBuilder
        .hasArg()
        .withArgName("file")
        .withDescription("hcat commands in file")
        .create('f'));

    // -g
    options.addOption(OptionBuilder
        .hasArg().
        withArgName("group").
        withDescription("group for the db/table specified in CREATE statement").
        create('g'));

    // -p
    options.addOption(OptionBuilder
        .hasArg()
        .withArgName("perms")
        .withDescription("permissions for the db/table specified in CREATE statement")
        .create('p'));

    // -D
    options.addOption(OptionBuilder
        .hasArgs(2)
        .withArgName("property=value")
        .withValueSeparator()
        .withDescription("use hadoop value for given property")
        .create('D'));

    // [-h|--help]
    options.addOption(new Option("h", "help", false, "Print help information"));

    Parser parser = new GnuParser();
    CommandLine cmdLine = null;

    try {
      cmdLine = parser.parse(options, args);

    } catch (ParseException e) {
      printUsage(options, System.err);
      // Note, we print to System.err instead of ss.err, because if we can't parse our
      // commandline, we haven't even begun, and therefore cannot be expected to have
      // reasonably constructed or started the SessionState.
      System.exit(1);
    }

    // -D : process these first, so that we can instantiate SessionState appropriately.
    setConfProperties(conf, cmdLine.getOptionProperties("D"));

    // -h
    if (cmdLine.hasOption('h')) {
      printUsage(options, ss.out);
      sysExit(ss, 0);
    }

    // -e
    String execString = (String) cmdLine.getOptionValue('e');

    // -f
    String fileName = (String) cmdLine.getOptionValue('f');
    if (execString != null && fileName != null) {
      ss.err.println("The '-e' and '-f' options cannot be specified simultaneously");
      printUsage(options, ss.err);
      sysExit(ss, 1);
    }

    // -p
    String perms = (String) cmdLine.getOptionValue('p');
    if (perms != null) {
      validatePermissions(ss, conf, perms);
    }

    // -g
    String grp = (String) cmdLine.getOptionValue('g');
    if (grp != null) {
      conf.set(HCatConstants.HCAT_GROUP, grp);
    }

    // Now that the properties are in, we can instantiate SessionState.
    SessionState.start(ss);

    // all done parsing, let's run stuff!
    if (execString != null) {
      // remove the leading and trailing quotes. hcatalog can miss on some cases.
      if (execString.length() > 1 && execString.startsWith("\"") && execString.endsWith("\"")) {
        execString = execString.substring(1, execString.length() - 1);
      }
      sysExit(ss, processLine(execString));
    }

    try {
      if (fileName != null) {
        sysExit(ss, processFile(fileName));
      }
    } catch (FileNotFoundException e) {
      ss.err.println("Input file not found. (" + e.getMessage() + ")");
      sysExit(ss, 1);
    } catch (IOException e) {
      ss.err.println("Could not open input file for reading. (" + e.getMessage() + ")");
      sysExit(ss, 1);
    }

    // -h
    printUsage(options, ss.err);
    sysExit(ss, 1);
  }

  /**
   * Wrapper for System.exit that makes sure we close our SessionState
   * before we exit. This ignores any error generated by attempting to
   * close the session state, merely printing out the error. The return
   * code is not changed in such an occurrence because we want to retain
   * the success code of whatever command we already ran.
   */
  private static void sysExit(SessionState ss, int retCode) {
    try {
      ss.close();
    } catch (IOException e) {
      // If we got an error attempting to ss.close, then it's not likely that
      // ss.err is valid. So we're back to System.err. Also, we don't change
      // the return code, we simply log a warning, and return whatever return
      // code we expected to do already.
      System.err.println(e.getMessage());
      e.printStackTrace(System.err);
    }
    System.exit(retCode);
  }

  private static void setConfProperties(HiveConf conf, Properties props) {
    for (java.util.Map.Entry<Object, Object> e : props.entrySet()) {
      conf.set((String) e.getKey(), (String) e.getValue());
    }
  }

  private static int processLine(String line) {
    int ret = 0;

    String command = "";
    for (String oneCmd : line.split(";")) {

      if (StringUtils.endsWith(oneCmd, "\\")) {
        command += StringUtils.chop(oneCmd) + ";";
        continue;
      } else {
        command += oneCmd;
      }
      if (StringUtils.isBlank(command)) {
        continue;
      }

      ret = processCmd(command);
      command = "";
    }
    return ret;
  }

  private static int processFile(String fileName) throws IOException {
    FileReader fileReader = null;
    BufferedReader reader = null;
    try {
      fileReader = new FileReader(fileName);
      reader = new BufferedReader(fileReader);
      String line;
      StringBuilder qsb = new StringBuilder();

      while ((line = reader.readLine()) != null) {
        qsb.append(line + "\n");
      }

      return (processLine(qsb.toString()));
    } finally {
      if (fileReader != null) {
        fileReader.close();
      }
      if (reader != null) {
        reader.close();
      }
    }
  }

  private static int processCmd(String cmd) {

    SessionState ss = SessionState.get();
    long start = System.currentTimeMillis();

    cmd = cmd.trim();
    String firstToken = cmd.split("\\s+")[0].trim();

    if (firstToken.equalsIgnoreCase("set")) {
      try {
        new SetProcessor().run(cmd.substring(firstToken.length()).trim());
        return 0;
      } catch (CommandProcessorException e) {
        return e.getResponseCode();
      }
    } else if (firstToken.equalsIgnoreCase("dfs")) {
      try {
        new DfsProcessor(ss.getConf()).run(cmd.substring(firstToken.length()).trim());
        return 0;
      } catch (CommandProcessorException e) {
        return e.getResponseCode();
      }
    }

    HCatDriver driver = new HCatDriver(ss.getConf());
    try {
      driver.run(cmd);
    } catch (CommandProcessorException e) {
      driver.close();
      sysExit(ss, e.getResponseCode());
    }

    int ret = 0;
    ArrayList<String> res = new ArrayList<String>();
    try {
      while (driver.getResults(res)) {
        for (String r : res) {
          ss.out.println(r);
        }
        res.clear();
      }
    } catch (IOException e) {
      ss.err.println("Failed with exception " + e.getClass().getName() + ":"
        + e.getMessage() + "\n" + org.apache.hadoop.util.StringUtils.stringifyException(e));
      ret = 1;
    }

    int cret = driver.close();
    if (ret == 0) {
      ret = cret;
    }

    long end = System.currentTimeMillis();
    if (end > start) {
      double timeTaken = (end - start) / 1000.0;
      ss.err.println("Time taken: " + timeTaken + " seconds");
    }
    return ret;
  }

  private static void printUsage(Options options, OutputStream os) {
    PrintWriter pw = new PrintWriter(os);
    new HelpFormatter().printHelp(pw, 2 * HelpFormatter.DEFAULT_WIDTH,
      "hcat { -e \"<query>\" | -f \"<filepath>\" } [ -g \"<group>\" ] [ -p \"<perms>\" ] [ -D\"<name>=<value>\" ]",
      null, options, HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD,
      null, false);
    pw.flush();
  }

  private static void validatePermissions(CliSessionState ss, HiveConf conf, String perms) {
    perms = perms.trim();
    FsPermission fp = null;

    if (perms.matches("^\\s*([r,w,x,-]{9})\\s*$")) {
      fp = FsPermission.valueOf("d" + perms);
    } else if (perms.matches("^\\s*([0-7]{3})\\s*$")) {
      fp = new FsPermission(Short.decode("0" + perms));
    } else {
      ss.err.println("Invalid permission specification: " + perms);
      sysExit(ss,1);
    }

    if (!HCatUtil.validateMorePermissive(fp.getUserAction(), fp.getGroupAction())) {
      ss.err.println("Invalid permission specification: " + perms + " : user permissions must be more permissive than group permission ");
      sysExit(ss,1);
    }
    if (!HCatUtil.validateMorePermissive(fp.getGroupAction(), fp.getOtherAction())) {
      ss.err.println("Invalid permission specification: " + perms + " : group permissions must be more permissive than other permission ");
      sysExit(ss,1);
    }
    if ((!HCatUtil.validateExecuteBitPresentIfReadOrWrite(fp.getUserAction())) ||
      (!HCatUtil.validateExecuteBitPresentIfReadOrWrite(fp.getGroupAction())) ||
      (!HCatUtil.validateExecuteBitPresentIfReadOrWrite(fp.getOtherAction()))) {
      ss.err.println("Invalid permission specification: " + perms + " : permissions must have execute permissions if read or write permissions are specified ");
      sysExit(ss,1);
    }

    conf.set(HCatConstants.HCAT_PERMS, "d" + fp.toString());

  }

}