text:
namespace occa {
  //---[ Helper Functions ]-----------
  namespace cl {
    cl_device_type deviceType(int type){
      cl_device_type ret = 0;

      if(type & occa::CPU)     ret |= CL_DEVICE_TYPE_CPU;
      if(type & occa::GPU)     ret |= CL_DEVICE_TYPE_GPU;
      if(type & occa::FPGA)    ret |= CL_DEVICE_TYPE_ACCELERATOR;
      if(type & occa::XeonPhi) ret |= CL_DEVICE_TYPE_ACCELERATOR;

      return ret;
    }

    int platformCount(){
      cl_uint platformCount;

      OCCA_CL_CHECK("OpenCL: Get Platform ID Count",
                    clGetPlatformIDs(0, NULL, &platformCount));

      return platformCount;
    }

    cl_platform_id platformID(int pID){
      cl_platform_id *platforms = new cl_platform_id[pID + 1];

      OCCA_CL_CHECK("OpenCL: Get Platform ID",
                    clGetPlatformIDs(pID + 1, platforms, NULL));

      cl_platform_id ret = platforms[pID];

      delete [] platforms;

      return ret;
    }

    int deviceCount(int type){
      int pCount = cl::platformCount();
      int ret = 0;

      for(int p = 0; p < pCount; ++p)
        ret += deviceCountInPlatform(p, type);

      return ret;
    }

    int deviceCountInPlatform(int pID, int type){
      cl_uint dCount;

      cl_platform_id clPID = platformID(pID);

      OCCA_CL_CHECK("OpenCL: Get Device ID Count",
                    clGetDeviceIDs(clPID,
                                   deviceType(type),
                                   0, NULL, &dCount));

      return dCount;
    }

    cl_device_id deviceID(int pID, int dID, int type){
      cl_device_id *devices = new cl_device_id[dID + 1];

      cl_platform_id clPID = platformID(pID);

      OCCA_CL_CHECK("OpenCL: Get Device ID Count",
                    clGetDeviceIDs(clPID,
                                   deviceType(type),
                                   dID + 1, devices, NULL));

      cl_device_id ret = devices[dID];

      delete [] devices;

      return ret;
    }

    std::string deviceStrInfo(cl_device_id clDID,
                              cl_device_info clInfo){
      size_t bytes;

      OCCA_CL_CHECK("OpenCL: Getting Device String Info",
                    clGetDeviceInfo(clDID,
                                    clInfo,
                                    0, NULL, &bytes));

      char *buffer  = new char[bytes + 1];
      buffer[bytes] = '\0';

      OCCA_CL_CHECK("OpenCL: Getting Device String Info",
                    clGetDeviceInfo(clDID,
                                    clInfo,
                                    bytes, buffer, NULL));

      std::string ret = buffer;

      delete [] buffer;

      size_t firstNS = ret.size();
      size_t lastNS  = ret.size();

      size_t i;

      for(i = 0; i < ret.size(); ++i){
        if((ret[i] != ' ') &&
           (ret[i] != '\t') &&
           (ret[i] != '\n')){
          firstNS = i;
          break;
        }
      }

      if(i == ret.size())
        return "";

      for(i = (ret.size() - 1); i > firstNS; --i){
        if((ret[i] != ' ') &&
           (ret[i] != '\t') &&
           (ret[i] != '\n')){
          lastNS = i;
          break;
        }
      }

      if(i == firstNS)
        return "";

      return ret.substr(firstNS, (lastNS - firstNS + 1));
    }

    std::string deviceName(int pID, int dID){
      cl_device_id clDID = deviceID(pID, dID);

      return deviceStrInfo(clDID, CL_DEVICE_NAME);
    }

    int deviceType(int pID, int dID){
      cl_device_id clDID = deviceID(pID, dID);
      int ret = 0;

      cl_device_type clDeviceType;

      OCCA_CL_CHECK("OpenCL: Get Device Type",
                    clGetDeviceInfo(clDID,
                                    CL_DEVICE_TYPE,
                                    sizeof(clDeviceType), &clDeviceType, NULL));

      if(clDeviceType & CL_DEVICE_TYPE_CPU)
        ret |= occa::CPU;
      else if(clDeviceType & CL_DEVICE_TYPE_GPU)
        ret |= occa::GPU;

      return ret;
    }

    int deviceVendor(int pID, int dID){
      cl_device_id clDID = deviceID(pID, dID);
      int ret = 0;

      std::string vendor = deviceStrInfo(clDID, CL_DEVICE_VENDOR);

      if(vendor.find("AMD")                    != std::string::npos ||
         vendor.find("Advanced Micro Devices") != std::string::npos ||
         vendor.find("ATI")                    != std::string::npos)
        ret |= occa::AMD;

      else if(vendor.find("Intel") != std::string::npos)
        ret |= occa::Intel;

      else if(vendor.find("Altera") != std::string::npos)
        ret |= occa::Altera;

      else if(vendor.find("Nvidia") != std::string::npos ||
              vendor.find("NVIDIA") != std::string::npos)
        ret |= occa::NVIDIA;

      return ret;
    }

    int deviceCoreCount(int pID, int dID){
      cl_device_id clDID = deviceID(pID, dID);
      cl_uint ret;

      OCCA_CL_CHECK("OpenCL: Get Device Core Count",
                    clGetDeviceInfo(clDID,
                                    CL_DEVICE_MAX_COMPUTE_UNITS,
                                    sizeof(ret), &ret, NULL));

      return ret;
    }

    std::string getDeviceListInfo(){
      std::stringstream ss;

      int platformCount = occa::cl::platformCount();

      for(int pID = 0; pID < platformCount; ++pID){
        int deviceCount = occa::cl::deviceCountInPlatform(pID);

        for(int dID = 0; dID < deviceCount; ++dID){
          if(pID || dID){
            ss << "              |-----------------------+------------------------------------------\n"
               << "              |  Device Name          | " << deviceName(pID, dID)            << '\n';
          }
          else{
            ss << "    OpenCL    |  Device Name          | " << deviceName(pID, dID)            << '\n';
          }

          ss << "              |  Driver Vendor        | " << occa::vendor(deviceVendor(pID,dID)) << '\n'
             << "              |  Platform ID          | " << pID                                 << '\n'
             << "              |  Device ID            | " << dID                                 << '\n';
        }
      }

      return ss.str();
    }

    void buildKernelFromSource(OpenCLKernelData_t &data_,
                               const char *content,
                               const size_t contentBytes,
                               const std::string &functionName,
                               const std::string &flags,
                               const std::string &hash,
                               const std::string &sourceFile){
      cl_int error;

      data_.program = clCreateProgramWithSource(data_.context, 1,
                                                (const char **) &content,
                                                &contentBytes,
                                                &error);

      if(error && hash.size())
        releaseHash(hash, 0);

      if(verboseCompilation_f){
        if(hash.size()){
          std::cout << "OpenCL compiling " << functionName
                    << " from [" << sourceFile << "]";

          if(flags.size())
            std::cout << " with flags [" << flags << "]";

          std::cout << '\n';
        }
        else
          std::cout << "OpenCL compiling " << functionName << " from [Library]\n";
      }

      OCCA_CL_CHECK("Kernel (" + functionName + ") : Constructing Program", error);

      error = clBuildProgram(data_.program,
                             1, &data_.deviceID,
                             flags.c_str(),
                             NULL, NULL);

      if(error){
        cl_int error;
        char *log;
        uintptr_t logSize;

        clGetProgramBuildInfo(data_.program, data_.deviceID, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);

        if(logSize > 2){
          log = new char[logSize+1];

          error = clGetProgramBuildInfo(data_.program, data_.deviceID, CL_PROGRAM_BUILD_LOG, logSize, log, NULL);
          OCCA_CL_CHECK("Kernel (" + functionName + ") : Building Program", error);
          log[logSize] = '\0';

          printf("Kernel (%s): Build Log\n%s", functionName.c_str(), log);

          delete[] log;
        }

        if(hash.size())
          releaseHash(hash, 0);
      }

      OCCA_CL_CHECK("Kernel (" + functionName + ") : Building Program", error);

      data_.kernel = clCreateKernel(data_.program, functionName.c_str(), &error);

      if(error && hash.size())
        releaseHash(hash, 0);

      OCCA_CL_CHECK("Kernel (" + functionName + "): Creating Kernel", error);

      if(verboseCompilation_f){
        if(sourceFile.size()){
          std::cout << "OpenCL compiled " << functionName << " from [" << sourceFile << "]";

          if(flags.size())
            std::cout << " with flags [" << flags << "]";

          std::cout << '\n';
        }
        else
          std::cout << "OpenCL compiled " << functionName << " from [Library]\n";
      }
    }

    void buildKernelFromBinary(OpenCLKernelData_t &data_,
                               const unsigned char *content,
                               const size_t contentBytes,
                               const std::string &functionName,
                               const std::string &flags){
      cl_int error, binaryError;

      data_.program = clCreateProgramWithBinary(data_.context,
                                                1, &(data_.deviceID),
                                                &contentBytes,
                                                (const unsigned char**) &content,
                                                &binaryError, &error);

      OCCA_CL_CHECK("Kernel (" + functionName + ") : Constructing Program", binaryError);
      OCCA_CL_CHECK("Kernel (" + functionName + ") : Constructing Program", error);

      error = clBuildProgram(data_.program,
                             1, &data_.deviceID,
                             flags.c_str(),
                             NULL, NULL);

      if(error){
        cl_int error;
        char *log;
        uintptr_t logSize;

        clGetProgramBuildInfo(data_.program, data_.deviceID, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);

        if(logSize > 2){
          log = new char[logSize+1];

          error = clGetProgramBuildInfo(data_.program, data_.deviceID, CL_PROGRAM_BUILD_LOG, logSize, log, NULL);
          OCCA_CL_CHECK("Kernel (" + functionName + ") : Building Program", error);
          log[logSize] = '\0';

          printf("Kernel (%s): Build Log\n%s", functionName.c_str(), log);

          delete[] log;
        }
      }

      OCCA_CL_CHECK("Kernel (" + functionName + ") : Building Program", error);

      data_.kernel = clCreateKernel(data_.program, functionName.c_str(), &error);
      OCCA_CL_CHECK("Kernel (" + functionName + "): Creating Kernel", error);
    }

    void saveProgramBinary(OpenCLKernelData_t &data_,
                           const std::string &binaryFile,
                           const std::string &hash){
      size_t binarySize;
      char *binary;

      cl_int error = clGetProgramInfo(data_.program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binarySize, NULL);

      if(error && hash.size())
        releaseHash(hash, 0);

      OCCA_CL_CHECK("saveProgramBinary: Getting Binary Sizes", error);

      binary = new char[binarySize + 1];

      error = clGetProgramInfo(data_.program, CL_PROGRAM_BINARIES, sizeof(char*), &binary, NULL);

      if(error && hash.size())
        releaseHash(hash, 0);

      OCCA_CL_CHECK("saveProgramBinary: Getting Binary", error);

      FILE *fp = fopen(binaryFile.c_str(), "wb");
      fwrite(binary, 1, binarySize, fp);
      fclose(fp);

      delete [] binary;
    }

