text:
namespace jcl {

std::mutex OpenCLContext::context_lock_;

OpenCLContext::OpenCLContext() {
  cur_program_ = nullptr;
  cur_kernel_ = nullptr;
}

OpenCLContext::~OpenCLContext() {
  // Make sure all queues are empty
  for (uint32_t i = 0; i < queues_.size(); i++) {
    queues_[i].finish();
  }
  queues_.clear();
  devices_.clear();
}

void OpenCLContext::init(const CLDevice device, const CLVendor vendor,
                         const bool verbose_startup) {
  std::lock_guard<std::mutex> lock(context_lock_);

  createContext(device, vendor, verbose_startup);
  InitDevices(device, verbose_startup);
  createCommandQueues(verbose_startup);  // For each device
}

bool OpenCLContext::queryDeviceExists(const CLDevice device,
                                      const CLVendor vendor) {
  std::lock_guard<std::mutex> lock(context_lock_);

  cl::Platform platform;
  bool exists = getPlatform(device, vendor, platform);

  return exists;
}

void OpenCLContext::createContext(const CLDevice device, const CLVendor vendor,
                                  const bool verbose_startup) {
  cl::Platform platform;

  // TODO: We might want to fail more gracefully.
  RASSERT(getPlatform(device, vendor,
                      platform));  // Otherwise no OpenCL platforms were found

  // Use the preferred platform and create a context
  cl_context_properties cps[] = {CL_CONTEXT_PLATFORM,
                                 (cl_context_properties)(platform)(), 0};

  cl_device_type device_cl = CLDevice2CLDeviceType(device);
  cl_int err;
  context_ = cl::Context(device_cl, cps, nullptr, nullptr, &err);
  CHECK_ERROR(err);
  if (verbose_startup) {
    std::cout << "\tCreated OpenCL Context: " << std::endl;
    std::cout << "\t - vendor: " << platform.getInfo<CL_PLATFORM_VENDOR>();
    std::cout << std::endl;
  }
}

void OpenCLContext::InitDevices(const CLDevice device,
                                const bool verbose_startup) {
  cl_int err;
  devices_ = context_.getInfo<CL_CONTEXT_DEVICES>(&err);
  CHECK_ERROR(err);

  // Check that there are devices attadched to the current context
  RASSERT(devices_.size() > 0);

  // Make sure all of the devices match what the user asked for.
  if (device != CLDeviceAll) {
    cl_device_type device_cl = CLDevice2CLDeviceType(device);
    static_cast<void>(device_cl);
    for (uint32_t i = 0; i < devices_.size(); i++) {
      cl_device_type cur_device_cl = devices_[i].getInfo<CL_DEVICE_TYPE>(&err);
      CHECK_ERROR(err);
      RASSERT(cur_device_cl == device_cl);
    }
  }

  for (uint32_t i = 0; i < devices_.size(); i++) {
    if (verbose_startup) {
      std::cout << "\t - device " << i << " CL_DEVICE_NAME: ";
      std::cout << devices_[i].getInfo<CL_DEVICE_NAME>(&err) << std::endl;
      CHECK_ERROR(err);
      std::cout << "\t - device " << i << " CL_DEVICE_VERSION: ";
      std::cout << devices_[i].getInfo<CL_DEVICE_VERSION>(&err) << std::endl;
      CHECK_ERROR(err);
      std::cout << "\t - device " << i << " CL_DRIVER_VERSION: ";
      std::cout << devices_[i].getInfo<CL_DRIVER_VERSION>(&err) << std::endl;
      CHECK_ERROR(err);
      std::cout << "\t - device " << i << " CL_DEVICE_MAX_COMPUTE_UNITS: ";
      std::cout << devices_[i].getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>(&err)
                << std::endl;
      CHECK_ERROR(err);
      std::cout << "\t - device " << i
                << " CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: ";
      std::cout << devices_[i].getInfo<CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS>(&err)
                << std::endl;
      CHECK_ERROR(err);
    }
    size_t max_size = devices_[i].getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>(&err);
    CHECK_ERROR(err);
    devices_max_workgroup_size_.push_back((int)max_size);
    if (verbose_startup) {
      std::cout << "\t - device " << i << " CL_DEVICE_MAX_WORK_GROUP_SIZE: ";
      std::cout << devices_max_workgroup_size_[i] << std::endl;
      std::cout << "\t - device " << i << " CL_DEVICE_GLOBAL_MEM_SIZE: ";
      std::cout << devices_[i].getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>(&err)
                << std::endl;
      CHECK_ERROR(err);
    }
    std::vector<size_t> item_sizes =
        devices_[i].getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>(&err);
    CHECK_ERROR(err);
    std::unique_ptr<uint32_t[]> item_sizes_arr(new uint32_t[3]);
    item_sizes_arr[0] = (uint32_t)item_sizes[0];
    item_sizes_arr[1] = (uint32_t)item_sizes[1];
    item_sizes_arr[2] = (uint32_t)item_sizes[2];
    devices_max_workitem_size_.push_back(std::move(item_sizes_arr));
    if (verbose_startup) {
      std::cout << "\t - device " << i << " CL_DEVICE_MAX_WORK_ITEM_SIZES: ";
      std::cout << "(i=2) ";
      for (int32_t j = 2; j >= 0; j--) {
        std::cout << item_sizes[j] << " ";
      }
      std::cout << "(i=0)";
      std::cout << std::endl;
    }
  }
}

void OpenCLContext::createCommandQueues(const bool verbose_startup) {
  for (uint32_t i = 0; i < devices_.size(); i++) {
    cl_int err;
    queues_.push_back(cl::CommandQueue(context_, devices_[i], 0, &err));
    CHECK_ERROR(err);
  }
}

uint32_t OpenCLContext::getNumDevices() { return (uint32_t)devices_.size(); }

uint32_t OpenCLContext::getMaxWorkgroupSize(const uint32_t i) {
  return devices_max_workgroup_size_[i];
}

uint32_t OpenCLContext::getMaxWorkitemSize(const uint32_t device_index,
                                           const uint32_t dim) {
  return devices_max_workitem_size_[device_index][dim];
}

std::string OpenCLContext::getDeviceName(const uint32_t device_index) {
  std::string name;
  cl_int err;
  name = devices_[device_index].getInfo<CL_DEVICE_NAME>(&err);
  CHECK_ERROR(err);
  return name;
}

CLDevice OpenCLContext::getDeviceType(const uint32_t device_index) {
  cl_device_type type;
  cl_int err;
  type = devices_[device_index].getInfo<CL_DEVICE_TYPE>(&err);
  CHECK_ERROR(err);
  return CLDeviceType2CLDevice(type);
}

uint32_t OpenCLContext::printDevices() {
  // ASSUME THAT THE CONTEXT LOCK HAS ALREADY BEEN TAKEN!
  // Get available platforms
  std::vector<cl::Platform> platforms;
  CHECK_ERROR(cl::Platform::get(&platforms));

  if (platforms.size() == 0) {
    std::cout << "No OpenCL devices found." << std::endl;
    return 0;
  }

  const cl_device_type type_cl = CLDevice2CLDeviceType(CLDeviceAll);

  uint32_t num_devices = 0;
  for (uint32_t i = 0; i < (uint32_t)platforms.size(); i++) {
    std::vector<cl_device_id> devices;
    getPlatformDeviceIDsOfType(platforms[i], type_cl, devices);
    std::cout << "  Platform: " << platforms[i].getInfo<CL_PLATFORM_VENDOR>()
              << " (" << devices.size() << " devices)" << std::endl;
    num_devices += static_cast<uint32_t>(devices.size());

    // Get the devices for this platform.
    std::unique_ptr<char[]> name(new char[1024]);
    for (uint32_t d = 0; d < devices.size(); d++) {
      CHECK_ERROR(clGetDeviceInfo(devices[d], CL_DEVICE_NAME,
                                  1023 * sizeof(name[0]), name.get(), nullptr));
      std::cout << "    Device " << d << " name: " << name.get() << std::endl;
    }
  }
  return num_devices;
}

bool OpenCLContext::getPlatform(const CLDevice device, const CLVendor vendor,
                                cl::Platform& return_platform) {
  // ASSUME THAT THE CONTEXT LOCK HAS ALREADY BEEN TAKEN!
  // Get available platforms
  std::vector<cl::Platform> platforms;
  CHECK_ERROR(cl::Platform::get(&platforms));

  if (platforms.size() == 0) {
    return false;
  }

  const cl_device_type type_cl = CLDevice2CLDeviceType(device);

  int platformID = -1;
  std::string find = CLVendor2String(vendor);
  std::vector<cl_device_id> devices;
  for (uint32_t i = 0; i < (uint32_t)platforms.size(); i++) {
    if (vendor == CLVendorAny ||
        platforms[i].getInfo<CL_PLATFORM_VENDOR>().find(find) !=
            std::string::npos) {
      // Check this platform for the device type we want
      getPlatformDeviceIDsOfType(platforms[i], type_cl, devices);
      if (devices.size() > 0) {
        platformID = i;
        break;
      }
    }
  }

  if (platformID != -1) {
    return_platform = platforms[platformID];
    return true;
  } else {
    return false;
  }
}

void OpenCLContext::getPlatformDeviceIDsOfType(
    cl::Platform& platform, const cl_device_type type,
    std::vector<cl_device_id>& devices) {
  // Unforunately, the ATI C++  API throws a DEEP driver-level memory
  // exception when querying devices on Nvidia hardware.  Use the C API
  // for this task instead.
  if (devices.size() > 0) {
    devices.clear();
  }

  // First, get the size of device list:
  cl_uint num_devices;
  cl_int rc = clGetDeviceIDs(platform(), type, 0, nullptr, &num_devices);
  if (rc != CL_SUCCESS || num_devices == 0) {
    return;
  }

  cl_device_id* dev_ids = new cl_device_id[num_devices];
  CHECK_ERROR(clGetDeviceIDs(platform(), type, num_devices, dev_ids, nullptr));

  for (uint32_t i = 0; i < num_devices; i++) {
    cl_device_type cur_type;
    CHECK_ERROR(clGetDeviceInfo(dev_ids[i], CL_DEVICE_TYPE, sizeof(cur_type),
                                &cur_type, nullptr));
    if (cur_type == type || type == CL_DEVICE_TYPE_ALL) {
      devices.push_back(dev_ids[i]);
    }
  }

  delete[] dev_ids;
}

std::shared_ptr<OpenCLBufferData> OpenCLContext::allocateBuffer(
    const CLBufferType type, const uint32_t nelems) {
  return std::shared_ptr<OpenCLBufferData>(
      new OpenCLBufferData(type, nelems, context_));
}

void OpenCLContext::useKernel(const char* filename, const char* kernel_name,
                              const bool strict_float) {
  // Make sure the program is compiled
  if (cur_program_ == nullptr || cur_program_->filename() != filename) {
    if (programs_.find(filename) == programs_.end()) {
      programs_[filename] = std::unique_ptr<OpenCLProgram>(
          new OpenCLProgram(filename, context_, devices_, strict_float));
    }
    cur_program_ = programs_[filename].get();
  }

  // Make sure the Kernel is compiled
  if (cur_kernel_ == nullptr || cur_kernel_->program() != cur_program_ ||
      cur_kernel_->kernel_name() != kernel_name) {
    std::string id = std::string(filename) + kernel_name;
    if (kernels_.find(id) == kernels_.end()) {
      kernels_[id] = std::unique_ptr<OpenCLKernel>(
          new OpenCLKernel(kernel_name, cur_program_));
    }
    cur_kernel_ = kernels_[id].get();
  }
}

void OpenCLContext::useKernelCStr(const char* kernel_c_str,
                                  const char* kernel_name,
                                  const bool strict_float) {
  // Hash the string and use this for the filename.
  uint32_t hash = jcl::data_str::HashString(
      std::numeric_limits<uint32_t>::max(), kernel_c_str);
  std::stringstream filename;
  filename << "char* kernel. StringHash: " << hash;

  // Make sure the program is compiled
  if (cur_program_ == nullptr || cur_program_->filename() != filename.str()) {
    if (programs_.find(filename.str()) == programs_.end()) {
      programs_[filename.str()] =
          std::unique_ptr<OpenCLProgram>(new OpenCLProgram(
              kernel_c_str, filename.str(), context_, devices_, strict_float));
    }
    cur_program_ = programs_[filename.str()].get();
  }
  // Make sure the Kernel is compiled
  if (cur_kernel_ == nullptr || cur_kernel_->program() != cur_program_ ||
      cur_kernel_->kernel_name() != kernel_name) {
    std::string id = filename.str() + kernel_name;
    if (kernels_.find(id) == kernels_.end()) {
      kernels_[id] = std::unique_ptr<OpenCLKernel>(
          new OpenCLKernel(kernel_name, cur_program_));
    }
    cur_kernel_ = kernels_[id].get();
  }
}

void OpenCLContext::setArg(const uint32_t index,
                           const std::shared_ptr<OpenCLBufferData>& val) {
  // You must call OpenCL::useKernel() first.
  RASSERT(cur_kernel_ != nullptr);
  cur_kernel_->setArg(index, val->buffer());
}

void OpenCLContext::setArg(const uint32_t index, const uint32_t size,
                           void* data) {
  // You must call OpenCL::useKernel() first.
  RASSERT(cur_kernel_ != nullptr);
  cur_kernel_->setArg(index, size, data);
}

void OpenCLContext::sync(const uint32_t device_index) {
  RASSERT(device_index < devices_.size());
  CHECK_ERROR(queues_[device_index].finish());
}

uint32_t OpenCLContext::queryMaxWorkgroupSizeForCurKernel(
    const uint32_t device_index) {
  // You must call OpenCL::useKernel() first.
  RASSERT(cur_kernel_ != nullptr);
  RASSERT(device_index < devices_.size());

  size_t max_workgroup_size;
  cl_int rc = cur_kernel_->kernel().getWorkGroupInfo<size_t>(
      devices_[device_index], CL_KERNEL_WORK_GROUP_SIZE, &max_workgroup_size);
  RASSERT(rc == CL_SUCCESS);
  return (uint32_t)max_workgroup_size;
}

void OpenCLContext::runKernel(const uint32_t device_index, const uint32_t dim,
                              const uint32_t* global_work_size,
                              const uint32_t* local_work_size,
                              const bool blocking) {
  // You must call OpenCL::useKernel() first.
  RASSERT(cur_kernel_ != nullptr);
  RASSERT(device_index < devices_.size());
  RASSERT(dim <= 3);  // OpenCL doesn't support greater than 3 dims!

  uint32_t total_worksize = 1;
  for (uint32_t i = 0; i < dim; i++) {
    // Check that: Global workgroup size is evenly divisible by the local work
    // group size!
    RASSERT((global_work_size[i] % local_work_size[i]) == 0);
    total_worksize *= local_work_size[i];
    // Check that: Local workgroup size is not greater than
    // devices_max_workitem_size_
    RASSERT((uint32_t)local_work_size[i] <=
            (uint32_t)devices_max_workitem_size_[device_index][i]);
  }
  // Check that: Local workgroup size is not greater than
  // CL_DEVICE_MAX_WORK_GROUP_SIZE!
  RASSERT(total_worksize <=
          (uint32_t)devices_max_workgroup_size_[device_index]);
  uint32_t max_size = queryMaxWorkgroupSizeForCurKernel(device_index);
  // Check that: Local workgroup size is not greater than
  // CL_KERNEL_WORK_GROUP_SIZE!
  RASSERT(total_worksize <= (uint32_t)max_size);

  cl::NDRange offset = cl::NullRange;
  cl::NDRange global_work;
  cl::NDRange local_work;
  switch (dim) {
    case 1:
      global_work = cl::NDRange(global_work_size[0]);
      local_work = cl::NDRange(local_work_size[0]);
      break;
    case 2:
      global_work = cl::NDRange(global_work_size[0], global_work_size[1]);
      local_work = cl::NDRange(local_work_size[0], local_work_size[1]);
      break;
    case 3:
      global_work = cl::NDRange(global_work_size[0], global_work_size[1],
                                global_work_size[2]);
      local_work = cl::NDRange(local_work_size[0], local_work_size[1],
                               local_work_size[2]);
      break;
  }
  cl::Event cur_event;
  CHECK_ERROR(queues_[device_index].enqueueNDRangeKernel(
      cur_kernel_->kernel(), offset, global_work, local_work, nullptr,
      &cur_event));

  if (blocking) {
    cur_event.wait();
  }
}

void OpenCLContext::runKernel(const uint32_t device_index, const uint32_t dim,
                              const uint32_t* global_work_size,
                              const bool blocking) {
  // You must call OpenCL::useKernel() first.
  RASSERT(cur_kernel_ != nullptr);
  RASSERT(device_index < devices_.size());
  RASSERT(dim <= 3);  // OpenCL doesn't support greater than 3 dims!

  cl::NDRange offset = cl::NullRange;
  cl::NDRange global_work;
  cl::NDRange local_work = cl::NullRange;  // Let OpenCL Choose
  switch (dim) {
    case 1:
      global_work = cl::NDRange(global_work_size[0]);
      break;
    case 2:
      global_work = cl::NDRange(global_work_size[0], global_work_size[1]);
      break;
    case 3:
      global_work = cl::NDRange(global_work_size[0], global_work_size[1],
                                global_work_size[2]);
      break;
  }
  cl::Event cur_event;
  CHECK_ERROR(queues_[device_index].enqueueNDRangeKernel(
      cur_kernel_->kernel(), offset, global_work, local_work, nullptr,
      &cur_event));

  if (blocking) {
    cur_event.wait();
  }
}

std::string OpenCLContext::CLVendor2String(const CLVendor vendor) {
  std::string str;
  switch (vendor) {
    case CLVendorAny:
      str = "CLVendorAny";
      break;
    case CLDeviceNVidia:
      str = "NVIDIA";
      break;
    case CLDeviceAMD:
      str = "Advanced Micro Devices";
      break;
    case CLDeviceIntel:
      str = "Intel";
      break;
    default:
      std::cout << "Invalid vendor specified" << std::endl;
      RASSERT(false);
      break;
  }
  return str;
}

cl_device_type OpenCLContext::CLDevice2CLDeviceType(const CLDevice device) {
  cl_device_type ret = CL_DEVICE_TYPE_ALL;
  switch (device) {
    case CLDeviceDefault:
      ret = CL_DEVICE_TYPE_DEFAULT;
      break;
    case CLDeviceCPU:
      ret = CL_DEVICE_TYPE_CPU;
      break;
    case CLDeviceGPU:
      ret = CL_DEVICE_TYPE_GPU;
      break;
    case CLDeviceAccelerator:
      ret = CL_DEVICE_TYPE_ACCELERATOR;
      break;
    case CLDeviceAll:
      ret = CL_DEVICE_TYPE_ALL;
      break;
    default:
      std::cout << "Invalid enumerant" << std::endl;
      RASSERT(false);
  }
  return ret;
}

CLDevice OpenCLContext::CLDeviceType2CLDevice(const cl_device_type device) {
  CLDevice ret;
  switch (device) {
    case CL_DEVICE_TYPE_DEFAULT:
      ret = CLDeviceDefault;
      break;
    case CL_DEVICE_TYPE_CPU:
      ret = CLDeviceCPU;
      break;
    case CL_DEVICE_TYPE_GPU:
      ret = CLDeviceGPU;
      break;
    case CL_DEVICE_TYPE_ACCELERATOR:
      ret = CLDeviceAccelerator;
      break;
    case CL_DEVICE_TYPE_ALL:
      ret = CLDeviceAll;
      break;
    default:
      std::cout << "Invalid enumerant" << std::endl;
      RASSERT(false);
      ret = CLDeviceDefault;
      break;
  }
  return ret;
}

std::string OpenCLContext::getErrorString(signed int err) {
  switch (err) {
    case 0:
      return "CL_SUCCESS";
    case -1:
      return "CL_DEVICE_NOT_FOUND";
    case -2:
      return "CL_DEVICE_NOT_AVAILABLE";
    case -3:
      return "CL_COMPILER_NOT_AVAILABLE";
    case -4:
      return "CL_MEM_OBJECT_ALLOCATION_FAILURE";
    case -5:
      return "CL_OUT_OF_RESOURCES";
    case -6:
      return "CL_OUT_OF_HOST_MEMORY";
    case -7:
      return "CL_PROFILING_INFO_NOT_AVAILABLE";
    case -8:
      return "CL_MEM_COPY_OVERLAP";
    case -9:
      return "CL_IMAGE_FORMAT_MISMATCH";
    case -10:
      return "CL_IMAGE_FORMAT_NOT_SUPPORTED";
    case -11:
      return "CL_BUILD_PROGRAM_FAILURE";
    case -12:
      return "CL_MAP_FAILURE";

    case -30:
      return "CL_INVALID_VALUE";
    case -31:
      return "CL_INVALID_DEVICE_TYPE";
    case -32:
      return "CL_INVALID_PLATFORM";
    case -33:
      return "CL_INVALID_DEVICE";
    case -34:
      return "CL_INVALID_CONTEXT";
    case -35:
      return "CL_INVALID_QUEUE_PROPERTIES";
    case -36:
      return "CL_INVALID_COMMAND_QUEUE";
    case -37:
      return "CL_INVALID_HOST_PTR";
    case -38:
      return "CL_INVALID_MEM_OBJECT";
    case -39:
      return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR";
    case -40:
      return "CL_INVALID_IMAGE_SIZE";
    case -41:
      return "CL_INVALID_SAMPLER";
    case -42:
      return "CL_INVALID_BINARY";
    case -43:
      return "CL_INVALID_BUILD_OPTIONS";
    case -44:
      return "CL_INVALID_PROGRAM";
    case -45:
      return "CL_INVALID_PROGRAM_EXECUTABLE";
    case -46:
      return "CL_INVALID_KERNEL_NAME";
    case -47:
      return "CL_INVALID_KERNEL_DEFINITION";
    case -48:
      return "CL_INVALID_KERNEL";
    case -49:
      return "CL_INVALID_ARG_INDEX";
    case -50:
      return "CL_INVALID_ARG_VALUE";
    case -51:
      return "CL_INVALID_ARG_SIZE";
    case -52:
      return "CL_INVALID_KERNEL_ARGS";
    case -53:
      return "CL_INVALID_WORK_DIMENSION";
    case -54:
      return "CL_INVALID_WORK_GROUP_SIZE";
    case -55:
      return "CL_INVALID_WORK_ITEM_SIZE";
    case -56:
      return "CL_INVALID_GLOBAL_OFFSET";
    case -57:
      return "CL_INVALID_EVENT_WAIT_LIST";
    case -58:
      return "CL_INVALID_EVENT";
    case -59:
      return "CL_INVALID_OPERATION";
    case -60:
      return "CL_INVALID_GL_OBJECT";
    case -61:
      return "CL_INVALID_BUFFER_SIZE";
    case -62:
      return "CL_INVALID_MIP_LEVEL";
    case -63:
      return "CL_INVALID_GLOBAL_WORK_SIZE";
    default:
      return "Unknown OpenCL error";
  }
}

std::string OpenCLContext::CLDeviceToString(const CLDevice device) {
  switch (device) {
    case CLDeviceDefault:
      return "CLDeviceDefault";
    case CLDeviceAll:
      return "CLDeviceAll";
    case CLDeviceCPU:
      return "CLDeviceCPU";
    case CLDeviceGPU:
      return "CLDeviceGPU";
    case CLDeviceAccelerator:
      return "CLDeviceDefault";
    default:
      std::cout << "Bad CLDevice" << std::endl;
      RASSERT(false);
      return "Bad CLDevice";
  }
}

std::string OpenCLContext::CLVendorToString(const CLVendor vendor) {
  switch (vendor) {
    case CLVendorAny:
      return "CLVendorAny";
    case CLDeviceNVidia:
      return "CLDeviceNVidia";
    case CLDeviceAMD:
      return "CLDeviceAMD";
    case CLDeviceIntel:
      return "CLDeviceIntel";
    default:
      std::cout << "Bad CLVendor" << std::endl;
      RASSERT(false);
      return "Bad CLVendor";
  }
}

}  // namespace jcl


