/**********************************************************************
Copyright ©2014 Advanced Micro Devices, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************/
// For clarity,error checking has been omitted.
#include <CL/cl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <fstream>
#define SUCCESS 0
#define FAILURE 1
using namespace std;
/* convert the kernel file into a string */
int convertToString( const char * filename, std:: string & s)
{
size_t size;
char * str;
std:: fstream f( filename, ( std:: fstream :: in | std:: fstream :: binary ) ) ;
if ( f.is_open ( ) )
{
size_t fileSize;
f.seekg ( 0 , std:: fstream :: end ) ;
size = fileSize = ( size_t ) f.tellg ( ) ;
f.seekg ( 0 , std:: fstream :: beg ) ;
str = new char [ size+ 1 ] ;
if ( ! str)
{
f.close ( ) ;
return 0 ;
}
f.read ( str, fileSize) ;
f.close ( ) ;
str[ size] = '\0 ' ;
s = str;
delete[ ] str;
return 0 ;
}
cout<< "Error: failed to open file\n :" << filename<< endl;
return FAILURE;
}
int main( int argc, char * argv[ ] )
{
/*Step1: Getting platforms and choose an available one.*/
cl_uint numPlatforms; //the NO. of platforms
cl_platform_id platform = NULL; //the chosen platform
cl_int status = clGetPlatformIDs( 0 , NULL, & numPlatforms) ;
if ( status != CL_SUCCESS)
{
cout << "Error: Getting platforms!" << endl;
return FAILURE;
}
/*For clarity, choose the first available platform. */
if ( numPlatforms > 0 )
{
cl_platform_id
* platforms
= ( cl_platform_id
* ) malloc ( numPlatforms
* sizeof ( cl_platform_id
) ) ; status = clGetPlatformIDs( numPlatforms, platforms, NULL) ;
platform = platforms[ 0 ] ;
}
/*Step 2:Query the platform and choose the first GPU device if has one.Otherwise use the CPU as device.*/
cl_uint numDevices = 0 ;
cl_device_id * devices;
status = clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU, 0 , NULL, & numDevices) ;
if ( numDevices == 0 ) //no GPU available.
{
cout << "No GPU device available." << endl;
cout << "Choose CPU as default device." << endl;
status = clGetDeviceIDs( platform, CL_DEVICE_TYPE_CPU, 0 , NULL, & numDevices) ;
devices
= ( cl_device_id
* ) malloc ( numDevices
* sizeof ( cl_device_id
) ) ; status = clGetDeviceIDs( platform, CL_DEVICE_TYPE_CPU, numDevices, devices, NULL) ;
}
else
{
devices
= ( cl_device_id
* ) malloc ( numDevices
* sizeof ( cl_device_id
) ) ; status = clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU, numDevices, devices, NULL) ;
}
/*Step 3: Create context.*/
cl_context context = clCreateContext( NULL, 1 , devices, NULL, NULL, NULL) ;
/*Step 4: Creating command queue associate with the context.*/
/*old func. code
cl_command_queue commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);
*/
/*new func.
* cl_command_queue clCreateCommandQueueWithProperties(
cl_context context,
cl_device_id device,
const cl_queue_properties *properties,
cl_int *errcode_ret)
*/
cl_command_queue commandQueue = clCreateCommandQueueWithProperties( context, devices[ 0 ] , 0 , NULL) ;
//cl_command_queue commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);
/*Step 5: Create program object */
const char * filename = "HelloWorld_Kernel.cl" ;
string sourceStr;
status = convertToString( filename, sourceStr) ;
const char * source = sourceStr.c_str ( ) ;
size_t sourceSize
[ ] = { strlen ( source
) } ; cl_program program = clCreateProgramWithSource( context, 1 , & source, sourceSize, NULL) ;
/*Step 6: Build program. */
const char options[ ] = "-cl-std=CL2.0" ;
status = clBuildProgram( program, 1 , devices, options, NULL, NULL) ;
/*Step 7: Create kernel object */
cl_kernel kernel = clCreateKernel( program, "SVMhelloworld" , NULL) ;
/*Step 8: Initial input,output for the host and create SVM buffer*/
const char * input = "HelloWorld" ;
size_t strlength
= strlen ( input
) ; char * output
= ( char * ) malloc ( strlength
+ 1 ) ; void * inputBuffer = clSVMAlloc( context, CL_MEM_READ_WRITE, ( strlength + 1 ) * sizeof ( char ) , 0 ) ;
void * outputBuffer = clSVMAlloc( context, CL_MEM_READ_WRITE, ( strlength + 1 ) * sizeof ( char ) , 0 ) ;
status = clEnqueueSVMMap( commandQueue, CL_TRUE, CL_MAP_WRITE_INVALIDATE_REGION, inputBuffer, ( strlength + 1 ) * sizeof ( char ) , 0 , NULL, NULL) ;
memcpy ( inputBuffer
, input
, strlength
) ; cout << "input string:" << endl;
cout << input << endl;
/*test inputBuffer
cout << "inputBuffer first char:" << endl;
cout << *((char *)inputBuffer) << endl;
*/
status = clEnqueueSVMUnmap( commandQueue, inputBuffer, 0 , NULL, NULL) ;
/*Step 9: Sets Kernel arguments.*/
status = clSetKernelArgSVMPointer( kernel, 0 , ( void * ) ( inputBuffer) ) ;
status = clSetKernelArgSVMPointer( kernel, 1 , ( void * ) ( outputBuffer) ) ;
/*Step 10: Running the kernel.*/
size_t global_work_size[ 1 ] = { strlength} ;
status = clEnqueueNDRangeKernel( commandQueue, kernel, 1 , NULL, global_work_size, NULL, 0 , NULL, NULL) ;
status = clEnqueueSVMMap( commandQueue, CL_TRUE, CL_MAP_WRITE_INVALIDATE_REGION, outputBuffer, ( strlength + 1 ) * sizeof ( char ) , 0 , NULL, NULL) ;
memcpy ( output
, outputBuffer
, strlength
) ; output[ strlength] = '\0 ' ; //Add the terminal character to the end of output.
/*test if kernel works and char. are all assign to outputBuffer*/
int i;
for ( i = 0 ; i < 10 ; i++ ) {
cout << "#" << i << ":" << * ( ( ( char * ) outputBuffer) + i) << endl;
}
cout << "\n output string:" << endl;
cout << output << endl;
status = clEnqueueSVMUnmap( commandQueue, outputBuffer, 0 , NULL, NULL) ;
/*Step 12: Clean the resources.*/
clSVMFree( context, inputBuffer) ;
clSVMFree( context, outputBuffer) ;
status = clReleaseKernel( kernel) ; //Release kernel.
status = clReleaseProgram( program) ; //Release the program object.
status = clReleaseCommandQueue( commandQueue) ; //Release Command queue.
status = clReleaseContext( context) ; //Release context.
if ( output != NULL)
{
output = NULL;
}
if ( devices != NULL)
{
devices = NULL;
}
cout<< "Program passed!\n " ;
return SUCCESS;
}
LyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKQ29weXJpZ2h0IMKpMjAxNCBBZHZhbmNlZCBNaWNybyBEZXZpY2VzLCBJbmMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgpSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQgbW9kaWZpY2F0aW9uLCBhcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxvd2luZyBjb25kaXRpb25zIGFyZSBtZXQ6CgoJUmVkaXN0cmlidXRpb25zIG9mIHNvdXJjZSBjb2RlIG11c3QgcmV0YWluIHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyLgoJUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyIGluIHRoZSBkb2N1bWVudGF0aW9uIGFuZC9vcgogb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi4KClRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORCBDT05UUklCVVRPUlMgIkFTIElTIiBBTkQgQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQKIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUgRElTQ0xBSU1FRC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVCBIT0xERVIgT1IgQ09OVFJJQlVUT1JTIEJFIExJQUJMRSBGT1IgQU5ZCiBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLCBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyAoSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVM7IExPU1MKIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBUSU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xVRElORwogTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRiBUSElTIFNPRlRXQVJFLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLgoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KCi8vIEZvciBjbGFyaXR5LGVycm9yIGNoZWNraW5nIGhhcyBiZWVuIG9taXR0ZWQuCgojaW5jbHVkZSA8Q0wvY2wuaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDxzdHJpbmc+CiNpbmNsdWRlIDxmc3RyZWFtPgoKI2RlZmluZSBTVUNDRVNTIDAKI2RlZmluZSBGQUlMVVJFIDEKCnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgovKiBjb252ZXJ0IHRoZSBrZXJuZWwgZmlsZSBpbnRvIGEgc3RyaW5nICovCmludCBjb252ZXJ0VG9TdHJpbmcoY29uc3QgY2hhciAqZmlsZW5hbWUsIHN0ZDo6c3RyaW5nJiBzKQp7CglzaXplX3Qgc2l6ZTsKCWNoYXIqICBzdHI7CglzdGQ6OmZzdHJlYW0gZihmaWxlbmFtZSwgKHN0ZDo6ZnN0cmVhbTo6aW4gfCBzdGQ6OmZzdHJlYW06OmJpbmFyeSkpOwoKCWlmKGYuaXNfb3BlbigpKQoJewoJCXNpemVfdCBmaWxlU2l6ZTsKCQlmLnNlZWtnKDAsIHN0ZDo6ZnN0cmVhbTo6ZW5kKTsKCQlzaXplID0gZmlsZVNpemUgPSAoc2l6ZV90KWYudGVsbGcoKTsKCQlmLnNlZWtnKDAsIHN0ZDo6ZnN0cmVhbTo6YmVnKTsKCQlzdHIgPSBuZXcgY2hhcltzaXplKzFdOwoJCWlmKCFzdHIpCgkJewoJCQlmLmNsb3NlKCk7CgkJCXJldHVybiAwOwoJCX0KCgkJZi5yZWFkKHN0ciwgZmlsZVNpemUpOwoJCWYuY2xvc2UoKTsKCQlzdHJbc2l6ZV0gPSAnXDAnOwoJCXMgPSBzdHI7CgkJZGVsZXRlW10gc3RyOwoJCXJldHVybiAwOwoJfQoJY291dDw8IkVycm9yOiBmYWlsZWQgdG8gb3BlbiBmaWxlXG46Ijw8ZmlsZW5hbWU8PGVuZGw7CglyZXR1cm4gRkFJTFVSRTsKfQoKaW50IG1haW4oaW50IGFyZ2MsIGNoYXIqIGFyZ3ZbXSkKewoKCS8qU3RlcDE6IEdldHRpbmcgcGxhdGZvcm1zIGFuZCBjaG9vc2UgYW4gYXZhaWxhYmxlIG9uZS4qLwoJY2xfdWludCBudW1QbGF0Zm9ybXM7CS8vdGhlIE5PLiBvZiBwbGF0Zm9ybXMKCWNsX3BsYXRmb3JtX2lkIHBsYXRmb3JtID0gTlVMTDsJLy90aGUgY2hvc2VuIHBsYXRmb3JtCgljbF9pbnQJc3RhdHVzID0gY2xHZXRQbGF0Zm9ybUlEcygwLCBOVUxMLCAmbnVtUGxhdGZvcm1zKTsKCWlmIChzdGF0dXMgIT0gQ0xfU1VDQ0VTUykKCXsKCQljb3V0IDw8ICJFcnJvcjogR2V0dGluZyBwbGF0Zm9ybXMhIiA8PCBlbmRsOwoJCXJldHVybiBGQUlMVVJFOwoJfQoKCS8qRm9yIGNsYXJpdHksIGNob29zZSB0aGUgZmlyc3QgYXZhaWxhYmxlIHBsYXRmb3JtLiAqLwoJaWYobnVtUGxhdGZvcm1zID4gMCkKCXsKCQljbF9wbGF0Zm9ybV9pZCogcGxhdGZvcm1zID0gKGNsX3BsYXRmb3JtX2lkKiApbWFsbG9jKG51bVBsYXRmb3Jtcyogc2l6ZW9mKGNsX3BsYXRmb3JtX2lkKSk7CgkJc3RhdHVzID0gY2xHZXRQbGF0Zm9ybUlEcyhudW1QbGF0Zm9ybXMsIHBsYXRmb3JtcywgTlVMTCk7CgkJcGxhdGZvcm0gPSBwbGF0Zm9ybXNbMF07CgkJZnJlZShwbGF0Zm9ybXMpOwoJfQoKCS8qU3RlcCAyOlF1ZXJ5IHRoZSBwbGF0Zm9ybSBhbmQgY2hvb3NlIHRoZSBmaXJzdCBHUFUgZGV2aWNlIGlmIGhhcyBvbmUuT3RoZXJ3aXNlIHVzZSB0aGUgQ1BVIGFzIGRldmljZS4qLwoJY2xfdWludAkJCQludW1EZXZpY2VzID0gMDsKCWNsX2RldmljZV9pZCAgICAgICAgKmRldmljZXM7CglzdGF0dXMgPSBjbEdldERldmljZUlEcyhwbGF0Zm9ybSwgQ0xfREVWSUNFX1RZUEVfR1BVLCAwLCBOVUxMLCAmbnVtRGV2aWNlcyk7CQoJaWYgKG51bURldmljZXMgPT0gMCkJLy9ubyBHUFUgYXZhaWxhYmxlLgoJewoJCWNvdXQgPDwgIk5vIEdQVSBkZXZpY2UgYXZhaWxhYmxlLiIgPDwgZW5kbDsKCQljb3V0IDw8ICJDaG9vc2UgQ1BVIGFzIGRlZmF1bHQgZGV2aWNlLiIgPDwgZW5kbDsKCQlzdGF0dXMgPSBjbEdldERldmljZUlEcyhwbGF0Zm9ybSwgQ0xfREVWSUNFX1RZUEVfQ1BVLCAwLCBOVUxMLCAmbnVtRGV2aWNlcyk7CQoJCWRldmljZXMgPSAoY2xfZGV2aWNlX2lkKiltYWxsb2MobnVtRGV2aWNlcyAqIHNpemVvZihjbF9kZXZpY2VfaWQpKTsKCQlzdGF0dXMgPSBjbEdldERldmljZUlEcyhwbGF0Zm9ybSwgQ0xfREVWSUNFX1RZUEVfQ1BVLCBudW1EZXZpY2VzLCBkZXZpY2VzLCBOVUxMKTsKCX0KCWVsc2UKCXsKCQlkZXZpY2VzID0gKGNsX2RldmljZV9pZCopbWFsbG9jKG51bURldmljZXMgKiBzaXplb2YoY2xfZGV2aWNlX2lkKSk7CgkJc3RhdHVzID0gY2xHZXREZXZpY2VJRHMocGxhdGZvcm0sIENMX0RFVklDRV9UWVBFX0dQVSwgbnVtRGV2aWNlcywgZGV2aWNlcywgTlVMTCk7Cgl9CgkKCgkvKlN0ZXAgMzogQ3JlYXRlIGNvbnRleHQuKi8KCWNsX2NvbnRleHQgY29udGV4dCA9IGNsQ3JlYXRlQ29udGV4dChOVUxMLDEsIGRldmljZXMsTlVMTCxOVUxMLE5VTEwpOwoJCgkvKlN0ZXAgNDogQ3JlYXRpbmcgY29tbWFuZCBxdWV1ZSBhc3NvY2lhdGUgd2l0aCB0aGUgY29udGV4dC4qLwoJLypvbGQgZnVuYy4gY29kZQoJCWNsX2NvbW1hbmRfcXVldWUgY29tbWFuZFF1ZXVlID0gY2xDcmVhdGVDb21tYW5kUXVldWUoY29udGV4dCwgZGV2aWNlc1swXSwgMCwgTlVMTCk7CiAgICAJKi8KCS8qbmV3IGZ1bmMuCiAgICAJKgljbF9jb21tYW5kX3F1ZXVlIGNsQ3JlYXRlQ29tbWFuZFF1ZXVlV2l0aFByb3BlcnRpZXMoCgkJCWNsX2NvbnRleHQgY29udGV4dCwgCgkJCWNsX2RldmljZV9pZCBkZXZpY2UsIAoJCQljb25zdCBjbF9xdWV1ZV9wcm9wZXJ0aWVzICpwcm9wZXJ0aWVzLCAKCQkJY2xfaW50ICplcnJjb2RlX3JldCkKCSovCgljbF9jb21tYW5kX3F1ZXVlIGNvbW1hbmRRdWV1ZSA9IGNsQ3JlYXRlQ29tbWFuZFF1ZXVlV2l0aFByb3BlcnRpZXMoY29udGV4dCwgZGV2aWNlc1swXSwgMCwgTlVMTCk7CgkvL2NsX2NvbW1hbmRfcXVldWUgY29tbWFuZFF1ZXVlID0gY2xDcmVhdGVDb21tYW5kUXVldWUoY29udGV4dCwgZGV2aWNlc1swXSwgMCwgTlVMTCk7CgoJLypTdGVwIDU6IENyZWF0ZSBwcm9ncmFtIG9iamVjdCAqLwoJY29uc3QgY2hhciAqZmlsZW5hbWUgPSAiSGVsbG9Xb3JsZF9LZXJuZWwuY2wiOwoJc3RyaW5nIHNvdXJjZVN0cjsKCXN0YXR1cyA9IGNvbnZlcnRUb1N0cmluZyhmaWxlbmFtZSwgc291cmNlU3RyKTsKCWNvbnN0IGNoYXIgKnNvdXJjZSA9IHNvdXJjZVN0ci5jX3N0cigpOwoJc2l6ZV90IHNvdXJjZVNpemVbXSA9IHtzdHJsZW4oc291cmNlKX07CgljbF9wcm9ncmFtIHByb2dyYW0gPSBjbENyZWF0ZVByb2dyYW1XaXRoU291cmNlKGNvbnRleHQsIDEsICZzb3VyY2UsIHNvdXJjZVNpemUsIE5VTEwpOwoJCgkvKlN0ZXAgNjogQnVpbGQgcHJvZ3JhbS4gKi8KCWNvbnN0IGNoYXIgb3B0aW9uc1tdID0gIi1jbC1zdGQ9Q0wyLjAiOwoJc3RhdHVzID0gY2xCdWlsZFByb2dyYW0ocHJvZ3JhbSwgMSxkZXZpY2VzLCBvcHRpb25zLE5VTEwsTlVMTCk7CgoJLypTdGVwIDc6IENyZWF0ZSBrZXJuZWwgb2JqZWN0ICovCgljbF9rZXJuZWwga2VybmVsID0gY2xDcmVhdGVLZXJuZWwocHJvZ3JhbSwiU1ZNaGVsbG93b3JsZCIsIE5VTEwpOwoJCgkvKlN0ZXAgODogSW5pdGlhbCBpbnB1dCxvdXRwdXQgZm9yIHRoZSBob3N0IGFuZCBjcmVhdGUgU1ZNIGJ1ZmZlciovCgljb25zdCBjaGFyICppbnB1dCA9ICJIZWxsb1dvcmxkIjsKCXNpemVfdCBzdHJsZW5ndGggPSBzdHJsZW4oaW5wdXQpOwoJY2hhciAqb3V0cHV0ID0gKGNoYXIqKSBtYWxsb2Moc3RybGVuZ3RoICsgMSk7Cgl2b2lkICppbnB1dEJ1ZmZlciA9IGNsU1ZNQWxsb2MoIGNvbnRleHQsIENMX01FTV9SRUFEX1dSSVRFLCAoc3RybGVuZ3RoICsgMSkgKiBzaXplb2YoY2hhciksIDAgKTsKCXZvaWQgKm91dHB1dEJ1ZmZlciA9IGNsU1ZNQWxsb2MoIGNvbnRleHQsIENMX01FTV9SRUFEX1dSSVRFLCAoc3RybGVuZ3RoICsgMSkgKiBzaXplb2YoY2hhciksIDAgKTsKCQoJc3RhdHVzID0gY2xFbnF1ZXVlU1ZNTWFwKGNvbW1hbmRRdWV1ZSwgQ0xfVFJVRSwgQ0xfTUFQX1dSSVRFX0lOVkFMSURBVEVfUkVHSU9OLCBpbnB1dEJ1ZmZlciwgKHN0cmxlbmd0aCArIDEpICogc2l6ZW9mKGNoYXIpLCAwLCBOVUxMLCBOVUxMKTsKCW1lbWNweShpbnB1dEJ1ZmZlcixpbnB1dCxzdHJsZW5ndGgpOwoJY291dCA8PCAiaW5wdXQgc3RyaW5nOiIgPDwgZW5kbDsKCWNvdXQgPDwgaW5wdXQgPDwgZW5kbDsKCS8qdGVzdCBpbnB1dEJ1ZmZlcgoJY291dCA8PCAiaW5wdXRCdWZmZXIgZmlyc3QgY2hhcjoiIDw8IGVuZGw7Cgljb3V0IDw8ICooKGNoYXIgKilpbnB1dEJ1ZmZlcikgPDwgZW5kbDsKCSovCglzdGF0dXMgPSBjbEVucXVldWVTVk1Vbm1hcChjb21tYW5kUXVldWUsIGlucHV0QnVmZmVyLCAwLCBOVUxMLCBOVUxMKTsKCQoJLypTdGVwIDk6IFNldHMgS2VybmVsIGFyZ3VtZW50cy4qLwoJc3RhdHVzID0gY2xTZXRLZXJuZWxBcmdTVk1Qb2ludGVyKGtlcm5lbCwwLCh2b2lkICopKGlucHV0QnVmZmVyKSk7CiAgICAJc3RhdHVzID0gY2xTZXRLZXJuZWxBcmdTVk1Qb2ludGVyKGtlcm5lbCwxLCh2b2lkICopKG91dHB1dEJ1ZmZlcikpOwogIAkKCS8qU3RlcCAxMDogUnVubmluZyB0aGUga2VybmVsLiovCglzaXplX3QgZ2xvYmFsX3dvcmtfc2l6ZVsxXSA9IHtzdHJsZW5ndGh9OwoJc3RhdHVzID0gY2xFbnF1ZXVlTkRSYW5nZUtlcm5lbChjb21tYW5kUXVldWUsIGtlcm5lbCwgMSwgTlVMTCwgZ2xvYmFsX3dvcmtfc2l6ZSwgTlVMTCwgMCwgTlVMTCwgTlVMTCk7CgogIAlzdGF0dXMgPSBjbEVucXVldWVTVk1NYXAoY29tbWFuZFF1ZXVlLCBDTF9UUlVFLCBDTF9NQVBfV1JJVEVfSU5WQUxJREFURV9SRUdJT04sIG91dHB1dEJ1ZmZlciwgKHN0cmxlbmd0aCArIDEpICogc2l6ZW9mKGNoYXIpLCAwLCBOVUxMLCBOVUxMKTsKCW1lbWNweShvdXRwdXQsb3V0cHV0QnVmZmVyLHN0cmxlbmd0aCk7CglvdXRwdXRbc3RybGVuZ3RoXSA9ICdcMCc7CS8vQWRkIHRoZSB0ZXJtaW5hbCBjaGFyYWN0ZXIgdG8gdGhlIGVuZCBvZiBvdXRwdXQuCgoJLyp0ZXN0IGlmIGtlcm5lbCB3b3JrcyBhbmQgY2hhci4gYXJlIGFsbCBhc3NpZ24gdG8gb3V0cHV0QnVmZmVyKi8KCWludCBpOwoJZm9yKGkgPSAwOyBpIDwgMTA7IGkrKyl7CgkJY291dCA8PCIjIiA8PCBpIDw8ICI6IiA8PCAqKCgoY2hhciAqKW91dHB1dEJ1ZmZlcikraSkgPDwgZW5kbDsKCX0KCgljb3V0IDw8ICJcbm91dHB1dCBzdHJpbmc6IiA8PCBlbmRsOwoJY291dCA8PCBvdXRwdXQgPDwgZW5kbDsKCiAgCXN0YXR1cyA9IGNsRW5xdWV1ZVNWTVVubWFwKGNvbW1hbmRRdWV1ZSwgb3V0cHV0QnVmZmVyLCAwLCBOVUxMLCBOVUxMKTsKCgkvKlN0ZXAgMTI6IENsZWFuIHRoZSByZXNvdXJjZXMuKi8KCWNsU1ZNRnJlZShjb250ZXh0LCBpbnB1dEJ1ZmZlcik7ICAKICAgIAljbFNWTUZyZWUoY29udGV4dCwgb3V0cHV0QnVmZmVyKTsgIAoJc3RhdHVzID0gY2xSZWxlYXNlS2VybmVsKGtlcm5lbCk7CQkJCS8vUmVsZWFzZSBrZXJuZWwuCglzdGF0dXMgPSBjbFJlbGVhc2VQcm9ncmFtKHByb2dyYW0pOwkJCQkvL1JlbGVhc2UgdGhlIHByb2dyYW0gb2JqZWN0LgoJc3RhdHVzID0gY2xSZWxlYXNlQ29tbWFuZFF1ZXVlKGNvbW1hbmRRdWV1ZSk7CS8vUmVsZWFzZSAgQ29tbWFuZCBxdWV1ZS4KCXN0YXR1cyA9IGNsUmVsZWFzZUNvbnRleHQoY29udGV4dCk7CQkJCS8vUmVsZWFzZSBjb250ZXh0LgoKCWlmIChvdXRwdXQgIT0gTlVMTCkKCXsKCQlmcmVlKG91dHB1dCk7CgkJb3V0cHV0ID0gTlVMTDsKCX0KCglpZiAoZGV2aWNlcyAhPSBOVUxMKQoJewoJCWZyZWUoZGV2aWNlcyk7CgkJZGV2aWNlcyA9IE5VTEw7Cgl9CgoJY291dDw8IlByb2dyYW0gcGFzc2VkIVxuIjsKCXJldHVybiBTVUNDRVNTOwp9