    occa::device wrapDevice(cl_platform_id platformID,
                            cl_device_id deviceID,
                            cl_context context){
      occa::device dev;
      device_t<OpenCL> &dHandle   = *(new device_t<OpenCL>());
      OpenCLDeviceData_t &devData = *(new OpenCLDeviceData_t);

      dev.dHandle = &dHandle;

      //---[ Setup ]----------
      dHandle.data = &devData;

      devData.platform = -1;
      devData.device   = -1;

      devData.platformID = platformID;
      devData.deviceID   = deviceID;
      devData.context    = context;
      //======================

      dHandle.modelID_ = library::deviceModelID(dHandle.getIdentifier());
      dHandle.id_      = library::genDeviceID();

      dHandle.currentStream = dHandle.createStream();

      return dev;
    }

    bool imageFormatIsSupported(cl_image_format &f,
                                cl_image_format *fs,
                                const int formatCount){

      for(int i = 0; i < formatCount; ++i){
        cl_image_format &f2 = fs[i];

        const bool orderSupported = (f.image_channel_order ==
                                     (f.image_channel_order &
                                      f2.image_channel_order));

        const bool typeSupported = (f.image_channel_data_type ==
                                    (f.image_channel_data_type &
                                     f2.image_channel_data_type));

        if(orderSupported && typeSupported)
          return true;
      }

      return false;
    }

    void printImageFormat(cl_image_format &imageFormat){
      std::cout << "---[ OpenCL Image Format ]--------------\n"
                << "Supported Channel Formats:\n";

#define OCCA_CL_PRINT_CHANNEL_INFO(X) \
      if(imageFormat.image_channel_order & X) std::cout << "  " #X "\n"

      OCCA_CL_PRINT_CHANNEL_INFO(CL_R);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_Rx);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_A);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_INTENSITY);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_RG);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_RGx);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_RA);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_RGB);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_RGBx);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_RGBA);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_ARGB);
      OCCA_CL_PRINT_CHANNEL_INFO(CL_BGRA);

#undef OCCA_CL_PRINT_CHANNEL_INFO

      std::cout << "\nSupported Channel Types:\n";

#define OCCA_CL_PRINT_CHANNEL_TYPE(X) \
      if(imageFormat.image_channel_data_type & X) std::cout << "  " #X "\n"

      OCCA_CL_PRINT_CHANNEL_TYPE(CL_SNORM_INT8);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_SNORM_INT16);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_UNORM_INT8);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_UNORM_INT16);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_UNORM_SHORT_565);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_UNORM_SHORT_555);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_UNORM_INT_101010);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_SIGNED_INT8);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_SIGNED_INT16);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_SIGNED_INT32);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_UNSIGNED_INT8);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_UNSIGNED_INT16);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_UNSIGNED_INT32);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_HALF_FLOAT);
      OCCA_CL_PRINT_CHANNEL_TYPE(CL_FLOAT);

#undef OCCA_CL_PRINT_CHANNEL_TYPE

      std::cout << "========================================\n";
    }
  };

  const cl_channel_type clFormats[8] = {CL_UNSIGNED_INT8,
                                        CL_UNSIGNED_INT16,
                                        CL_UNSIGNED_INT32,
                                        CL_SIGNED_INT8,
                                        CL_SIGNED_INT16,
                                        CL_SIGNED_INT32,
                                        CL_HALF_FLOAT,
                                        CL_FLOAT};

  template <>
  void* formatType::format<occa::OpenCL>() const {
    return ((void*) &(clFormats[format_]));
  }
  //==================================

  //---[ Kernel ]---------------------
  template <>
  kernel_t<OpenCL>::kernel_t(){
    strMode = "OpenCL";

    data    = NULL;
    dHandle = NULL;

    dims  = 1;
    inner = occa::dim(1,1,1);
    outer = occa::dim(1,1,1);

    nestedKernelCount = 0;

    maximumInnerDimSize_ = 0;
    preferredDimSize_    = 0;
  }

  template <>
  kernel_t<OpenCL>::kernel_t(const kernel_t<OpenCL> &k){
    data    = k.data;
    dHandle = k.dHandle;

    metaInfo = k.metaInfo;

    dims  = k.dims;
    inner = k.inner;
    outer = k.outer;

    nestedKernelCount = k.nestedKernelCount;

    if(0 < nestedKernelCount){
      nestedKernels = new kernel[nestedKernelCount];

      for(int i = 0; i < nestedKernelCount; ++i)
        nestedKernels[i] = k.nestedKernels[i];
    }

    maximumInnerDimSize_ = k.maximumInnerDimSize_;
    preferredDimSize_    = k.preferredDimSize_;
  }

  template <>
  kernel_t<OpenCL>& kernel_t<OpenCL>::operator = (const kernel_t<OpenCL> &k){
    data    = k.data;
    dHandle = k.dHandle;

    metaInfo = k.metaInfo;

    dims  = k.dims;
    inner = k.inner;
    outer = k.outer;

    nestedKernelCount = k.nestedKernelCount;

    if(0 < nestedKernelCount){
      nestedKernels = new kernel[nestedKernelCount];

      for(int i = 0; i < nestedKernelCount; ++i)
        nestedKernels[i] = k.nestedKernels[i];
    }

    maximumInnerDimSize_ = k.maximumInnerDimSize_;
    preferredDimSize_    = k.preferredDimSize_;

    return *this;
  }

  template <>
  kernel_t<OpenCL>::~kernel_t(){}

  template <>
  std::string kernel_t<OpenCL>::fixBinaryName(const std::string &filename){
    return filename;
  }

  template <>
  kernel_t<OpenCL>* kernel_t<OpenCL>::buildFromSource(const std::string &filename,
                                                      const std::string &functionName,
                                                      const kernelInfo &info_){

    name = functionName;

    OCCA_EXTRACT_DATA(OpenCL, Kernel);

    kernelInfo info = info_;

    dHandle->addOccaHeadersToInfo(info);

    const std::string hash = getFileContentHash(filename,
                                                dHandle->getInfoSalt(info));

    const std::string hashDir    = hashDirFor(filename, hash);
    const std::string sourceFile = hashDir + kc::sourceFile;
    const std::string binaryFile = hashDir + fixBinaryName(kc::binaryFile);

    if(!haveHash(hash, 0)){
      waitForHash(hash, 0);

      if(verboseCompilation_f)
        std::cout << "Found cached binary of [" << compressFilename(filename) << "] in [" << compressFilename(binaryFile) << "]\n";

      return buildFromBinary(binaryFile, functionName);
    }

    if(sys::fileExists(binaryFile)){
      releaseHash(hash, 0);

      if(verboseCompilation_f)
        std::cout << "Found cached binary of [" << compressFilename(filename) << "] in [" << compressFilename(binaryFile) << "]\n";

      return buildFromBinary(binaryFile, functionName);
    }

    createSourceFileFrom(filename, hashDir, info);

    std::string cFunction = readFile(sourceFile);

    std::string catFlags = info.flags + dHandle->compilerFlags;

    cl::buildKernelFromSource(data_,
                              cFunction.c_str(), cFunction.size(),
                              functionName,
                              catFlags,
                              hash, sourceFile);

    cl::saveProgramBinary(data_, binaryFile, hash);

    releaseHash(hash, 0);

    return this;
  }

  template <>
  kernel_t<OpenCL>* kernel_t<OpenCL>::buildFromBinary(const std::string &filename,
                                                      const std::string &functionName){

    name = functionName;

    OCCA_EXTRACT_DATA(OpenCL, Kernel);

    std::string cFile = readFile(filename);

    cl::buildKernelFromBinary(data_,
                              (const unsigned char*) cFile.c_str(),
                              cFile.size(),
                              functionName,
                              dHandle->compilerFlags);

    return this;
  }

  template <>
  kernel_t<OpenCL>* kernel_t<OpenCL>::loadFromLibrary(const char *cache,
                                                      const std::string &functionName){
    OCCA_EXTRACT_DATA(OpenCL, Kernel);

    cl::buildKernelFromSource(data_,
                              cache, strlen(cache),
                              functionName);

    return this;
  }

  template <>
  uintptr_t kernel_t<OpenCL>::maximumInnerDimSize(){
    if(maximumInnerDimSize_)
      return maximumInnerDimSize_;

    OCCA_EXTRACT_DATA(OpenCL, Kernel);

    size_t pds;

    OCCA_CL_CHECK("Kernel: Getting Preferred Dim Size",
                  clGetKernelWorkGroupInfo(data_.kernel,
                                           data_.deviceID,
                                           CL_KERNEL_WORK_GROUP_SIZE,
                                           sizeof(size_t), &pds, NULL));

    maximumInnerDimSize_ = (uintptr_t) pds;

    return maximumInnerDimSize_;
  }

  template <>
  int kernel_t<OpenCL>::preferredDimSize(){
    if(preferredDimSize_)
      return preferredDimSize_;

    OCCA_EXTRACT_DATA(OpenCL, Kernel);

    size_t pds;

    OCCA_CL_CHECK("Kernel: Getting Preferred Dim Size",
                  clGetKernelWorkGroupInfo(data_.kernel,
                                           data_.deviceID,
                                           CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE,
                                           sizeof(size_t), &pds, NULL));

    preferredDimSize_ = (uintptr_t) pds;

    return preferredDimSize_;
  }