text:
export * from "./DeprecatedResponsive"
import { createMedia } from "@artsy/fresnel"

// TODO: We need this to be 0-based, whereas currently in palette xs is defined
//       as 767. We should move this up to palette, but we need to give the
//       migration path for users of the current Responsive component some
//       serious thought.
const newThemeBreakpoints = {
  xs: 0,
  sm: 768,
  md: 900,
  lg: 1024,
  xl: 1192,
}

const ReactionMedia = createMedia({
  breakpoints: newThemeBreakpoints,
  interactions: {
    // TODO: These should go into palette
    hover: "(pointer: coarse), (-moz-touch-enabled: 1)",
    notHover:
      "not all and (pointer: coarse), not all and (-moz-touch-enabled: 1)",
  },
})

export const Media = ReactionMedia.Media
export const MediaContextProvider = ReactionMedia.MediaContextProvider
export const createMediaStyle = ReactionMedia.createMediaStyle
export const SortedBreakpoints = ReactionMedia.SortedBreakpoints
export const findBreakpointsForWidths = ReactionMedia.findBreakpointsForWidths
export const findBreakpointAtWidth = ReactionMedia.findBreakpointAtWidth
export const valuesWithBreakpointProps = ReactionMedia.valuesWithBreakpointProps

// TODO: Simplify this hideous typing.
export type MatchingMediaQueries = Array<
  "hover" | "notHover" | typeof SortedBreakpoints[0]