#include "operators/occaOpenCLKernelOperators.cpp"

  template <>
  void kernel_t<OpenCL>::free(){
    OCCA_EXTRACT_DATA(OpenCL, Kernel);

    OCCA_CL_CHECK("Kernel: Free",
                  clReleaseKernel(data_.kernel));
  }
  //==================================

  //---[ Memory ]---------------------
  template <>
  memory_t<OpenCL>::memory_t(){
    strMode = "OpenCL";

    memInfo = memFlag::none;

    handle    = NULL;
    mappedPtr = NULL;
    uvaPtr    = NULL;

    dHandle = NULL;
    size = 0;

    textureInfo.dim = 1;
    textureInfo.w = textureInfo.h = textureInfo.d = 0;
  }

  template <>
  memory_t<OpenCL>::memory_t(const memory_t<OpenCL> &m){
    *this = m;
  }

  template <>
  memory_t<OpenCL>& memory_t<OpenCL>::operator = (const memory_t<OpenCL> &m){
    memInfo = m.memInfo;

    handle    = m.handle;
    mappedPtr = m.mappedPtr;
    uvaPtr    = m.uvaPtr;

    dHandle = m.dHandle;
    size    = m.size;

    textureInfo.dim = m.textureInfo.dim;

    textureInfo.w = m.textureInfo.w;
    textureInfo.h = m.textureInfo.h;
    textureInfo.d = m.textureInfo.d;

    return *this;
  }

  template <>
  memory_t<OpenCL>::~memory_t(){}

  template <>
  void* memory_t<OpenCL>::getMemoryHandle(){
    return handle;
  }

  template <>
  void* memory_t<OpenCL>::getTextureHandle(){
    return textureInfo.arg;
  }

  template <>
  void memory_t<OpenCL>::copyFrom(const void *src,
                                  const uintptr_t bytes,
                                  const uintptr_t offset){
    cl_command_queue &stream = *((cl_command_queue*) dHandle->currentStream);

    const uintptr_t bytes_ = (bytes == 0) ? size : bytes;

    OCCA_CHECK((bytes_ + offset) <= size,
               "Memory has size [" << size << "],"
               << "trying to access [ " << offset << " , " << (offset + bytes_) << " ]");

    if(!isATexture())
      OCCA_CL_CHECK("Memory: Copy From",
                    clEnqueueWriteBuffer(stream, *((cl_mem*) handle),
                                         CL_TRUE,
                                         offset, bytes_, src,
                                         0, NULL, NULL));
    else{
      const int bie = textureInfo.bytesInEntry;

      size_t offset_[3] = {      (offset / bie)      % textureInfo.w , 0, 0};
      size_t pixels_[3] = {1 + (((bytes_ / bie) - 1) % textureInfo.w), 1, 1};

      if(textureInfo.dim == 2){
        offset_[1] = (offset / bie) / textureInfo.w;
        pixels_[1] = (bytes_ / bie) / textureInfo.w;
      }

      OCCA_CL_CHECK("Texture Memory: Copy From",
                    clEnqueueWriteImage(stream, *((cl_mem*) handle),
                                        CL_TRUE,
                                        offset_, pixels_,
                                        0, 0,
                                        src,
                                        0, NULL, NULL));
    }
  }

  template <>
  void memory_t<OpenCL>::copyFrom(const memory_v *src,
                                  const uintptr_t bytes,
                                  const uintptr_t destOffset,
                                  const uintptr_t srcOffset){
    cl_command_queue &stream = *((cl_command_queue*) dHandle->currentStream);

    const uintptr_t bytes_ = (bytes == 0) ? size : bytes;

    OCCA_CHECK((bytes_ + destOffset) <= size,
               "Memory has size [" << size << "],"
               << "trying to access [ " << destOffset << " , " << (destOffset + bytes_) << " ]");

    OCCA_CHECK((bytes_ + srcOffset) <= src->size,
               "Source has size [" << src->size << "],"
               << "trying to access [ " << srcOffset << " , " << (srcOffset + bytes_) << " ]");

    if(!isATexture())
      OCCA_CL_CHECK("Memory: Copy From",
                    clEnqueueCopyBuffer(stream,
                                        *((cl_mem*) src->handle),
                                        *((cl_mem*) handle),
                                        srcOffset, destOffset,
                                        bytes_,
                                        0, NULL, NULL));
    else
      OCCA_CL_CHECK("Texture Memory: Copy From",
                    clEnqueueCopyBuffer(stream,
                                        *((cl_mem*) src->handle),
                                        *((cl_mem*) handle),
                                        srcOffset, destOffset,
                                        bytes_,
                                        0, NULL, NULL));
  }

  template <>
  void memory_t<OpenCL>::copyTo(void *dest,
                                const uintptr_t bytes,
                                const uintptr_t offset){
    const cl_command_queue &stream = *((cl_command_queue*) dHandle->currentStream);

    const uintptr_t bytes_ = (bytes == 0) ? size : bytes;

    OCCA_CHECK((bytes_ + offset) <= size,
               "Memory has size [" << size << "],"
               << "trying to access [ " << offset << " , " << (offset + bytes_) << " ]");

    if(!isATexture())
      OCCA_CL_CHECK("Memory: Copy To",
                    clEnqueueReadBuffer(stream, *((cl_mem*) handle),
                                        CL_TRUE,
                                        offset, bytes_, dest,
                                        0, NULL, NULL));
    else{
      const int bie = textureInfo.bytesInEntry;

      size_t offset_[3] = {      (offset / bie)      % textureInfo.w , 0, 0};
      size_t pixels_[3] = {1 + (((bytes_ / bie) - 1) % textureInfo.w), 1, 1};

      if(textureInfo.dim == 2){
        offset_[1] = (offset / bie) / textureInfo.w;
        pixels_[1] = (bytes_ / bie) / textureInfo.w;
      }

      OCCA_CL_CHECK("Texture Memory: Copy From",
                    clEnqueueReadImage(stream, *((cl_mem*) handle),
                                       CL_TRUE,
                                       offset_, pixels_,
                                       0, 0,
                                       dest,
                                       0, NULL, NULL));
    }
  }

  template <>
  void memory_t<OpenCL>::copyTo(memory_v *dest,
                                const uintptr_t bytes,
                                const uintptr_t destOffset,
                                const uintptr_t srcOffset){
    const cl_command_queue &stream = *((cl_command_queue*) dHandle->currentStream);

    const uintptr_t bytes_ = (bytes == 0) ? size : bytes;

    OCCA_CHECK((bytes_ + srcOffset) <= size,
               "Memory has size [" << size << "],"
               << "trying to access [ " << srcOffset << " , " << (srcOffset + bytes_) << " ]");

    OCCA_CHECK((bytes_ + destOffset) <= dest->size,
               "Destination has size [" << dest->size << "],"
               << "trying to access [ " << destOffset << " , " << (destOffset + bytes_) << " ]");

    if(!isATexture())
      OCCA_CL_CHECK("Memory: Copy To",
                    clEnqueueCopyBuffer(stream,
                                        *((cl_mem*) handle),
                                        *((cl_mem*) dest->handle),
                                        srcOffset, destOffset,
                                        bytes_,
                                        0, NULL, NULL));
    else
      OCCA_CL_CHECK("Texture Memory: Copy To",
                    clEnqueueCopyBuffer(stream,
                                        *((cl_mem*) handle),
                                        *((cl_mem*) dest->handle),
                                        srcOffset, destOffset,
                                        bytes_,
                                        0, NULL, NULL));
  }

  template <>
  void memory_t<OpenCL>::asyncCopyFrom(const void *src,
                                       const uintptr_t bytes,
                                       const uintptr_t offset){
    const cl_command_queue &stream = *((cl_command_queue*) dHandle->currentStream);

    const uintptr_t bytes_ = (bytes == 0) ? size : bytes;

    OCCA_CHECK((bytes_ + offset) <= size,
               "Memory has size [" << size << "],"
               << "trying to access [ " << offset << " , " << (offset + bytes_) << " ]");

    if(!isATexture())
      OCCA_CL_CHECK("Memory: Asynchronous Copy From",
                    clEnqueueWriteBuffer(stream, *((cl_mem*) handle),
                                         CL_FALSE,
                                         offset, bytes_, src,
                                         0, NULL, NULL));
    else
      OCCA_CL_CHECK("Texture Memory: Asynchronous Copy From",
                    clEnqueueWriteBuffer(stream, *((cl_mem*) handle),
                                         CL_FALSE,
                                         offset, bytes_, src,
                                         0, NULL, NULL));
  }

  template <>
  void memory_t<OpenCL>::asyncCopyFrom(const memory_v *src,
                                       const uintptr_t bytes,
                                       const uintptr_t destOffset,
                                       const uintptr_t srcOffset){
    const cl_command_queue &stream = *((cl_command_queue*) dHandle->currentStream);

    const uintptr_t bytes_ = (bytes == 0) ? size : bytes;

    OCCA_CHECK((bytes_ + destOffset) <= size,
               "Memory has size [" << size << "],"
               << "trying to access [ " << destOffset << " , " << (destOffset + bytes_) << " ]");

    OCCA_CHECK((bytes_ + srcOffset) <= src->size,
               "Source has size [" << src->size << "],"
               << "trying to access [ " << srcOffset << " , " << (srcOffset + bytes_) << " ]");

    if(!isATexture())
      OCCA_CL_CHECK("Memory: Asynchronous Copy From",
                    clEnqueueCopyBuffer(stream,
                                        *((cl_mem*) src->handle),
                                        *((cl_mem*) handle),
                                        srcOffset, destOffset,
                                        bytes_,
                                        0, NULL, NULL));
    else
      OCCA_CL_CHECK("Texture Memory: Asynchronous Copy From",
                    clEnqueueCopyBuffer(stream,
                                        *((cl_mem*) src->handle),
                                        *((cl_mem*) handle),
                                        srcOffset, destOffset,
                                        bytes_,
                                        0, NULL, NULL));
  }

  template <>
  void memory_t<OpenCL>::asyncCopyTo(void *dest,
                                     const uintptr_t bytes,
                                     const uintptr_t offset){
    const cl_command_queue &stream = *((cl_command_queue*) dHandle->currentStream);

    const uintptr_t bytes_ = (bytes == 0) ? size : bytes;

    OCCA_CHECK((bytes_ + offset) <= size,
               "Memory has size [" << size << "],"
               << "trying to access [ " << offset << " , " << (offset + bytes_) << " ]");

    if(!isATexture())
      OCCA_CL_CHECK("Memory: Asynchronous Copy To",
                    clEnqueueReadBuffer(stream, *((cl_mem*) handle),
                                        CL_FALSE,
                                        offset, bytes_, dest,
                                        0, NULL, NULL));
    else
      OCCA_CL_CHECK("Texture Memory: Asynchronous Copy To",
                    clEnqueueReadBuffer(stream, *((cl_mem*) handle),
                                        CL_FALSE,
                                        offset, bytes_, dest,
                                        0, NULL, NULL));
  }

  template <>
  void memory_t<OpenCL>::asyncCopyTo(memory_v *dest,
                                     const uintptr_t bytes,
                                     const uintptr_t destOffset,
                                     const uintptr_t srcOffset){
    const cl_command_queue &stream = *((cl_command_queue*) dHandle->currentStream);

    const uintptr_t bytes_ = (bytes == 0) ? size : bytes;

    OCCA_CHECK((bytes_ + srcOffset) <= size,
               "Memory has size [" << size << "],"
               << "trying to access [ " << srcOffset << " , " << (srcOffset + bytes_) << " ]");

    OCCA_CHECK((bytes_ + destOffset) <= dest->size,
               "Destination has size [" << dest->size << "],"
               << "trying to access [ " << destOffset << " , " << (destOffset + bytes_) << " ]");

    if(!isATexture())
      OCCA_CL_CHECK("Memory: Asynchronous Copy To",
                    clEnqueueCopyBuffer(stream,
                                        *((cl_mem*) handle),
                                        *((cl_mem*) dest->handle),
                                        srcOffset, destOffset,
                                        bytes_,
                                        0, NULL, NULL));
    else
      OCCA_CL_CHECK("Texture Memory: Asynchronous Copy To",
                    clEnqueueCopyBuffer(stream,
                                        *((cl_mem*) handle),
                                        *((cl_mem*) dest->handle),
                                        srcOffset, destOffset,
                                        bytes_,
                                        0, NULL, NULL));
  }

  template <>
  void memory_t<OpenCL>::mappedFree(){
    cl_command_queue &stream = *((cl_command_queue*) dHandle->currentStream);
    cl_int error;

    // Un-map pointer
    error = clEnqueueUnmapMemObject(stream,
                                    *((cl_mem*) handle),
                                    mappedPtr,
                                    0, NULL, NULL);

    OCCA_CL_CHECK("Mapped Free: clEnqueueUnmapMemObject", error);

    // Free mapped-host pointer
    error = clReleaseMemObject(*((cl_mem*) handle));

    OCCA_CL_CHECK("Mapped Free: clReleaseMemObject", error);
  }

  template <>
  void memory_t<OpenCL>::free(){
    clReleaseMemObject(*((cl_mem*) handle));

    if(isAWrapper())
      delete (cl_mem*) handle;

    if(isATexture()){
      clReleaseSampler( *((cl_sampler*) textureInfo.arg) );

      if(!isAWrapper())
        delete (cl_sampler*) textureInfo.arg;
    }

    size = 0;
  }
  //==================================

  //---[ Device ]---------------------
  template <>
  device_t<OpenCL>::device_t() {
    strMode = "OpenCL";

    data = NULL;

    uvaEnabled_ = false;

    bytesAllocated = 0;

    getEnvironmentVariables();
  }

  template <>
  device_t<OpenCL>::device_t(const device_t<OpenCL> &d){
    data           = d.data;
    bytesAllocated = d.bytesAllocated;

    compilerFlags = d.compilerFlags;
  }

  template <>
  device_t<OpenCL>& device_t<OpenCL>::operator = (const device_t<OpenCL> &d){
    modelID_ = d.modelID_;
    id_      = d.id_;

    data = d.data;

    uvaEnabled_    = d.uvaEnabled_;
    uvaMap         = d.uvaMap;
    uvaDirtyMemory = d.uvaDirtyMemory;

    compiler      = d.compiler;
    compilerFlags = d.compilerFlags;

    bytesAllocated = d.bytesAllocated;

    return *this;
  }

  template <>
  void device_t<OpenCL>::setup(argInfoMap &aim){
    data = new OpenCLDeviceData_t;

    OCCA_EXTRACT_DATA(OpenCL, Device);
    cl_int error;

    OCCA_CHECK(aim.has("platformID"),
               "[OpenCL] device not given [platformID]");

    OCCA_CHECK(aim.has("deviceID"),
               "[OpenCL] device not given [deviceID]");

    data_.platform = aim.iGet("platformID");
    data_.device   = aim.iGet("deviceID");

    data_.platformID = cl::platformID(data_.platform);
    data_.deviceID   = cl::deviceID(data_.platform, data_.device);

    data_.context = clCreateContext(NULL, 1, &data_.deviceID, NULL, NULL, &error);
    OCCA_CL_CHECK("Device: Creating Context", error);
  }

  template <>
  void device_t<OpenCL>::addOccaHeadersToInfo(kernelInfo &info_){
    info_.mode = OpenCL;
  }

  template <>
  std::string device_t<OpenCL>::getInfoSalt(const kernelInfo &info_){
    OCCA_EXTRACT_DATA(OpenCL, Device);

    std::stringstream salt;

    salt << "OpenCL"
         << data_.platform << '-' << data_.device
         << info_.salt()
         << parserVersion
         << compilerEnvScript
         << compiler
         << compilerFlags;

    return salt.str();
  }

  template <>
  deviceIdentifier device_t<OpenCL>::getIdentifier() const {
    deviceIdentifier dID;

    dID.mode_ = OpenCL;

    return dID;
  }

  template <>
  void device_t<OpenCL>::getEnvironmentVariables(){
    char *c_compilerFlags = getenv("OCCA_OPENCL_COMPILER_FLAGS");
    if(c_compilerFlags != NULL)
      compilerFlags = std::string(c_compilerFlags);
    else{
#if OCCA_DEBUG_ENABLED
      compilerFlags = "-cl-opt-disable";
#else
      compilerFlags = "";
#endif
    }
  }

  template <>
  void device_t<OpenCL>::appendAvailableDevices(std::vector<device> &dList){
    int platformCount = occa::cl::platformCount();

    for(int p = 0; p < platformCount; ++p){
      int deviceCount = occa::cl::deviceCountInPlatform(p);

      for(int d = 0; d < deviceCount; ++d){
        device dev;
        dev.setup("OpenCL", p, d);

        dList.push_back(dev);
      }
    }
  }

  template <>
  void device_t<OpenCL>::setCompiler(const std::string &compiler_){
    compiler = compiler_;
  }

  template <>
  void device_t<OpenCL>::setCompilerEnvScript(const std::string &compilerEnvScript_){
    compilerEnvScript = compilerEnvScript_;
  }

  template <>
  void device_t<OpenCL>::setCompilerFlags(const std::string &compilerFlags_){
    compilerFlags = compilerFlags_;
  }

  template <>
  void device_t<OpenCL>::flush(){
    OCCA_CL_CHECK("Device: Flush",
                  clFlush(*((cl_command_queue*) currentStream)));
  }

  template <>
  void device_t<OpenCL>::finish(){
    OCCA_CL_CHECK("Device: Finish",
                  clFinish(*((cl_command_queue*) currentStream)));
  }

  template <>
  bool device_t<OpenCL>::fakesUva(){
    return true;
  }

  template <>
  void device_t<OpenCL>::waitFor(streamTag tag){
    OCCA_CL_CHECK("Device: Waiting For Tag",
                  clWaitForEvents(1, &(tag.clEvent)));
  }

  template <>
  stream_t device_t<OpenCL>::createStream(){
    OCCA_EXTRACT_DATA(OpenCL, Device);
    cl_int error;

    cl_command_queue *retStream = new cl_command_queue;

    *retStream = clCreateCommandQueue(data_.context, data_.deviceID, CL_QUEUE_PROFILING_ENABLE, &error);
    OCCA_CL_CHECK("Device: createStream", error);

    return retStream;
  }

  template <>
  void device_t<OpenCL>::freeStream(stream_t s){
    OCCA_CL_CHECK("Device: freeStream",
                  clReleaseCommandQueue( *((cl_command_queue*) s) ));

    delete (cl_command_queue*) s;
  }

  template <>
  stream_t device_t<OpenCL>::wrapStream(void *handle_){
    return handle_;
  }

  template <>
  streamTag device_t<OpenCL>::tagStream(){
    cl_command_queue &stream = *((cl_command_queue*) currentStream);

    streamTag ret;

#ifdef CL_VERSION_1_2
    OCCA_CL_CHECK("Device: Tagging Stream",
                  clEnqueueMarkerWithWaitList(stream, 0, NULL, &(ret.clEvent)));
#else
    OCCA_CL_CHECK("Device: Tagging Stream",
                  clEnqueueMarker(stream, &(ret.clEvent)));
#endif

    return ret;
  }

  template <>
  double device_t<OpenCL>::timeBetween(const streamTag &startTag, const streamTag &endTag){
    cl_ulong start, end;

    finish();

    OCCA_CL_CHECK ("Device: Time Between Tags (Start)",
                   clGetEventProfilingInfo(startTag.clEvent  ,
                                           CL_PROFILING_COMMAND_END,
                                           sizeof(cl_ulong),
                                           &start, NULL) );

    OCCA_CL_CHECK ("Device: Time Between Tags (End)",
                   clGetEventProfilingInfo(endTag.clEvent  ,
                                           CL_PROFILING_COMMAND_START,
                                           sizeof(cl_ulong),
                                           &end, NULL) );

    OCCA_CL_CHECK("Device: Time Between Tags (Freeing start tag)",
                  clReleaseEvent(startTag.clEvent));

    OCCA_CL_CHECK("Device: Time Between Tags (Freeing end tag)",
                  clReleaseEvent(endTag.clEvent));

    return (double) (1.0e-9 * (double)(end - start));
  }

  template <>
  std::string device_t<OpenCL>::fixBinaryName(const std::string &filename){
    return filename;
  }

  template <>
  kernel_v* device_t<OpenCL>::buildKernelFromSource(const std::string &filename,
                                                   const std::string &functionName,
                                                   const kernelInfo &info_){
    OCCA_EXTRACT_DATA(OpenCL, Device);

    kernel_v *k = new kernel_t<OpenCL>;

    k->dHandle = this;
    k->data    = new OpenCLKernelData_t;

    OpenCLKernelData_t &kData_ = *((OpenCLKernelData_t*) k->data);

    kData_.platform = data_.platform;
    kData_.device   = data_.device;

    kData_.platformID = data_.platformID;
    kData_.deviceID   = data_.deviceID;
    kData_.context    = data_.context;

    k->buildFromSource(filename, functionName, info_);

    return k;
  }

  template <>
  kernel_v* device_t<OpenCL>::buildKernelFromBinary(const std::string &filename,
                                                    const std::string &functionName){
    OCCA_EXTRACT_DATA(OpenCL, Device);

    kernel_v *k = new kernel_t<OpenCL>;

    k->dHandle = this;
    k->data    = new OpenCLKernelData_t;

    OpenCLKernelData_t &kData_ = *((OpenCLKernelData_t*) k->data);

    kData_.platform = data_.platform;
    kData_.device   = data_.device;

    kData_.platformID = data_.platformID;
    kData_.deviceID   = data_.deviceID;
    kData_.context    = data_.context;

    k->buildFromBinary(filename, functionName);
    return k;
  }

  template <>
  void device_t<OpenCL>::cacheKernelInLibrary(const std::string &filename,
                                              const std::string &functionName,
                                              const kernelInfo &info_){
#if 0
    //---[ Creating shared library ]----
    kernel tmpK = occa::device(this).buildKernelFromSource(filename, functionName, info_);
    tmpK.free();

    kernelInfo info = info_;

    addOccaHeadersToInfo(info);

    std::string cachedBinary = getCachedName(filename, getInfoSalt(info));

    std::string prefix, name;
    getFilePrefixAndName(cachedBinary, prefix, name);

    std::string extension = getFileExtension(filename);

    const std::string iCachedBinary = prefix + "i_" + name;

    std::string contents = readFile(iCachedBinary);
    //==================================

    library::infoID_t infoID;

    infoID.modelID    = modelID_;
    infoID.kernelName = functionName;

    library::infoHeader_t &header = library::headerMap[infoID];

    header.fileID = -1;
    header.mode   = OpenCL;

    const std::string flatDevID = getIdentifier().flattenFlagMap();

    header.flagsOffset = library::addToScratchPad(flatDevID);
    header.flagsBytes  = flatDevID.size();

    header.contentOffset = library::addToScratchPad(contents);
    header.contentBytes  = contents.size();

    header.kernelNameOffset = library::addToScratchPad(functionName);
    header.kernelNameBytes  = functionName.size();
#endif
  }

  template <>
  kernel_v* device_t<OpenCL>::loadKernelFromLibrary(const char *cache,
                                                    const std::string &functionName){
#if 0
    OCCA_EXTRACT_DATA(OpenCL, Device);

    kernel_v *k = new kernel_t<OpenCL>;

    k->dHandle = this;
    k->data    = new OpenCLKernelData_t;

    OpenCLKernelData_t &kData_ = *((OpenCLKernelData_t*) k->data);

    kData_.platform = data_.platform;
    kData_.device   = data_.device;

    kData_.platformID = data_.platformID;
    kData_.deviceID   = data_.deviceID;
    kData_.context    = data_.context;

    k->loadFromLibrary(cache, functionName);
    return k;
#endif

    return NULL;
  }

  template <>
  memory_v* device_t<OpenCL>::wrapMemory(void *handle_,
                                         const uintptr_t bytes){
    memory_v *mem = new memory_t<OpenCL>;

    mem->dHandle = this;
    mem->size    = bytes;
    mem->handle  = handle_;

    mem->memInfo |= memFlag::isAWrapper;

    return mem;
  }

  template <>
  memory_v* device_t<OpenCL>::wrapTexture(void *handle_,
                                          const int dim, const occa::dim &dims,
                                          occa::formatType type, const int permissions){
#ifndef CL_VERSION_1_2
    if(dim == 1)
      return wrapMemory(handle_, dims.x * type.bytes());

    OCCA_EXTRACT_DATA(OpenCL, Device);

    memory_v *mem = new memory_t<OpenCL>;
    cl_int error;

    mem->dHandle = this;
    mem->size    = (dims.x * dims.y) * type.bytes();
    mem->handle  = handle_;

    mem->memInfo |= (memFlag::isATexture |
                     memFlag::isAWrapper);

    mem->textureInfo.dim  = dim;

    mem->textureInfo.w = dims.x;
    mem->textureInfo.h = dims.y;
    mem->textureInfo.d = dims.z;

    mem->textureInfo.bytesInEntry = type.bytes();

    mem->textureInfo.arg = new cl_sampler;

    *((cl_sampler*) mem->textureInfo.arg) = clCreateSampler(data_.context,
                                                            CL_FALSE,                 // Are args Normalized?
                                                            CL_ADDRESS_CLAMP_TO_EDGE, // Clamp edges
                                                            CL_FILTER_NEAREST,        // Point interpolation
                                                            &error);

    OCCA_CL_CHECK("Device: Creating texture sampler", error);

    return mem;
#else
    OCCA_EXTRACT_DATA(OpenCL, Device);
    cl_int error;

    memory_v *mem = new memory_t<OpenCL>;

    mem->dHandle = this;
    mem->size    = ((dim == 1) ? dims.x : (dims.x * dims.y)) * type.bytes();
    mem->handle  = handle_;

    mem->memInfo |= (memFlag::isATexture |
                     memFlag::isAWrapper);

    mem->textureInfo.dim  = dim;

    mem->textureInfo.w = dims.x;
    mem->textureInfo.h = dims.y;
    mem->textureInfo.d = dims.z;

    mem->textureInfo.bytesInEntry = type.bytes();

    mem->textureInfo.arg = new cl_sampler;

    *((cl_sampler*) mem->textureInfo.arg) = clCreateSampler(data_.context,
                                                            CL_FALSE,                 // Are args Normalized?
                                                            CL_ADDRESS_CLAMP_TO_EDGE, // Clamp edges
                                                            CL_FILTER_NEAREST,        // Point interpolation
                                                            &error);

    OCCA_CL_CHECK("Device: Creating texture sampler", error);

    return mem;
#endif
  }

  template <>
  memory_v* device_t<OpenCL>::malloc(const uintptr_t bytes,
                                     void *src){
    OCCA_EXTRACT_DATA(OpenCL, Device);

    memory_v *mem = new memory_t<OpenCL>;
    cl_int error;

    mem->dHandle = this;
    mem->handle  = new cl_mem;
    mem->size    = bytes;

    if(src == NULL){
      *((cl_mem*) mem->handle) = clCreateBuffer(data_.context,
                                                CL_MEM_READ_WRITE,
                                                bytes, NULL, &error);
    }
    else{
      *((cl_mem*) mem->handle) = clCreateBuffer(data_.context,
                                                CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
                                                bytes, src, &error);

      finish();
    }

    return mem;
  }

  template <>
  memory_v* device_t<OpenCL>::textureAlloc(const int dim, const occa::dim &dims,
                                           void *src,
                                           occa::formatType type, const int permissions){
#ifndef CL_VERSION_1_2
    if(dim == 1)
      return malloc(dims.x * type.bytes(), src);

    OCCA_EXTRACT_DATA(OpenCL, Device);

    memory_v *mem = new memory_t<OpenCL>;
    cl_int error;

    mem->dHandle = this;
    mem->handle  = new cl_mem;
    mem->size    = (dims.x * dims.y) * type.bytes();

    mem->memInfo |= memFlag::isATexture;

    mem->textureInfo.dim  = dim;

    mem->textureInfo.w = dims.x;
    mem->textureInfo.h = dims.y;
    mem->textureInfo.d = dims.z;

    mem->textureInfo.bytesInEntry = type.bytes();

    cl_mem_flags flag = (CL_MEM_COPY_HOST_PTR |
                         ((permissions == occa::readWrite) ?
                          CL_MEM_READ_WRITE : CL_MEM_READ_ONLY));
    cl_image_format imageFormat;

    const int count = type.count();

    switch(count){
    case 1: imageFormat.image_channel_order = CL_R;    break;
    case 2: imageFormat.image_channel_order = CL_RG;   break;
    case 4: imageFormat.image_channel_order = CL_RGBA; break;
    };

    imageFormat.image_channel_data_type = *((cl_channel_type*) type.format<OpenCL>());

    *((cl_mem*) mem->handle) = clCreateImage2D(data_.context, flag,
                                               &imageFormat,
                                               dims.x,
                                               dims.y,
                                               0,
                                               src, &error);

    OCCA_CL_CHECK("Device: Allocating texture", error);

    mem->textureInfo.arg = new cl_sampler;

    *((cl_sampler*) mem->textureInfo.arg) = clCreateSampler(data_.context,
                                                            CL_FALSE,                 // Are args Normalized?
                                                            CL_ADDRESS_CLAMP_TO_EDGE, // Clamp edges
                                                            CL_FILTER_NEAREST,        // Point interpolation
                                                            &error);

    OCCA_CL_CHECK("Device: Creating texture sampler", error);

    return mem;
#else
    OCCA_EXTRACT_DATA(OpenCL, Device);

    memory_v *mem = new memory_t<OpenCL>;
    cl_int error;

    mem->dHandle = this;
    mem->handle  = new cl_mem;
    mem->size    = ((dim == 1) ? dims.x : (dims.x * dims.y)) * type.bytes();

    mem->memInfo |= memFlag::isATexture;

    mem->textureInfo.dim  = dim;

    mem->textureInfo.w = dims.x;
    mem->textureInfo.h = dims.y;
    mem->textureInfo.d = dims.z;

    mem->textureInfo.bytesInEntry = type.bytes();

    cl_mem_flags flag;
    cl_image_format imageFormat;
    cl_image_desc imageDesc;

    flag  = CL_MEM_COPY_HOST_PTR;
    flag |= ((permissions == occa::readWrite) ? CL_MEM_READ_WRITE : CL_MEM_READ_ONLY);

    const int count = type.count();

    switch(count){
    case 1: imageFormat.image_channel_order = CL_R;    break;
    case 2: imageFormat.image_channel_order = CL_RG;   break;
    case 4: imageFormat.image_channel_order = CL_RGBA; break;
    };

    imageFormat.image_channel_data_type = *((cl_channel_type*) type.format<OpenCL>());

    imageDesc.image_type        = (dim == 1) ? CL_MEM_OBJECT_IMAGE1D : CL_MEM_OBJECT_IMAGE2D;
    imageDesc.image_width       = dims.x;
    imageDesc.image_height      = (dim < 2) ? 0 : dims.y;
    imageDesc.image_depth       = (dim < 3) ? 0 : dims.z;
    imageDesc.image_array_size  = 1;
    imageDesc.image_row_pitch   = 0;
    imageDesc.image_slice_pitch = 0;
    imageDesc.num_mip_levels    = 0;
    imageDesc.num_samples       = 0;
    imageDesc.buffer            = NULL;

    //--------------------------------------------
    cl_uint imageFormatCount;
    cl_image_format imageFormats[1024];

    clGetSupportedImageFormats(data_.context,
                               flag,
                               imageDesc.image_type,
                               0, NULL,
                               &imageFormatCount);

    clGetSupportedImageFormats(data_.context,
                               flag,
                               imageDesc.image_type,
                               imageFormatCount, imageFormats,
                               NULL);

    bool isCompatible = cl::imageFormatIsSupported(imageFormat,
                                                   imageFormats,
                                                   imageFormatCount);

    OCCA_CHECK(isCompatible,
               "The specified image format is not compatible");
    //============================================

    *((cl_mem*) mem->handle) = clCreateImage(data_.context, flag,
                                             &imageFormat, &imageDesc,
                                             src, &error);

    OCCA_CL_CHECK("Device: Allocating texture", error);

    mem->textureInfo.arg = new cl_sampler;

    *((cl_sampler*) mem->textureInfo.arg) = clCreateSampler(data_.context,
                                                            CL_FALSE,                 // Are args Normalized?
                                                            CL_ADDRESS_CLAMP_TO_EDGE, // Clamp edges
                                                            CL_FILTER_NEAREST,        // Point interpolation
                                                            &error);

    OCCA_CL_CHECK("Device: Creating texture sampler", error);

    return mem;
#endif

    finish();
  }

  template <>
  memory_v* device_t<OpenCL>::mappedAlloc(const uintptr_t bytes,
                                          void *src){

    OCCA_EXTRACT_DATA(OpenCL, Device);

    cl_command_queue &stream = *((cl_command_queue*) currentStream);

    memory_v *mem = new memory_t<OpenCL>;
    cl_int error;

    mem->dHandle  = this;
    mem->handle   = new cl_mem;
    mem->size     = bytes;

    mem->memInfo |= memFlag::isMapped;

    // Alloc pinned host buffer
    *((cl_mem*) mem->handle) = clCreateBuffer(data_.context,
                                              CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR,
                                              bytes,
                                              NULL, &error);

    OCCA_CL_CHECK("Device: clCreateBuffer", error);

    if(src != NULL)
      mem->copyFrom(src);

    // Map memory to read/write
    mem->mappedPtr = clEnqueueMapBuffer(stream,
                                        *((cl_mem*) mem->handle),
                                        CL_TRUE,
                                        CL_MAP_READ | CL_MAP_WRITE,
                                        0, bytes,
                                        0, NULL, NULL,
                                        &error);

    OCCA_CL_CHECK("Device: clEnqueueMapBuffer", error);

    // Sync memory mapping
    finish();

    return mem;
  }

  template <>
  void device_t<OpenCL>::free(){
    OCCA_EXTRACT_DATA(OpenCL, Device);

    OCCA_CL_CHECK("Device: Freeing Context",
                  clReleaseContext(data_.context) );

    delete (OpenCLDeviceData_t*) data;
  }

  template <>
  int device_t<OpenCL>::simdWidth(){
    if(simdWidth_)
      return simdWidth_;

    OCCA_EXTRACT_DATA(OpenCL, Device);

    cl_device_type dBuffer;
    bool isGPU = false;

    const int bSize = 8192;
    char buffer[bSize + 1];
    buffer[bSize] = '\0';

    OCCA_CL_CHECK("Device: DEVICE_TYPE",
                  clGetDeviceInfo(data_.deviceID, CL_DEVICE_TYPE, sizeof(dBuffer), &dBuffer, NULL));

    OCCA_CL_CHECK("Device: DEVICE_VENDOR",
                  clGetDeviceInfo(data_.deviceID, CL_DEVICE_VENDOR, bSize, buffer, NULL));

    if(dBuffer & CL_DEVICE_TYPE_CPU)
      isGPU = false;
    else if(dBuffer & CL_DEVICE_TYPE_GPU)
      isGPU = true;
    else{
      OCCA_CHECK(false, "Can only find SIMD width for CPU and GPU devices at the momement\n");
    }

    if(isGPU){
      std::string vendor = buffer;
      if(vendor.find("NVIDIA") != std::string::npos)
        simdWidth_ = 32;
      else if((vendor.find("AMD")                    != std::string::npos) ||
              (vendor.find("Advanced Micro Devices") != std::string::npos))
        simdWidth_ = 64;
      else if(vendor.find("Intel") != std::string::npos)   // <> Need to check for Xeon Phi
        simdWidth_ = OCCA_SIMD_WIDTH;
      else{
        OCCA_CHECK(false, "simdWidth() only available for AMD, Intel and NVIDIA architectures");
      }
    }
    else
      simdWidth_ = OCCA_SIMD_WIDTH;

    return simdWidth_;
  }
  //==================================

  //---[ Error Handling ]-------------
  std::string openclError(int e){
    switch(e){
    case CL_SUCCESS:                                   return "CL_SUCCESS";
    case CL_DEVICE_NOT_FOUND:                          return "CL_DEVICE_NOT_FOUND";
    case CL_DEVICE_NOT_AVAILABLE:                      return "CL_DEVICE_NOT_AVAILABLE";
    case CL_COMPILER_NOT_AVAILABLE:                    return "CL_COMPILER_NOT_AVAILABLE";
    case CL_MEM_OBJECT_ALLOCATION_FAILURE:             return "CL_MEM_OBJECT_ALLOCATION_FAILURE";
    case CL_OUT_OF_RESOURCES:                          return "CL_OUT_OF_RESOURCES";
    case CL_OUT_OF_HOST_MEMORY:                        return "CL_OUT_OF_HOST_MEMORY";
    case CL_PROFILING_INFO_NOT_AVAILABLE:              return "CL_PROFILING_INFO_NOT_AVAILABLE";
    case CL_MEM_COPY_OVERLAP:                          return "CL_MEM_COPY_OVERLAP";
    case CL_IMAGE_FORMAT_MISMATCH:                     return "CL_IMAGE_FORMAT_MISMATCH";
    case CL_IMAGE_FORMAT_NOT_SUPPORTED:                return "CL_IMAGE_FORMAT_NOT_SUPPORTED";
    case CL_BUILD_PROGRAM_FAILURE:                     return "CL_BUILD_PROGRAM_FAILURE";
    case CL_MAP_FAILURE:                               return "CL_MAP_FAILURE";
    case CL_MISALIGNED_SUB_BUFFER_OFFSET:              return "CL_MISALIGNED_SUB_BUFFER_OFFSET";
    case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST: return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST";
    case CL_INVALID_VALUE:                             return "CL_INVALID_VALUE";
    case CL_INVALID_DEVICE_TYPE:                       return "CL_INVALID_DEVICE_TYPE";
    case CL_INVALID_PLATFORM:                          return "CL_INVALID_PLATFORM";
    case CL_INVALID_DEVICE:                            return "CL_INVALID_DEVICE";
    case CL_INVALID_CONTEXT:                           return "CL_INVALID_CONTEXT";
    case CL_INVALID_QUEUE_PROPERTIES:                  return "CL_INVALID_QUEUE_PROPERTIES";
    case CL_INVALID_COMMAND_QUEUE:                     return "CL_INVALID_COMMAND_QUEUE";
    case CL_INVALID_HOST_PTR:                          return "CL_INVALID_HOST_PTR";
    case CL_INVALID_MEM_OBJECT:                        return "CL_INVALID_MEM_OBJECT";
    case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR:           return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR";
    case CL_INVALID_IMAGE_SIZE:                        return "CL_INVALID_IMAGE_SIZE";
    case CL_INVALID_SAMPLER:                           return "CL_INVALID_SAMPLER";
    case CL_INVALID_BINARY:                            return "CL_INVALID_BINARY";
    case CL_INVALID_BUILD_OPTIONS:                     return "CL_INVALID_BUILD_OPTIONS";
    case CL_INVALID_PROGRAM:                           return "CL_INVALID_PROGRAM";
    case CL_INVALID_PROGRAM_EXECUTABLE:                return "CL_INVALID_PROGRAM_EXECUTABLE";
    case CL_INVALID_KERNEL_NAME:                       return "CL_INVALID_KERNEL_NAME";
    case CL_INVALID_KERNEL_DEFINITION:                 return "CL_INVALID_KERNEL_DEFINITION";
    case CL_INVALID_KERNEL:                            return "CL_INVALID_KERNEL";
    case CL_INVALID_ARG_INDEX:                         return "CL_INVALID_ARG_INDEX";
    case CL_INVALID_ARG_VALUE:                         return "CL_INVALID_ARG_VALUE";
    case CL_INVALID_ARG_SIZE:                          return "CL_INVALID_ARG_SIZE";
    case CL_INVALID_KERNEL_ARGS:                       return "CL_INVALID_KERNEL_ARGS";
    case CL_INVALID_WORK_DIMENSION:                    return "CL_INVALID_WORK_DIMENSION";
    case CL_INVALID_WORK_GROUP_SIZE:                   return "CL_INVALID_WORK_GROUP_SIZE";
    case CL_INVALID_WORK_ITEM_SIZE:                    return "CL_INVALID_WORK_ITEM_SIZE";
    case CL_INVALID_GLOBAL_OFFSET:                     return "CL_INVALID_GLOBAL_OFFSET";
    case CL_INVALID_EVENT_WAIT_LIST:                   return "CL_INVALID_EVENT_WAIT_LIST";
    case CL_INVALID_EVENT:                             return "CL_INVALID_EVENT";
    case CL_INVALID_OPERATION:                         return "CL_INVALID_OPERATION";
    case CL_INVALID_GL_OBJECT:                         return "CL_INVALID_GL_OBJECT";
    case CL_INVALID_BUFFER_SIZE:                       return "CL_INVALID_BUFFER_SIZE";
    case CL_INVALID_MIP_LEVEL:                         return "CL_INVALID_MIP_LEVEL";
    case CL_INVALID_GLOBAL_WORK_SIZE:                  return "CL_INVALID_GLOBAL_WORK_SIZE";
    case CL_INVALID_PROPERTY:                          return "CL_INVALID_PROPERTY";
    default:                                           return "UNKNOWN ERROR";
    };
  }
  //==================================
};