>

redpajama_set_name: RedPajamaGithub


text:
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="chrome=1">
    <title>Black Metal as a Service</title>
    <link rel="stylesheet" href="stylesheets/styles.css">
    <link rel="image_src" href="http://blackmaas.com/images/tn_128x128.png"/>
    <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />

    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">

            SATAN IPSUM
            |
            BRUTAL PLACEHOLDERS
            |
            BLACKMAAS.JS
            |
            ABOUT

Azazel demands you use his placeholder images.

        Width
        <input type='text' id='width' name='width' value='500'/>

        Height
        <input type='text' id='height' name='height' value='350'/>

        <button id='generate' name='generate'>GENERATE</button>

Created by Keith Hamilton ©2014


text:
require "test/unit"
require "./rom3999"

class TestRoman3999 < Test::Unit::TestCase

  def test_conversion
    assert_equal('I', Roman3999.convert(1) )
    assert_equal('II', Roman3999.convert(2) )
    assert_equal('III', Roman3999.convert(3) )
    assert_equal('IV', Roman3999.convert(4) )
    assert_equal('V', Roman3999.convert(5) )
    assert_equal('VI', Roman3999.convert(6) )
    assert_equal('VII', Roman3999.convert(7) )
    assert_equal('VIII', Roman3999.convert(8) )
    assert_equal('IX', Roman3999.convert(9) )
    assert_equal('L', Roman3999.convert(50) )
    assert_equal('C', Roman3999.convert(100) )
    assert_equal('C', Roman3999.convert(99) )
    assert_equal('C', Roman3999.convert(100) )
    assert_equal('C', Roman3999.convert(100) )
    assert_equal('', Roman3999.convert(1000) )
    assert_equal('C', Roman3999.convert(1234) )

    assert_equal('MMCMLXXXVII', Roman3999.convert(2987) )
  end

  def test_negative_scenarios