#endif


text:
First, please do contribute! There are three ways to contribute:

- introduce June to your friends
- discuss June, and submit bugs with Github issues
- send patch with Github pull request

## Codebase

You should follow the code style.

A little hint to make things simple:

- when you cloned this repo, run `make`, it will prepare everything for you
- check the code style with `make lint`
- check the test case with `make test`

## Writing Patches / Sending Pull Requests

Consider contributing patches back to June? That's great. Here are some basic principles that will help maintainers / reviewers and your future self:

- break your changes to separate patches
- a patch should include only one functional change / fix
- state clear what's changed and why it should be changed like that in commit message
- arrange your patches so they don't break bisection

Following the above principles, you should be able to:

- run `git log` and know exactly what's going on in each patch without even looking at the code
- run `git bisect` and easily find out which commit breaks things

## Basic Git Workflow

You should always create a dedicated branch for your need, whether it's for bug fix or new feature. Then you should rebase your changes on top of upstream master branch before sending pull request.

Example of workflow ("origin" refers to upstream remote):

```
$ git branch [feature-name]
$ git checkout [feature-name]
...DEVELOPMENT...
$ git fetch origin
$ git rebase origin/master
$ git push [your-repository] [feature-name]
```

It's all set! After that you can send a pull request to upstream.

## Checklist

We are still in development, and this is a total rewrite of June in Flask.

redpajama_set_name: RedPajamaGithub


text:
INSERT INTO BLC_ADMIN_ROLE (ADMIN_ROLE_ID, DESCRIPTION, NAME) VALUES (-1,'Admin Master Access','ROLE_ADMIN');
INSERT INTO BLC_ADMIN_ROLE (ADMIN_ROLE_ID, DESCRIPTION, NAME) VALUES (-2,'Merchandiser','ROLE_MERCHANDISE_MANAGER');
INSERT INTO BLC_ADMIN_ROLE (ADMIN_ROLE_ID, DESCRIPTION, NAME) VALUES (-3,'Promotion Manager','ROLE_PROMOTION_MANAGER');
INSERT INTO BLC_ADMIN_ROLE (ADMIN_ROLE_ID, DESCRIPTION, NAME) VALUES (-4,'CSR','ROLE_CUSTOMER_SERVICE_REP');
INSERT INTO BLC_ADMIN_ROLE (ADMIN_ROLE_ID, DESCRIPTION, NAME) VALUES (-5,'CMS Editor','ROLE_CONTENT_EDITOR');
INSERT INTO BLC_ADMIN_ROLE (ADMIN_ROLE_ID, DESCRIPTION, NAME) VALUES (-6,'CMS Approver','ROLE_CONTENT_APPROVER');
INSERT INTO BLC_ADMIN_ROLE (ADMIN_ROLE_ID, DESCRIPTION, NAME) VALUES (-7,'CMS Designer','ROLE_CONTENT_DESIGNER');