# 0

# sending a string instead of number

  end

end


text:
typedef enum titleOrientation {

    kTitleToRightOfIcon = 0,
    kTItleToBottomOfIcon

} NMTitleOrientation;

@protocol NMBottomTabBarDelegate <NSObject>

@optional

-(void)didSelectTabAtIndex : (NSInteger)index;
-(BOOL)shouldSelectTabAtIndex : (NSInteger)index;

@end

@interface NMBottomTabBar : UIControl{

    NSInteger numberOFTabs;
    NSMutableArray *tabButtons;
    NSInteger selectedIndex;
   }

@property (assign, nonatomic) id <NMBottomTabBarDelegate> delegate;
@property (strong, nonatomic) UIImage *separatorImage;

-(void)layoutTabWihNumberOfButtons:(NSInteger)numberOfTabs ;
-(void)configureTabAtIndex : (NSInteger)index andTitleOrientation : (NMTitleOrientation)titleOrientation withUnselectedBackgroundImage : (UIImage *)backImage selectedBackgroundImage : (UIImage *)selecetedBackImage iconImage : (UIImage *)iconImage iconSelectedImage: (UIImage *)iconSelectedImage andText : (NSString *)text andTextFont:(UIFont *)font andFontColour:(UIColor *)color;
-(void)setTabSelectedWithIndex : (NSInteger)index;