--
--
-- Mapping from Roles to permissions
--
-- Super user
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-101);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-103);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-105);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-107);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-109);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-111);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-113);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-115);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-117);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-119);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-121);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-123);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-127);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-128);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-129);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-131);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-141);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-161);

-- This permission grants access to "Permission" management to admin.    Since this can be harmful,
-- it is not provided by default
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-151);

-- These are the permissions that grant access to SystemProperty. This is somewhat advanced and can be harmful,
-- so they are not enabled by default.
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-110);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-1,-112);

-- Merchandiser
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-2,-101);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-2,-103);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-2,-105);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-2,-111);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-2,-131);

-- Promotions
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-3,-107);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-3,-131);

-- CSR
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-4,-117);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-4,-119);

-- CMS Editor
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-5,-109);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-5,-111);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-5,-113);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-5,-131);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-5,-161);

-- CMS Approver
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-6,-109);
INSERT INTO BLC_ADMIN_ROLE_PERMISSION_XREF (ADMIN_ROLE_ID, ADMIN_PERMISSION_ID) VALUES (-6,-111);


text:
@interface ViewController : UIViewController

@property (strong, nonatomic) UIViewController *viewCustomAlert;

@end


text:
REM OK TO RUN SERVER mvn clean install org.codehaus.cargo:cargo-maven2-plugin:run -Dserver=jetty9x -Pjacoco > deploy.log 2>&1