@end


text:
<!--
 Copyright 2013 Red Hat, Inc.

 Red Hat licenses this file to you under the Apache License, version
 2.0 (the "License"); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  implied.  See the License for the specific language governing
 permissions and limitations under the License.
 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

  <artifactId>org.fusesource.camel.component.sap.model.edit</artifactId>
  <packaging>eclipse-plugin</packaging>

  <parent>
  	<groupId>org.fusesource</groupId>
  	<artifactId>camel-sap-parent</artifactId>
  	<version>7.3.0.redhat-SNAPSHOT</version>
  </parent>

  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
      	<groupId>org.eclipse.tycho</groupId>
      	<artifactId>tycho-maven-plugin</artifactId>
      	<extensions>true</extensions>
      </plugin>
	<plugin>
		<groupId>org.eclipse.tycho</groupId>
		<artifactId>target-platform-configuration</artifactId>
	</plugin>
    </plugins>
  </build>
  <url>http://www.fusesource.org</url>
  <name>[TODO]Camel SAP Component Edit Plugin</name>
</project>


text:
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Highcharts {

	// Static var to increment the variable declaration in render function
	private static $chart_id = 0;

	private $shared_opts 	= array(); // shared grah data
	private $global_opts	= array(); // All stocked graph data
	private $opts					= array(); // current graph data
	private $replace_keys, $orig_keys, $serie_index = 0;

	public $js_chart_name = 'chart'; // name of the js var

	/**
	 * __construct function.
	 * You can pass a config array() to the constructor
	 *
	 * @access public
	 * @param array $config. (default: array())
	 * @return void
	 */
	public function __construct($config = array())
	{
		if (count($config) > 0) $this->initialize($config);
	}

	/**
	 * initialize function.
	 * load options form a config file or directelly from array.
	 * If
	 *
	 * @access public
	 * @param mixed $template
	 * @param bool $config_file. (default: false)
	 * @param string $config_path. (default: 'highcharts')
	 * @return void
	 */
	public function initialize($config = array(), $config_path = 'highcharts')
	{
		if (is_string($config)) // string means "load this template"
		{
			$ci =& get_instance();
			$ci->config->load($config_path);

			$config = $ci->config->item($config);

			if (count($config) > 0)
			{
				$this->opts = $this->set_local_options($config);
			}

		}
		if (isset($config['shared_options']) AND empty($this->shared_opts))
		{
			$this->shared_opts = $config['shared_options'];
			unset($config['shared_options']);
		}

		if (! isset($this->opts['series'])) $this->opts['series'] = array();
		if (! isset($this->opts['chart']['renderTo'])) $this->opts['chart']['renderTo'] = 'hc_chart';

		return $this;
	}

	/**
	 * set_options function.
	 * This function can set global options shared by your charts
	 *
	 * @access public
	 * @param array $options. (default: array())
	 * @return void
	 */
	public function set_global_options($options = array())
	{
		if (! empty($options)) $this->shared_opts = $this->set_local_options($options);

		return $this;
	}

	/**
	 * __call function.
	 *
	 * @access public
	 * @param mixed $func
	 * @param mixed $args
	 * @return void
	 */
	public function __call($func, $args)
	{
		if (strpos($func,'_'))
		{
			list($action, $type) = explode('_', $func);

			if (! isset($this->opts[$type]))
			{
				$this->opts[$type] = array();
			}
			switch ($action)
			{
				case 'set':
				$this->opts[$type] = $this->set_local_options($args[0]);
				break;

				case 'push':
				$this->opts[$type] += $this->set_local_options($args[0]);
				break;

				case 'unset':
				$this->unset_local_options($args, $type);
				break;
			}
		}

		return $this;
	}

	/**
	 * set_options function.
	 *
	 * @access private
	 * @param array $options. (default: array())
	 * @param array $root. (default: array())
	 * @return void
	 */
	private function set_local_options($options = array(), $root = array())
	{
		foreach ($options as $opt_key => $opt_name)
		{
			if(is_string($opt_key))
			{
				if(is_object($opt_name))
				{
					$root[$opt_key] = array();
					$root[$opt_key] = $this->set_local_options($opt_name, $root[$opt_key]); // convert back to array
				}
				else $root[$opt_key] = $this->encode_function($opt_name);
			}
		}
		return $root;
	}

	/**
	 * unset_options function.
	 *
	 * @access private
	 * @param array $options. (default: array())
	 * @param mixed $type
	 * @return void
	 */
	private function unset_local_options($options = array(), $type)
	{
		foreach ($options as $option)
		{
			if (array_key_exists($option, $this->opts[$type]))
			{
				unset($this->opts[$type][$option]);
			}
		}
	}

	// SHORTCUT FUNCTIONS
	// guessed most used parameters that desserves to be set quickly
	/**
	 * set_title function.
	 * set title and subtitle in one shoot
	 *
	 * @access public
	 * @param string $title. (default: '')
	 * @param array $options. (default: array())
	 * @return void
	 */
	public function set_title($title = '', $subtitle = '')
	{
		if ($title) $this->opts['title']['text'] = $title;
		if ($subtitle) $this->opts['subtitle']['text'] = $subtitle;

		return $this;
	}

	/**
	 * set_axis_titles function.
	 * quickly set x and y texts
	 *
	 * @access public
	 * @param string $x_label. (default: '')
	 * @param string $y_label. (default: '')
	 * @return void
	 */
	function set_axis_titles($x_title = '', $y_title = '')
	{
		if ($x_title) $this->opts['xAxis']['title']['text'] = $x_title;
		if ($y_title) $this->opts['yAxis']['title']['text'] = $y_title;

		return $this;
	}

	/**
	 * render_to function.
	 * set the container's id to render the graph
	 *
	 * @access public
	 * @param string $id. (default: '')
	 * @return void
	 */
	public function render_to($id = '')
	{
		$this->opts['chart']['renderTo'] = $id;

		return $this;
	}

	/**
	 * set_type function.
	 * The default series type for the chart
	 *
	 * @access public
	 * @param string $type. (default: '')
	 * @return void
	 */
	public function set_type($type = '')
	{
		if ($type AND is_string($type)) $this->opts['chart']['type'] = $type;

		return $this;
	}

	/**
	 * set_dimensions function.
	 * fastly set dimension of the graph is desired
	 *
	 * @access public
	 * @param mixed $width. (default: null)
	 * @param mixed $height. (default: null)
	 * @return void
	 */
	public function set_dimensions($width = null, $height = null)
	{
		if ($width)  $this->opts['chart']['width'] = (int)$width;
		if ($height) $this->opts['chart']['height'] = (int)$height;

		return $this;
	}

	/**
	 * set_serie function.
	 *
	 * @access public
	 * @param string $s_serie_name. (default: '')
	 * @param array $a_value. (default: array())
	 * @return void
	 */
	public function set_serie($options = array(), $serie_name = '')
	{
		if ( ! $serie_name AND ! isset($options['name']))
		{
			$serie_name = count($this->opts['series']);
		}
		// override with the serie name passed
		else if ($serie_name AND isset($options['name']))
		{
			$options['name'] = $serie_name;
		}

		$index = $this->find_serie_name($serie_name);

		if (count($options) > 0)
		{
		    foreach($options as $key => $value)
		    {
					$value = (is_numeric($value)) ? (float)$value : $value;
					$this->opts['series'][$index][$key] = $value;
		    }
		}
		return $this;
	}

	/**
	 * set_serie_option function.
	 * We are settings each serie options for graph
	 *
	 * @access public
	 * @param string $s_serie_name. (default: '')
	 * @param string $s_option. (default: '')
	 * @param string $value. (default: '')
	 * @return void
	 */
	public function set_serie_options($options = array(), $serie_name = '')
	{
		if ($serie_name AND count($options) > 0)
		{
			$index = $this->find_serie_name($serie_name);

			foreach ($options as $key => $opt)
			{
				$this->opts['series'][$index][$key] = $opt;
			}
		}
		return $this;
	}

	/**
	 * push_serie_data function.
	 *
	 * @access public
	 * @param string $s_serie_name. (default: '')
	 * @param string $s_value. (default: '')
	 * @return void
	 */
	public function push_serie_data($value = '', $serie_name = ''){

		if ($serie_name AND $value)
		{
			$index = $this->find_serie_name($serie_name);

			$value = (is_numeric($value)) ? (float)$value : $value;

			$this->opts['series'][$index]['data'][] = $value;
		}
		return $this;
	}

	/**
	 * find_serie_name function.
	 * fonction qui permet de savoir si une série existe
	 *
	 * @access private
	 * @return void
	 */
	private function find_serie_name($name)
	{
		$tot_indexes = count($this->opts['series']);

		if ($tot_indexes > 0)
		{
			foreach($this->opts['series'] as $index => $serie)
			{
				if (isset($serie['name']) AND strtolower($serie['name']) == strtolower($name))
				{
					return $index;
				}
			}
		}

		$this->opts['series'][$tot_indexes]['name'] = $name;

		return $tot_indexes;
	}

	/**
	 * push_categorie function.
	 * Add custom name to axes.
	 *
	 * @access public
	 * @param mixed $value
	 * @return void
	 */
	public function push_categorie($value, $axis = 'x')
	{
		if(trim($value)!= '') $this->opts[$axis.'Axis']['categories'][] = $value;

		return $this;
	}

	// AUTOMATIC DATABASE RENDERING
	/**
	 * from_result function.
	 *
	 * @access public
	 * @param array $data. (default: array())
	 * @return void
	 */
	public function from_result($data = array())
	{
		if (! isset($this->opts['series']))
		{
			$this->opts['series'] = array();
		}

		foreach ($data['data'] as $row)
		{
			if (isset($data['x_labels'])) $this->push_categorie($row->$data['x_labels'],'x');
			if (isset($data['y_labels'])) $this->push_categorie($row->$data['y_labels'],'y');

			foreach ($data['series'] as $name => $value)
			{
				// there is no options, juste assign name / value pair
				if (is_string($value))
				{
					$text = (is_string($name)) ? $name : $value;
					$dat  = $row->$value;
				}

				// options are passed
				else if (is_array($value))
				{
					if (isset($value['name']))
					{
						$text = $value['name'];
						unset($value['name']);
					}
					else
					{
						$text = $value['row'];
					}
					$dat = $row->{$value['row']};
					unset($value['row']);

					$this->set_serie_options($value, $text);
				}

				$this->push_serie_data($dat, $text);
			}
		}
		return $this;
	}

	/**
	 * add function.
	 * If options is a string, then the index of the current
	 * options to store it
	 *
	 * @access public
	 * @param array $options. (default: array())
	 * @return void
	 */
	public function add($options = array(), $clear = true)
	{
		if (count($this->global_opts) <= self::$chart_id AND ! empty($this->opts['series']))
		{
			if (is_string($options) AND trim($options) !== '')
			{
				$this->global_opts[$options] = $this->opts;
			}
			else
			{
				$this->global_opts[self::$chart_id] = (count($options)> 0) ? $options : $this->opts;
			}
		}

		self::$chart_id++;

		if ($clear === true) $this->clear();

		return $this;
	}

	/**
	 * get function.
	 * return the global options array as json string
	 *
	 * @access public
	 * @return void
	 */
	public function get($clear = true)
	{
		$this->add();

		foreach ($this->global_opts as $key => $opts)
		{
			$this->global_opts[$key] = $this->encode($opts);
		}

		return $this->process_get($this->global_opts, $clear, 'json');
	}

	/**
	 * get_array function.
	 * return the raw options array
	 *
	 * @access public
	 * @return void
	 */
	public function get_array($clear = true)
	{
		$this->add();

		return $this->process_get($this->global_opts, $clear, 'array');
	}

	/**
	 * encode function.
	 * Search and replace delimited functions by encode_function()
	 * We need to remove quotes from json string in order to
	 * make javascript function works.
	 *
	 * @access public
	 * @param mixed $options
	 * @return void
	 * JSON_UNESCAPED_UNICODE to change unicode javascript string
	 * Modify David Jonatan Tirado Reyes at 06, Dec 2016
	 */
	public function encode($options)
	{
		$options = str_replace('\\', '', json_encode($options, JSON_UNESCAPED_UNICODE));
		return str_replace($this->replace_keys, $this->orig_keys, $options);
	}

	/**
	 * process_get function.
	 * This functon send the output for get() and get_array().
	 * it will return an associative array if some global variables are defined.
	 *
	 * @access private
	 * @param mixed $options
	 * @param mixed $clear
	 * @return Json / Array
	 */
	private function process_get($options, $clear, $type)
	{
		if (count($this->shared_opts) > 0)
		{
			$global = ($type == 'json') ? $this->encode($this->shared_opts) : $this->shared_opts;

			$options = array('global' => $global, 'local' => $options);
		}

		if ($clear === true) $this->clear();

		return $options;
	}

	/**
	 * get_embed function.
	 * Return javascript embedable code and friend div
	 *
	 * @access public
	 * @return void
	 */
	public function render()
	{
		$this->add();

		$i = 1; $d = 1; $divs = '';

		$embed  = ''."\n";
		$embed .= $divs;

		$this->clear();

		return $embed;
	}

	/**
	 * clear function.
	 * clear instance properties. Very general at the moment, should only reset
	 * desired vars when lib will be finish
	 *
	 * @access public
	 * @return void
	 */
	public function clear($shared = false)
	{
		$this->opts = array();
		$this->opts['series'] = array();
		$this->opts['chart']['renderTo'] = 'hc_chart';
		$this->serie_index = 0;

		if ($shared === true) $this->shared_opts = array();

		return $this;
	}

	/**
	 * encode_functions function.
	 * We are looking for javascript functions and delimit them
	 *
	 * @access private
	 * @param mixed $array
	 * @return void
	 */
	private function encode_function($array = array())
	{
		if (is_string($array)) {
			$array = $this->delimit_function($array);
		}
		else {
			foreach($array as $key => $value) {
				if (is_array($value)) {
					$this->encode_function($value);
				}
				else {
					$array[$key] = $this->delimit_function($value);
				}
			}
		}
		return $array;
	}

	/**
	 * delimit_function function.
	 * 'Tag' javascript functions
	 *
	 * @access private
	 * @param string $string. (default: '')
	 * @return void
	 */
	private function delimit_function($string = '')
	{
		if(strpos($string, 'function(') !== false)
		{
    	  $this->orig_keys[] = $string;
    	  $string = '$$' . $string . '$$';
			  $this->replace_keys[] = '"' . $string . '"';
		}
		return $string;
	}

}


text:
killbill-adyen-plugin
=====================

Plugin to use [Adyen](https://www.adyen.com/home/) as a gateway.

Release builds are available on [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.kill-bill.billing.plugin.java%22%20AND%20a%3A%22adyen-plugin%22) with coordinates `org.kill-bill.billing.plugin.java:adyen-plugin`.

Kill Bill compatibility
-----------------------

| Plugin version | Kill Bill version |
| -------------: | ----------------: |
| 0.1.y          | 0.14.z            |
| 0.2.y          | 0.15.z            |
| 0.3.y          | 0.16.z            |
| 0.4.y          | 0.17.z            |
| 0.5.y          | 0.18.z            |

Requirements
------------

The plugin needs a database. The latest version of the schema can be found [here](https://github.com/killbill/killbill-adyen-plugin/blob/master/src/main/resources/ddl.sql).

Configuration
-------------

The following properties are required:

* `org.killbill.billing.plugin.adyen.merchantAccount`: your merchant account(s)
* `org.killbill.billing.plugin.adyen.username`: your username(s)
* `org.killbill.billing.plugin.adyen.password`: your password(s)
* `org.killbill.billing.plugin.adyen.paymentUrl`: SOAP Payment service url (i.e. `https://pal-test.adyen.com/pal/servlet/Payment/v12` or `https://pal-live.adyen.com/pal/servlet/Payment/v12`)

The following properties are optional:

* `org.killbill.billing.plugin.adyen.paymentConnectionTimeout`: Connection time-out in milliseconds for calls to Adyen SOAP Payment Service
* `org.killbill.billing.plugin.adyen.paymentReadTimeout`: Read time-out in milliseconds for calls to Adyen SOAP Payment Service
* `org.killbill.billing.plugin.adyen.recurringConnectionTimeout`: Connection time-out in milliseconds for calls to Adyen SOAP Recurring Service
* `org.killbill.billing.plugin.adyen.recurringReadTimeout`: Read time-out in milliseconds for calls to Adyen SOAP Recurring Service
* `org.killbill.billing.plugin.adyen.proxyServer`: Proxy server address
* `org.killbill.billing.plugin.adyen.proxyPort`: Proxy server port
* `org.killbill.billing.plugin.adyen.proxyType`: Proxy server type (HTTP or SOCKS)
* `org.killbill.billing.plugin.adyen.trustAllCertificates`: Whether to disable SSL certificates validation

Only needed for the Tests:

* `org.killbill.billing.plugin.adyen.recurringUrl`: SOAP Recurring Service URL (i.e. `https://pal-test.adyen.com/pal/servlet/Recurring/v12`)

The format for the merchant account(s), username(s) and password(s) is `XX#YY|XX#YY|...` where:

* `XX` is the country code (DE, FR, etc.)
* `YY` is the value (merchant account, username of the form `ws@Company.[YourCompanyAccount]` or password)

Notes:

* If you have a single country, omit the country code part
* If you have several merchant accounts per country, you can also specify:
  * `XX#YY` in the username property where `XX` is the merchant account
  * `XX#YY` in the password property where `XX` is the username
  * `XX#YY` in the skin property where `XX` is the merchant account
  * `XX#YY` in the hmac secret property where `XX` is the skin name

To configure Hosted Payment Pages (HPP):

* `org.killbill.billing.plugin.adyen.hpp.target`: host payment page url (e.g. https://test.adyen.com/hpp/pay.shtml)
* `org.killbill.billing.plugin.adyen.hmac.secret`: your hmac secret(s)
* `org.killbill.billing.plugin.adyen.skin`: you skin code(s)
* `org.killbill.billing.plugin.adyen.directoryUrl`: directory lookup url (e.g. https://test.adyen.com/hpp/directory.shtml)

The format for secrets and skins is the same as above if you support multiple countries.

These properties can be specified globally via System Properties or on a per tenant basis:

```
curl -v \
     -X POST \
     -u admin:password \
     -H 'X-Killbill-ApiKey: bob' \
     -H 'X-Killbill-ApiSecret: lazar' \
     -H 'X-Killbill-CreatedBy: admin' \
     -H 'Content-Type: text/plain' \
     -d 'org.killbill.billing.plugin.adyen.paymentUrl=WWW
org.killbill.billing.plugin.adyen.merchantAccount=XXX
org.killbill.billing.plugin.adyen.username=YYY
org.killbill.billing.plugin.adyen.password=ZZZ' \
     http://127.0.0.1:8080/1.0/kb/tenants/uploadPluginConfig/killbill-adyen
```

### Kill Bill

To avoid runtime errors (such as `ClassCastException`), starting Kill Bill with the System Property `com.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize=true` is recommended.

Usage
-----

A full end-to-end integration demo is also available [here](https://github.com/killbill/killbill-adyen-demo).

### Credit cards

Add a payment method:

```
curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     -H "X-Killbill-CreatedBy: demo" \
     -X POST \
     --data-binary '{
       "pluginName": "killbill-adyen",
       "pluginInfo": {
         "properties": [
           {
             "key": "ccLastName",
             "value": "KillBill"
           },
           {
             "key": "ccExpirationMonth",
             "value": 8
           },
           {
             "key": "ccExpirationYear",
             "value": 2018
           },
           {
             "key": "ccNumber",
             "value": 4111111111111111
           },
           {
             "key": "ccVerificationValue",
             "value": 737
           }
         ]
       }
     }' \
     "http://127.0.0.1:8080/1.0/kb/accounts/<ACCOUNT_ID>/paymentMethods?isDefault=true"
```

Notes:
* Make sure to replace *ACCOUNT_ID* with the id of the Kill Bill account
* Details for working payment methods are available here: https://www.adyen.com/home/support/knowledgebase/implementation-articles.html

To trigger a payment:

```
curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     -H "X-Killbill-CreatedBy: demo" \
     -X POST \
     --data-binary '{"transactionType":"AUTHORIZE","amount":"5","currency":"EUR","transactionExternalKey":"INV-'$(uuidgen)'-PURCHASE"}' \
    "http://127.0.0.1:8080/1.0/kb/accounts/<ACCOUNT_ID>/payments?pluginProperty=country=DE"
```

Notes:
* Make sure to replace *ACCOUNT_ID* with the id of the Kill Bill account
* The country plugin property will be used to retrieve your merchant account

At this point, the payment will be in *PENDING* state, until we receive a notification from Adyen. You can verify the state of the transaction by listing the payments:

```
curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     -H "X-Killbill-CreatedBy: demo" \
    "http://127.0.0.1:8080/1.0/kb/accounts/<ACCOUNT_ID>/payments?withPluginInfo=true"
```

You can simulate a notification from Adyen as follows:

```
curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     -H "X-Killbill-CreatedBy: demo" \
     -X POST \
     --data-binary '<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:Body>
    <ns1:sendNotification xmlns:ns1="http://notification.services.adyen.com">
      <ns1:notification>
        <live xmlns="http://notification.services.adyen.com">true</live>
        <notificationItems xmlns="http://notification.services.adyen.com">
          <NotificationRequestItem>
            <additionalData xsi:nil="true"/>
            <amount>
              <currency xmlns="http://common.services.adyen.com">EUR</currency>
              <value xmlns="http://common.services.adyen.com">2995</value>
            </amount>
            <eventCode>AUTHORISATION</eventCode>
            <eventDate>2013-04-15T06:59:22.278+02:00</eventDate>
            <merchantAccountCode>TestMerchant</merchantAccountCode>
            <merchantReference>325147059</merchantReference>
            <operations>
              <string>CANCEL</string>
              <string>CAPTURE</string>
              <string>REFUND</string>
            </operations>
            <originalReference xsi:nil="true"/>
            <paymentMethod>visa</paymentMethod>
            <pspReference>4823660019473428</pspReference>
            <reason>111647:7629:5/2014</reason>
            <success>true</success>
          </NotificationRequestItem>
        </notificationItems>
      </ns1:notification>
    </ns1:sendNotification>
  </soap:Body>
</soap:Envelope>' \
    "http://127.0.0.1:8080/1.0/kb/paymentGateways/notification/killbill-adyen"
```

Notes:
* Make sure to replace *pspReference* with the psp reference of your payment (see the *adyen_responses* table)
* If *success* is true, the payment transaction state will be *SUCCESS* and the payment state *AUTH_SUCCESS*
* If *success* is false, the payment transaction state will be *PAYMENT_FAILURE* and the payment state *AUTH_FAILED*

### SEPA

The APIs are similar to the Credit Card use-case. Here is an example payload for the add payment method call:

```
curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     -H "X-Killbill-CreatedBy: demo" \
     -X POST \
     --data-binary '{
       "pluginName": "killbill-adyen",
       "pluginInfo": {
         "properties": [
           {
             "key": "ddHolderName",
             "value": "A. Schneider"
           },
           {
             "key": "ddNumber",
             "value": "DE87123456781234567890"
           },
           {
             "key": "ddBic",
             "value": "TESTDE01XXX"
           }
         ]
       }
     }' \
     "http://127.0.0.1:8080/1.0/kb/accounts/<ACCOUNT_ID>/paymentMethods?isDefault=true"
```

### HPP

To generate an HPP url:

```
curl -v \
     -u admin:password \
     -H "X-Killbill-ApiKey: bob" \
     -H "X-Killbill-ApiSecret: lazar" \
     -H "Content-Type: application/json" \
     -H "X-Killbill-CreatedBy: demo" \
     -X POST \
     --data-binary '{
       "formFields": [
         {
           "key": "country",
           "value": "DE"
         },
         {
           "key": "serverUrl",
           "value": "http://killbill.io"
         },
         {
           "key": "resultUrl",
           "value": "?q=test+adyen+redirect+success"
         },
         {
           "key": "amount",
           "value": 10
         },
         {
           "key": "currency",
           "value": "USD"
         }
       ]
     }' \
     "http://127.0.0.1:8080/1.0/kb/paymentGateways/hosted/form/<ACCOUNT_ID>"
```

Notes:
* Make sure to replace *ACCOUNT_ID* with the id of the Kill Bill account
* *country* is used to retrieve the skin and the merchant account
* *customerLocale* (e.g. *es_CO*) can be used to specify Adyen's *countryCode* parameter (to override the filtering of payment methods based on IP address). This will also be used to specify the *shopperLocale* parameter
* *serverUrl* and *resultUrl* are used to redirect the user after the completion of the payment flow (success or failure)
* At this point, no payment has been created in Kill Bill. The payment will be recorded when processing the notification

### Recurring

For [Adyen's Recurring Functionality](https://docs.adyen.com/display/TD/Recurring+Manual) the following recurring types are provided (see [RecurringType.java](https://github.com/killbill/killbill-adyen-plugin/blob/master/src/main/java/org/killbill/billing/plugin/adyen/client/model/RecurringType.java))
* `ONECLICK`
* `RECURRING`

There are 3 different use cases:

1. Use Adyen's recurring payments feature with contract `RECURRING`: CVV is not required (it's an implicit `contAuth`)
2. Use Adyen's recurring payment feature with contract `ONECLICK`: CVV is always required
3. Use you own card-on-file system + `contAuth` to simulate option 1. Instead of providing Adyen's `recurringDetailId`, the merchant retrieves stored payment data from its store and populates the fields like a normal payment request. `contAuth` is needed to turn Adyen's (not needed) validations off.

Plugin properties
-----------------

| Key                      | Description                                   |
| -----------------------: | :-------------------------------------------- |
| ccNumber                 | Credit card number                            |
| ccType                   | Credit card brand                             |
| ccFirstName              | Credit card holder first name                 |
| ccLastName               | Credit card holder last name                  |
| ccExpirationMonth        | Credit card expiration month                  |
| ccExpirationYear         | Credit card expiration year                   |
| ccStartMonth             | Credit card start month                       |
| ccStartYear              | Credit card start year                        |
| ccVerificationValue      | CVC/CVV/CVN                                   |
| encryptedJson            | Encrypted JSON (EE)                           |
| dccAmount                | Payable amount                                |
| dccCurrency              | The three-character ISO currency code         |
| ddNumber                 | Direct Debit card number                      |
| ddHolderName             | Direct Debit holder name                      |
| ddBic                    | Direct Debit bank identification code (SEPA)  |
| ddBlz                    | Direct Debit Bankleitzahl (ELV)               |
| email                    | Purchaser email                               |
| address1                 | Billing address first line                    |
| address2                 | Billing address second line                   |
| city                     | Billing address city                          |
| zip                      | Billing address zip code                      |
| state                    | Billing address state                         |
| country                  | Billing address country                       |
| PaReq                    | 3D-Secure Pa Request                          |
| PaRes                    | 3D-Secure Pa Response                         |
| MD                       | 3D-Secure Message Digest                      |
| TermUrl                  | 3D-Secure Term URL                            |
| threeDThreshold          | Minimum amount for triggering 3D-Secure       |
| userAgent                | User-Agent for 3D-Secure Browser Info         |
| acceptHeader             | Accept-Header for 3D-Secure Browser Info      |
| contAuth                 | Continuous authentication enabled (boolean)   |
| recurringDetailId        | ID of payment details stored at Adyen         |
| recurringType            | Contract to be used for Recurring             |
| createPendingPayment     | Whether to create a PENDING payment for HPP   |
| authMode                 | Create an auth instead of purchase for HPP    |
| paymentExternalKey       | HPP payment external key                      |
| acquirer                 | Value of Adyen's acquirerCode field           |
| acquirerMID              | Value of Adyen's authorisationMid field       |
| selectedBrand            | Value of Adyen's selectedBrand field          |
| lookupDirectory          | If true, query the directory (HPP flow)       |