grunt phantomflow:websitetests --report

sudo apt-get install graphicsmagick

# examples/wraith
gem install wraith

# run the capture process
wraith capture demo

# view results in the browser
open shots/gallery.html


text:
require 'teststrap'
require 'rails/active_record_test_helper'

context "association validation" do
  has_association_validation = lambda do |klass,assoc|
    !klass.validation_collection.detect do |(validation_klass,opts)|
      validation_klass == WhyValidationsSuckIn96::ValidatesAssociated && opts[:attribute] == assoc && opts[:on] == :save
    end.nil?
  end

  teardown do
    next unless topic.kind_of?(Class)
    Object.send(:remove_const, topic.name)
  end

  context "against has_many" do
    context "with :validate set to true" do
      setup do
        class ::TestBook < Book
          has_many :chapters, :validate => true
          self
        end
      end

      should "set up an association validation" do
        has_association_validation[topic, :chapters]
      end
    end # with :validate set to true

    context "with :validate set to false" do
      setup do
        class ::TestBook < Book
          has_many :chapters, :validate => false
          self
        end
      end

      should "not set up an association validation" do
        has_association_validation[topic, :chapters]
      end.equals(false)
    end # with :validate set to false
  end   # against has_many

  context "against has_and_belongs_to_many" do
    context "with :validate set to true" do
      setup do
        class ::TestGenre < Genre
          has_and_belongs_to_many :books, :validate => true
          self
        end
      end

      should "set up an association validation" do
        has_association_validation[topic, :books]
      end
    end # with :validate set to true

    context "with :validate set to false" do
      setup do
        class ::TestGenre < Genre
          has_and_belongs_to_many :books, :validate => false
          self
        end
      end

      should "not set up an association validation" do
        has_association_validation[topic, :books]
      end.equals(false)
    end # with :validate set to false
  end   # against has_and_belongs_to_many

  context "against has_one" do
    context "with :validate set to true" do
      setup do
        class ::TestBook < Book
          has_one :glossary, :validate => true
          self
        end
      end

      should "set up an association validation" do
        has_association_validation[topic, :glossary]
      end
    end # with :validate set to true

    context "with :validate set to false" do
      setup do
        class ::TestBook < Book
          has_one :glossary, :validate => false
          self
        end
      end

      should "not set up an association validation" do
        has_association_validation[topic, :glossary]
      end.equals(false)
    end # with :validate set to false
  end   # against has_one

  context "against belongs_to" do
    context "with :validate set to true" do
      setup do
        class ::TestChapter < Chapter
          belongs_to :book, :validate => true
          self
        end
      end

      should "set up an association validation" do
        has_association_validation[topic, :book]
      end
    end # with :validate set to true

    context "with :validate set to false" do
      setup do
        class ::TestChapter < Chapter
          belongs_to :book, :validate => false
          self
        end
      end

      should "not set up an association validation" do
        has_association_validation[topic, :book]
      end.equals(false)
    end # with :validate set to false
  end   # against belongs_to
end     # association validation


text:
template<>
VideoPAK* _mfxSession::Create<VideoPAK>(mfxVideoParam& par)
{
    VideoPAK* pPAK = nullptr;
    mfxStatus mfxRes = MFX_ERR_MEMORY_ALLOC;
    mfxU32 codecId = par.mfx.CodecId;

    switch (codecId)
    {
#if defined(MFX_VA_LINUX) && defined(MFX_ENABLE_H264_VIDEO_ENCODE_HW) && defined(MFX_ENABLE_H264_VIDEO_FEI_PAK)
    case MFX_CODEC_AVC:
        if (bEnc_PAK(&par))
            pPAK = (VideoPAK*) new VideoPAK_PAK(m_pCORE.get(), &mfxRes);
        break;
#endif // MFX_ENABLE_H264_VIDEO_FEI_PAK

    default:
        break;
    }

    // check error(s)
    if (MFX_ERR_NONE != mfxRes)
    {
        delete pPAK;
        pPAK = nullptr;
    }

    return pPAK;
}

mfxStatus MFXVideoPAK_Query(mfxSession session, mfxVideoParam *in, mfxVideoParam *out)
{
    (void)in;

    MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
    MFX_CHECK(out, MFX_ERR_NULL_PTR);

    mfxStatus mfxRes;
    try
    {
        switch (out->mfx.CodecId)
        {

#if defined(MFX_VA_LINUX) && defined(MFX_ENABLE_H264_VIDEO_ENCODE_HW) && defined(MFX_ENABLE_H264_VIDEO_FEI_PAK)
        case MFX_CODEC_AVC:
            if (bEnc_PAK(in))
                mfxRes = VideoPAK_PAK::Query(session->m_pCORE.get(), in, out);
            else
                mfxRes = MFX_ERR_UNSUPPORTED;
            break;
#endif

        default: case 0:
            mfxRes = MFX_ERR_UNSUPPORTED;
        }
    }
    // handle error(s)
    catch(...)
    {
        mfxRes = MFX_ERR_NULL_PTR;
    }
    return mfxRes;
}

mfxStatus MFXVideoPAK_QueryIOSurf(mfxSession session, mfxVideoParam *par, mfxFrameAllocRequest *request)
{
    MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
    MFX_CHECK(par, MFX_ERR_NULL_PTR);
    MFX_CHECK(request, MFX_ERR_NULL_PTR);

    mfxStatus mfxRes;
    try
    {
        switch (par->mfx.CodecId)
        {

#if defined(MFX_VA_LINUX) && defined(MFX_ENABLE_H264_VIDEO_ENCODE_HW) && defined(MFX_ENABLE_H264_VIDEO_FEI_PAK)
        case MFX_CODEC_AVC:
            if (bEnc_PAK(par))
                mfxRes = VideoPAK_PAK::QueryIOSurf(session->m_pCORE.get(), par, request);
            else
                mfxRes = MFX_ERR_UNSUPPORTED;
            break;
#endif

        default: case 0:
            mfxRes = MFX_ERR_UNSUPPORTED;
        }
    }
    // handle error(s)
    catch(...)
    {
        mfxRes = MFX_ERR_NULL_PTR;
    }
    return mfxRes;
}

mfxStatus MFXVideoPAK_Init(mfxSession session, mfxVideoParam *par)
{
    mfxStatus mfxRes;

    MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
    MFX_CHECK(par, MFX_ERR_NULL_PTR);

    try
    {
        // create a new instance
        session->m_pPAK.reset(session->Create<VideoPAK>(*par));
        MFX_CHECK(session->m_pPAK.get(), MFX_ERR_INVALID_VIDEO_PARAM);

        mfxRes = session->m_pPAK->Init(par);
    }
    // handle error(s)
    catch(...)
    {
        // set the default error value
        mfxRes = MFX_ERR_UNKNOWN;
    }

    return mfxRes;
}

mfxStatus MFXVideoPAK_Close(mfxSession session)
{
    mfxStatus mfxRes;

    MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);

    try
    {
        if (!session->m_pPAK)
        {
            return MFX_ERR_NOT_INITIALIZED;
        }

        // wait until all tasks are processed
        session->m_pScheduler->WaitForAllTasksCompletion(session->m_pPAK.get());

        mfxRes = session->m_pPAK->Close();
        // delete the codec's instance
        session->m_pPAK.reset(nullptr);
    }
    // handle error(s)
    catch(...)
    {
        // set the default error value
        mfxRes = MFX_ERR_UNKNOWN;
    }

    return mfxRes;
}

enum
{
    MFX_NUM_ENTRY_POINTS = 2
};

mfxStatus MFXVideoPAK_ProcessFrameAsync(mfxSession session , mfxPAKInput *in, mfxPAKOutput *out, mfxSyncPoint *syncp)
{
     mfxStatus mfxRes;

     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
     MFX_CHECK(session->m_pPAK.get(), MFX_ERR_NOT_INITIALIZED);
     MFX_CHECK(syncp, MFX_ERR_NULL_PTR);

     VideoPAK_Ext *pPak = dynamic_cast<VideoPAK_Ext *>(session->m_pPAK.get());
     MFX_CHECK(pPak, MFX_ERR_INVALID_HANDLE);

     try
     {
         mfxSyncPoint syncPoint = NULL;
         MFX_ENTRY_POINT entryPoints[MFX_NUM_ENTRY_POINTS];
         mfxU32 numEntryPoints = MFX_NUM_ENTRY_POINTS;
         memset(&entryPoints, 0, sizeof(entryPoints));

         mfxRes = pPak->RunFramePAKCheck(in,out,entryPoints,numEntryPoints);

         if ((MFX_ERR_NONE == mfxRes) ||
             (MFX_WRN_INCOMPATIBLE_VIDEO_PARAM == mfxRes) ||
             (MFX_WRN_OUT_OF_RANGE == mfxRes) ||
             (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes)) ||
             (MFX_ERR_MORE_BITSTREAM == mfxRes))
         {
             if (1 == numEntryPoints)
             {
                 MFX_TASK task;

                 memset(&task, 0, sizeof(task));
                 task.pOwner = pPak;
                 task.entryPoint = entryPoints[0];
                 task.priority = session->m_priority;
                 task.threadingPolicy = pPak->GetThreadingPolicy();
                 // fill dependencies

                 task.pSrc[0] = in->InSurface;
                 task.pSrc[1] = out ? out->ExtParam : 0; // for LA plugin
                 task.pDst[0] = out;

                 // register input and call the task
                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));
             }
             else
             {
                 MFX_TASK task;

                 memset(&task, 0, sizeof(task));
                 task.pOwner = pPak;
                 task.entryPoint = entryPoints[0];
                 task.priority = session->m_priority;
                 task.threadingPolicy = pPak->GetThreadingPolicy();
                 // fill dependencies
                 task.pSrc[0] = pPak->GetSrcForSync(entryPoints[0]);
                 task.pDst[0] = entryPoints[0].pParam;

                 // register input and call the task
                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));

                 memset(&task, 0, sizeof(task));
                 task.pOwner = pPak;
                 task.entryPoint = entryPoints[1];
                 task.priority = session->m_priority;
                 task.threadingPolicy = pPak->GetThreadingPolicy();
                 // fill dependencies
                 task.pSrc[0] = entryPoints[0].pParam;
                 task.pDst[0] = pPak->GetDstForSync(entryPoints[1]);
                 task.pDst[1] = out ? out->ExtParam : 0; // sync point for LA plugin

                 // register input and call the task
                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));
             }

             // IT SHOULD BE REMOVED
             if (MFX_ERR_MORE_DATA_SUBMIT_TASK == mfxRes)
             {
                 mfxRes = MFX_ERR_MORE_DATA;
                 syncPoint = NULL;
             }

         }

         // return pointer to synchronization point
         *syncp = syncPoint;
     }
     // handle error(s)
     catch(...)
     {
         // set the default error value
         mfxRes = MFX_ERR_UNKNOWN;
     }

     return mfxRes;
}

//
// THE OTHER PAK FUNCTIONS HAVE IMPLICIT IMPLEMENTATION
//

FUNCTION_RESET_IMPL(PAK, Reset, (mfxSession session, mfxVideoParam *par), (par))

FUNCTION_IMPL(PAK, GetVideoParam, (mfxSession session, mfxVideoParam *par), (par))
FUNCTION_IMPL(PAK, GetFrameParam, (mfxSession session, mfxFrameParam *par), (par))


text:
package com.amazonaws.services.kinesisvideo.model;

import java.io.Serializable;
import javax.annotation.Generated;

import com.amazonaws.AmazonWebServiceRequest;

/**
 *
 * @see AWS API Documentation
 */
@Generated("com.amazonaws:aws-java-sdk-code-generator")
public class UpdateNotificationConfigurationRequest extends com.amazonaws.AmazonWebServiceRequest implements Serializable, Cloneable {

    /**
     *

     * The name of the stream from which to update the notification configuration. You must specify either the
     * StreamName or the StreamARN.
     *

     */
    private String streamName;
    /**
     *

     * The Amazon Resource Name (ARN) of the Kinesis video stream from where you want to update the notification
     * configuration. You must specify either the StreamName or the StreamARN.
     *

     */
    private String streamARN;
    /**
     *

     * The structure containing the information required for notifications. If the structure is null, the configuration
     * will be deleted from the stream.
     *

     */
    private NotificationConfiguration notificationConfiguration;

    /**
     *

     * The name of the stream from which to update the notification configuration. You must specify either the
     * StreamName or the StreamARN.
     *

     *
     * @param streamName
     *        The name of the stream from which to update the notification configuration. You must specify either the
     *        StreamName or the StreamARN.
     */

    public void setStreamName(String streamName) {
        this.streamName = streamName;
    }

    /**
     *

     * The name of the stream from which to update the notification configuration. You must specify either the
     * StreamName or the StreamARN.
     *

     *
     * @return The name of the stream from which to update the notification configuration. You must specify either the
     *         StreamName or the StreamARN.
     */

    public String getStreamName() {
        return this.streamName;
    }

    /**
     *

     * The name of the stream from which to update the notification configuration. You must specify either the
     * StreamName or the StreamARN.
     *

     *
     * @param streamName
     *        The name of the stream from which to update the notification configuration. You must specify either the
     *        StreamName or the StreamARN.
     * @return Returns a reference to this object so that method calls can be chained together.
     */

    public UpdateNotificationConfigurationRequest withStreamName(String streamName) {
        setStreamName(streamName);
        return this;
    }

    /**
     *

     * The Amazon Resource Name (ARN) of the Kinesis video stream from where you want to update the notification
     * configuration. You must specify either the StreamName or the StreamARN.
     *

     *
     * @param streamARN
     *        The Amazon Resource Name (ARN) of the Kinesis video stream from where you want to update the notification
     *        configuration. You must specify either the StreamName or the StreamARN.
     */

    public void setStreamARN(String streamARN) {
        this.streamARN = streamARN;
    }

    /**
     *

     * The Amazon Resource Name (ARN) of the Kinesis video stream from where you want to update the notification
     * configuration. You must specify either the StreamName or the StreamARN.
     *

     *
     * @return The Amazon Resource Name (ARN) of the Kinesis video stream from where you want to update the notification
     *         configuration. You must specify either the StreamName or the StreamARN.
     */

    public String getStreamARN() {
        return this.streamARN;
    }

    /**
     *

     * The Amazon Resource Name (ARN) of the Kinesis video stream from where you want to update the notification
     * configuration. You must specify either the StreamName or the StreamARN.
     *

     *
     * @param streamARN
     *        The Amazon Resource Name (ARN) of the Kinesis video stream from where you want to update the notification
     *        configuration. You must specify either the StreamName or the StreamARN.
     * @return Returns a reference to this object so that method calls can be chained together.
     */

    public UpdateNotificationConfigurationRequest withStreamARN(String streamARN) {
        setStreamARN(streamARN);
        return this;
    }

    /**
     *

     * The structure containing the information required for notifications. If the structure is null, the configuration
     * will be deleted from the stream.
     *

     *
     * @param notificationConfiguration
     *        The structure containing the information required for notifications. If the structure is null, the
     *        configuration will be deleted from the stream.
     */

    public void setNotificationConfiguration(NotificationConfiguration notificationConfiguration) {
        this.notificationConfiguration = notificationConfiguration;
    }

    /**
     *

     * The structure containing the information required for notifications. If the structure is null, the configuration
     * will be deleted from the stream.
     *

     *
     * @return The structure containing the information required for notifications. If the structure is null, the
     *         configuration will be deleted from the stream.
     */

    public NotificationConfiguration getNotificationConfiguration() {
        return this.notificationConfiguration;
    }

    /**
     *

     * The structure containing the information required for notifications. If the structure is null, the configuration
     * will be deleted from the stream.
     *

     *
     * @param notificationConfiguration
     *        The structure containing the information required for notifications. If the structure is null, the
     *        configuration will be deleted from the stream.
     * @return Returns a reference to this object so that method calls can be chained together.
     */

    public UpdateNotificationConfigurationRequest withNotificationConfiguration(NotificationConfiguration notificationConfiguration) {
        setNotificationConfiguration(notificationConfiguration);
        return this;
    }

    /**
     * Returns a string representation of this object. This is useful for testing and debugging. Sensitive data will be
     * redacted from this string using a placeholder value.
     *
     * @return A string representation of this object.
     *
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        if (getStreamName() != null)
            sb.append("StreamName: ").append(getStreamName()).append(",");
        if (getStreamARN() != null)
            sb.append("StreamARN: ").append(getStreamARN()).append(",");
        if (getNotificationConfiguration() != null)
            sb.append("NotificationConfiguration: ").append(getNotificationConfiguration());
        sb.append("}");
        return sb.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;

        if (obj instanceof UpdateNotificationConfigurationRequest == false)
            return false;
        UpdateNotificationConfigurationRequest other = (UpdateNotificationConfigurationRequest) obj;
        if (other.getStreamName() == null ^ this.getStreamName() == null)
            return false;
        if (other.getStreamName() != null && other.getStreamName().equals(this.getStreamName()) == false)
            return false;
        if (other.getStreamARN() == null ^ this.getStreamARN() == null)
            return false;
        if (other.getStreamARN() != null && other.getStreamARN().equals(this.getStreamARN()) == false)
            return false;
        if (other.getNotificationConfiguration() == null ^ this.getNotificationConfiguration() == null)
            return false;
        if (other.getNotificationConfiguration() != null && other.getNotificationConfiguration().equals(this.getNotificationConfiguration()) == false)
            return false;
        return true;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int hashCode = 1;

        hashCode = prime * hashCode + ((getStreamName() == null) ? 0 : getStreamName().hashCode());
        hashCode = prime * hashCode + ((getStreamARN() == null) ? 0 : getStreamARN().hashCode());
        hashCode = prime * hashCode + ((getNotificationConfiguration() == null) ? 0 : getNotificationConfiguration().hashCode());
        return hashCode;
    }

    @Override
    public UpdateNotificationConfigurationRequest clone() {
        return (UpdateNotificationConfigurationRequest) super.clone();
    }

}


text:
#include <aws/outposts/model/SupportedStorageEnum.h>
#include <aws/core/utils/HashingUtils.h>
#include <aws/core/Globals.h>
#include <aws/core/utils/EnumParseOverflowContainer.h>

using namespace Aws::Utils;

namespace Aws
{
  namespace Outposts
  {
    namespace Model
    {
      namespace SupportedStorageEnumMapper
      {

        static const int EBS_HASH = HashingUtils::HashString("EBS");
        static const int S3_HASH = HashingUtils::HashString("S3");

        SupportedStorageEnum GetSupportedStorageEnumForName(const Aws::String& name)
        {
          int hashCode = HashingUtils::HashString(name.c_str());
          if (hashCode == EBS_HASH)
          {
            return SupportedStorageEnum::EBS;
          }
          else if (hashCode == S3_HASH)
          {
            return SupportedStorageEnum::S3;
          }
          EnumParseOverflowContainer* overflowContainer = Aws::GetEnumOverflowContainer();
          if(overflowContainer)
          {
            overflowContainer->StoreOverflow(hashCode, name);
            return static_cast<SupportedStorageEnum>(hashCode);
          }

          return SupportedStorageEnum::NOT_SET;
        }

        Aws::String GetNameForSupportedStorageEnum(SupportedStorageEnum enumValue)
        {
          switch(enumValue)
          {
          case SupportedStorageEnum::EBS:
            return "EBS";
          case SupportedStorageEnum::S3:
            return "S3";
          default:
            EnumParseOverflowContainer* overflowContainer = Aws::GetEnumOverflowContainer();
            if(overflowContainer)
            {
              return overflowContainer->RetrieveOverflow(static_cast<int>(enumValue));
            }

            return {};
          }
        }

      } // namespace SupportedStorageEnumMapper
    } // namespace Model
  } // namespace Outposts
} // namespace Aws