#include <math.h>
#include <string.h>
#include <GL/glut.h>
#define _CRT_SECURE_NO_WARNINGS
void setCamera( void );
void setLight( void );
void display( void );
void displayAxis( float length );
void keyboardFunction( unsigned char key, int x, int y );
void mouseFunction( int button, int state, int x, int y );
void motionFunction( int x, int y );
void printCharacter( const char* buffer, const int width, const int height );
void printParameter( void );
const int WINDOW_WIDTH = 512;
const int WINDOW_HEIGHT = 512;
const float DISTANCE_SCALE = 0.05f; // マウス移動量と距離の変換倍率
const float ANGLE_SCALE = 0.01f; // マウス移動量と角度の変換倍率
float distance = 6.0f; // カメラと注視点の距離
float angleX = 0.f; // カメラ極座標 X (rad)
float angleY = 0.f; // カメラ極座標 Y (rad)
int mouseX = 0; // マウスの位置xを格納する変数
int mouseY = 0; // マウスの位置yを格納する変数
int action = 0; // 操作中判別 0: 未操作, 1: 操作中
int mode = 0; // 0: ROTATE, 1: WALK
// main.cpp
#ifndef _MSC_VER
# define sprintf_s(b, s, f, ...) (sprintf((b), (f), __VA_ARGS__))
#endif
void setCamera( void ) {
glViewport( 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 30.f, ( GLdouble ) WINDOW_WIDTH / ( GLdouble ) WINDOW_HEIGHT,
0.1f, 100.f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
float cx = cosf(angleX), sx = sinf(angleX),
cy = cosf(angleY), sy = sinf(angleY);
gluLookAt( distance * cx * sy, distance * sx, distance * cx * cy,
0.f, 0.f, 0.f,
-sx * sy, cx, -sx * cy );
}
void setLight( void )
{
GLfloat light_position[ 4 ] = { 2.f, 2.f, 5.f, 1.f };
GLfloat light_ambient[ 4 ] = { 0.3f, 0.3f, 0.3f, 0.f };
GLfloat light_diffuse[ 4 ] = { 1.f, 1.f, 1.f, 1.f };
GLfloat light_specular[ 4 ] = { 1.f, 1.f, 1.f, 1.f };
glLightfv( GL_LIGHT0, GL_POSITION, light_position );
glLightfv( GL_LIGHT0, GL_AMBIENT, light_ambient );
glLightfv( GL_LIGHT0, GL_DIFFUSE, light_diffuse );
glLightfv( GL_LIGHT0, GL_SPECULAR, light_specular );
}
void displayAxis( float length )
{
glDisable( GL_LIGHTING );
glBegin( GL_LINES );
glColor3f( 1.f, 0.f, 0.f );
glVertex3f( 0.f, 0.f, 0.f );
glVertex3f( length, 0.f, 0.f );
glColor3f( 0.f, 1.f, 0.f );
glVertex3f( 0.f, 0.f, 0.f );
glVertex3f( 0.f, length, 0.f );
glColor3f( 0.f, 0.f, 1.f );
glVertex3f( 0.f, 0.f, 0.f );
glVertex3f( 0.f, 0.f, length );
glEnd();
}
void keyboardFunction( unsigned char key, int x, int y )
{
switch( key ) {
case 'q': exit( 0 ); break;
case 'r': mode = 0; break;
case 'w': mode = 1; break;
default: break;
}
glutPostRedisplay();
}
void mouseFunction( int button, int state, int x, int y )
{
switch (button) {
case GLUT_LEFT_BUTTON:
switch (state) {
case GLUT_DOWN:
action = 1; // 左クリックで操作開始
mouseX = x;
mouseY = y;
break;
case GLUT_UP:
action = 0; // ボタンUpで操作終了
break;
default:
break;
}
break;
default:
break;
}
glutPostRedisplay();
}
void motionFunction( int x, int y )
{
if (0 == action) { return; }
switch (mode) {
case 0:
angleX -= ANGLE_SCALE * (float)(mouseY - y);
angleY += ANGLE_SCALE * (float)(mouseX - x);
break;
case 1:
distance += DISTANCE_SCALE * (float)(mouseY - y);
distance = distance < 0.0f ? 0.0f : distance;
distance = 100.0f < distance ? 100.0f : distance;
break;
default:
break;
}
mouseX = x;
mouseY = y;
glutPostRedisplay();
}
void printCharacter( const char* buffer, const int width, const int height )
{
glDisable( GL_LIGHTING );
glMatrixMode( GL_PROJECTION ); glPushMatrix(); {
glLoadIdentity();
gluOrtho2D( 0.0, ( GLdouble ) WINDOW_WIDTH,
0.0, ( GLdouble ) WINDOW_HEIGHT );
glViewport( 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT );
glMatrixMode( GL_MODELVIEW ); glPushMatrix(); {
glLoadIdentity();
glColor3f( 1.0f, 1.0f, 1.0f );
glRasterPos2i( width, WINDOW_HEIGHT - height );
for( unsigned i = 0; i < strlen( buffer ); i++ ) {
glutBitmapCharacter( GLUT_BITMAP_HELVETICA_12, buffer[ i ] );
}
} glMatrixMode( GL_MODELVIEW ); glPopMatrix();
} glMatrixMode( GL_PROJECTION ); glPopMatrix();
}
void printParameter( void )
{
char buffer[ 256 ];
sprintf_s( buffer, sizeof( buffer ), "mode : [ %s ]",
0 == mode ? "ROTATE" : "WALK");
printCharacter( buffer, 10, 30 );
sprintf_s( buffer, sizeof( buffer ), "distance : [ %+3.2f ]", distance);
printCharacter( buffer, 10, 50 );
sprintf_s( buffer, sizeof( buffer ), "angle(deg) : [ %+3.2f, %+3.2f ]",
angleX / M_PI * 180.0, angleY / M_PI * 180.0);
printCharacter( buffer, 10, 70 );
}
void display( void )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
printParameter();
setCamera();
setLight();
displayAxis( 10.f );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glutSolidTeapot(0.5);
glutSwapBuffers();
}
int main( int argc, char** argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( WINDOW_WIDTH, WINDOW_HEIGHT );
glutCreateWindow( "OpenGL Based Renderer" );
glClearColor( 0.f, 0.f, 0.f, 0.f );
glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LESS );
glutDisplayFunc( display );
glutKeyboardFunc( keyboardFunction );
glutMouseFunc( mouseFunction );
glutMotionFunc( motionFunction );
glutMainLoop();
return 0;
}
I2luY2x1ZGUgPG1hdGguaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8R0wvZ2x1dC5oPgoKI2RlZmluZSBfQ1JUX1NFQ1VSRV9OT19XQVJOSU5HUwoKdm9pZCBzZXRDYW1lcmEoIHZvaWQgKTsKdm9pZCBzZXRMaWdodCggdm9pZCApOwoKdm9pZCBkaXNwbGF5KCB2b2lkICk7CnZvaWQgZGlzcGxheUF4aXMoIGZsb2F0IGxlbmd0aCApOwoKdm9pZCBrZXlib2FyZEZ1bmN0aW9uKCB1bnNpZ25lZCBjaGFyIGtleSwgaW50IHgsIGludCB5ICk7CnZvaWQgbW91c2VGdW5jdGlvbiggaW50IGJ1dHRvbiwgaW50IHN0YXRlLCBpbnQgeCwgaW50IHkgKTsKdm9pZCBtb3Rpb25GdW5jdGlvbiggaW50IHgsIGludCB5ICk7Cgp2b2lkIHByaW50Q2hhcmFjdGVyKCBjb25zdCBjaGFyKiBidWZmZXIsIGNvbnN0IGludCB3aWR0aCwgY29uc3QgaW50IGhlaWdodCApOwp2b2lkIHByaW50UGFyYW1ldGVyKCB2b2lkICk7Cgpjb25zdCBpbnQgV0lORE9XX1dJRFRIID0gNTEyOwpjb25zdCBpbnQgV0lORE9XX0hFSUdIVCA9IDUxMjsKCmNvbnN0IGZsb2F0IERJU1RBTkNFX1NDQUxFID0gMC4wNWY7ICAgICAvLyDjg57jgqbjgrnnp7vli5Xph4/jgajot53pm6Ljga7lpInmj5vlgI3njocKY29uc3QgZmxvYXQgQU5HTEVfU0NBTEUgPSAwLjAxZjsgICAgICAgIC8vIOODnuOCpuOCueenu+WLlemHj+OBqOinkuW6puOBruWkieaPm+WAjeeOhwoKZmxvYXQgZGlzdGFuY2UgPSA2LjBmOyAgICAgICAgICAgICAgICAgIC8vIOOCq+ODoeODqeOBqOazqOimlueCueOBrui3nembogpmbG9hdCBhbmdsZVggPSAwLmY7ICAgICAgICAgICAgICAgICAgICAgLy8g44Kr44Oh44Op5qW15bqn5qiZIFggKHJhZCkKZmxvYXQgYW5nbGVZID0gMC5mOyAgICAgICAgICAgICAgICAgICAgIC8vIOOCq+ODoeODqealteW6p+aomSBZIChyYWQpCgppbnQgbW91c2VYID0gMDsgICAgICAgICAgICAgICAgICAgICAgICAgLy8g44Oe44Km44K544Gu5L2N572ueOOCkuagvOe0jeOBmeOCi+WkieaVsAppbnQgbW91c2VZID0gMDsgICAgICAgICAgICAgICAgICAgICAgICAgLy8g44Oe44Km44K544Gu5L2N572ueeOCkuagvOe0jeOBmeOCi+WkieaVsAoKaW50IGFjdGlvbiA9IDA7ICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOaTjeS9nOS4reWIpOWIpSAwOiDmnKrmk43kvZwsIDE6IOaTjeS9nOS4rQppbnQgbW9kZSA9IDA7ICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMDogUk9UQVRFLCAxOiBXQUxLCgovLyBtYWluLmNwcAojaWZuZGVmIF9NU0NfVkVSCiMgZGVmaW5lIHNwcmludGZfcyhiLCBzLCBmLCAuLi4pIChzcHJpbnRmKChiKSwgKGYpLCBfX1ZBX0FSR1NfXykpCiNlbmRpZgoKdm9pZCBzZXRDYW1lcmEoIHZvaWQgKSB7CiAgZ2xWaWV3cG9ydCggMCwgMCwgV0lORE9XX1dJRFRILCBXSU5ET1dfSEVJR0hUICk7CgogIGdsTWF0cml4TW9kZSggR0xfUFJPSkVDVElPTiApOwogIGdsTG9hZElkZW50aXR5KCk7CiAgZ2x1UGVyc3BlY3RpdmUoIDMwLmYsICggR0xkb3VibGUgKSBXSU5ET1dfV0lEVEggLyAoIEdMZG91YmxlICkgV0lORE9XX0hFSUdIVCwKICAgICAgICAgICAgICAgICAgMC4xZiwgMTAwLmYgKTsKCiAgZ2xNYXRyaXhNb2RlKCBHTF9NT0RFTFZJRVcgKTsKICBnbExvYWRJZGVudGl0eSgpOwoKICBmbG9hdCBjeCA9IGNvc2YoYW5nbGVYKSwgc3ggPSBzaW5mKGFuZ2xlWCksCiAgICAgICAgY3kgPSBjb3NmKGFuZ2xlWSksIHN5ID0gc2luZihhbmdsZVkpOwogIGdsdUxvb2tBdCggZGlzdGFuY2UgKiBjeCAqIHN5LCBkaXN0YW5jZSAqIHN4LCBkaXN0YW5jZSAqIGN4ICogY3ksCiAgICAgICAgICAgICAwLmYsIDAuZiwgMC5mLAogICAgICAgICAgICAgLXN4ICogc3ksIGN4LCAtc3ggKiBjeSApOwp9Cgp2b2lkIHNldExpZ2h0KCB2b2lkICkKewogIEdMZmxvYXQgbGlnaHRfcG9zaXRpb25bIDQgXSA9IHsgMi5mLCAyLmYsIDUuZiwgMS5mIH07CiAgR0xmbG9hdCBsaWdodF9hbWJpZW50WyA0IF0gPSB7IDAuM2YsIDAuM2YsIDAuM2YsIDAuZiB9OwogIEdMZmxvYXQgbGlnaHRfZGlmZnVzZVsgNCBdID0geyAxLmYsIDEuZiwgMS5mLCAxLmYgfTsKICBHTGZsb2F0IGxpZ2h0X3NwZWN1bGFyWyA0IF0gPSB7IDEuZiwgMS5mLCAxLmYsIDEuZiB9OwogIGdsTGlnaHRmdiggR0xfTElHSFQwLCBHTF9QT1NJVElPTiwgbGlnaHRfcG9zaXRpb24gKTsKICBnbExpZ2h0ZnYoIEdMX0xJR0hUMCwgR0xfQU1CSUVOVCwgbGlnaHRfYW1iaWVudCApOwogIGdsTGlnaHRmdiggR0xfTElHSFQwLCBHTF9ESUZGVVNFLCBsaWdodF9kaWZmdXNlICk7CiAgZ2xMaWdodGZ2KCBHTF9MSUdIVDAsIEdMX1NQRUNVTEFSLCBsaWdodF9zcGVjdWxhciApOwp9Cgp2b2lkIGRpc3BsYXlBeGlzKCBmbG9hdCBsZW5ndGggKQp7CiAgZ2xEaXNhYmxlKCBHTF9MSUdIVElORyApOwogIGdsQmVnaW4oIEdMX0xJTkVTICk7CiAgZ2xDb2xvcjNmKCAxLmYsIDAuZiwgMC5mICk7CiAgZ2xWZXJ0ZXgzZiggMC5mLCAwLmYsIDAuZiApOwogIGdsVmVydGV4M2YoIGxlbmd0aCwgMC5mLCAwLmYgKTsKCiAgZ2xDb2xvcjNmKCAwLmYsIDEuZiwgMC5mICk7CiAgZ2xWZXJ0ZXgzZiggMC5mLCAwLmYsIDAuZiApOwogIGdsVmVydGV4M2YoIDAuZiwgbGVuZ3RoLCAwLmYgKTsKCiAgZ2xDb2xvcjNmKCAwLmYsIDAuZiwgMS5mICk7CiAgZ2xWZXJ0ZXgzZiggMC5mLCAwLmYsIDAuZiApOwogIGdsVmVydGV4M2YoIDAuZiwgMC5mLCBsZW5ndGggKTsKICBnbEVuZCgpOwp9Cgp2b2lkIGtleWJvYXJkRnVuY3Rpb24oIHVuc2lnbmVkIGNoYXIga2V5LCBpbnQgeCwgaW50IHkgKQp7CiAgc3dpdGNoKCBrZXkgKSB7CiAgICBjYXNlICdxJzogICBleGl0KCAwICk7ICAgICAgYnJlYWs7CiAgICBjYXNlICdyJzogICBtb2RlID0gMDsgICAgICAgYnJlYWs7CiAgICBjYXNlICd3JzogICBtb2RlID0gMTsgICAgICAgYnJlYWs7CiAgICBkZWZhdWx0OiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgfQogIGdsdXRQb3N0UmVkaXNwbGF5KCk7Cn0KCnZvaWQgbW91c2VGdW5jdGlvbiggaW50IGJ1dHRvbiwgaW50IHN0YXRlLCBpbnQgeCwgaW50IHkgKQp7CiAgc3dpdGNoIChidXR0b24pIHsKICAgIGNhc2UgR0xVVF9MRUZUX0JVVFRPTjoKICAgICAgc3dpdGNoIChzdGF0ZSkgewogICAgICAgIGNhc2UgR0xVVF9ET1dOOgogICAgICAgICAgYWN0aW9uID0gMTsgICAgICAgICAgIC8vIOW3puOCr+ODquODg+OCr+OBp+aTjeS9nOmWi+WniwogICAgICAgICAgbW91c2VYID0geDsKICAgICAgICAgIG1vdXNlWSA9IHk7CiAgICAgICAgICBicmVhazsKICAgICAgICBjYXNlIEdMVVRfVVA6CiAgICAgICAgICBhY3Rpb24gPSAwOyAgICAgICAgICAgLy8g44Oc44K/44OzVXDjgafmk43kvZzntYLkuoYKICAgICAgICAgIGJyZWFrOwogICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICBicmVhazsKICAgICAgfQogICAgICBicmVhazsKICAgIGRlZmF1bHQ6CiAgICAgIGJyZWFrOwogIH0KICBnbHV0UG9zdFJlZGlzcGxheSgpOwp9Cgp2b2lkIG1vdGlvbkZ1bmN0aW9uKCBpbnQgeCwgaW50IHkgKQp7CiAgaWYgKDAgPT0gYWN0aW9uKSB7IHJldHVybjsgfQogIHN3aXRjaCAobW9kZSkgewogICAgY2FzZSAwOgogICAgICBhbmdsZVggLT0gQU5HTEVfU0NBTEUgKiAoZmxvYXQpKG1vdXNlWSAtIHkpOwogICAgICBhbmdsZVkgKz0gQU5HTEVfU0NBTEUgKiAoZmxvYXQpKG1vdXNlWCAtIHgpOwogICAgICBicmVhazsKICAgIGNhc2UgMToKICAgICAgZGlzdGFuY2UgKz0gRElTVEFOQ0VfU0NBTEUgKiAoZmxvYXQpKG1vdXNlWSAtIHkpOwogICAgICBkaXN0YW5jZSA9IGRpc3RhbmNlIDwgICAgIDAuMGYgPyAgIDAuMGYgOiBkaXN0YW5jZTsKICAgICAgZGlzdGFuY2UgPSAgIDEwMC4wZiA8IGRpc3RhbmNlID8gMTAwLjBmIDogZGlzdGFuY2U7CiAgICAgIGJyZWFrOwogICAgZGVmYXVsdDoKICAgICAgYnJlYWs7CiAgfQogIG1vdXNlWCA9IHg7CiAgbW91c2VZID0geTsKICBnbHV0UG9zdFJlZGlzcGxheSgpOwp9Cgp2b2lkIHByaW50Q2hhcmFjdGVyKCBjb25zdCBjaGFyKiBidWZmZXIsIGNvbnN0IGludCB3aWR0aCwgY29uc3QgaW50IGhlaWdodCApCnsKICBnbERpc2FibGUoIEdMX0xJR0hUSU5HICk7CiAgZ2xNYXRyaXhNb2RlKCBHTF9QUk9KRUNUSU9OICk7IGdsUHVzaE1hdHJpeCgpOyB7CiAgICBnbExvYWRJZGVudGl0eSgpOwogICAgZ2x1T3J0aG8yRCggMC4wLCAoIEdMZG91YmxlICkgV0lORE9XX1dJRFRILAogICAgICAgICAgICAgICAgMC4wLCAoIEdMZG91YmxlICkgV0lORE9XX0hFSUdIVCApOwogICAgZ2xWaWV3cG9ydCggMCwgMCwgV0lORE9XX1dJRFRILCBXSU5ET1dfSEVJR0hUICk7CiAgICBnbE1hdHJpeE1vZGUoIEdMX01PREVMVklFVyApOyBnbFB1c2hNYXRyaXgoKTsgewogICAgICBnbExvYWRJZGVudGl0eSgpOwogICAgICBnbENvbG9yM2YoIDEuMGYsIDEuMGYsIDEuMGYgKTsKICAgICAgZ2xSYXN0ZXJQb3MyaSggd2lkdGgsIFdJTkRPV19IRUlHSFQgLSBoZWlnaHQgKTsKICAgICAgZm9yKCB1bnNpZ25lZCBpID0gMDsgaSA8IHN0cmxlbiggYnVmZmVyICk7IGkrKyApIHsKICAgICAgICBnbHV0Qml0bWFwQ2hhcmFjdGVyKCBHTFVUX0JJVE1BUF9IRUxWRVRJQ0FfMTIsIGJ1ZmZlclsgaSBdICk7CiAgICAgIH0KICAgIH0gZ2xNYXRyaXhNb2RlKCBHTF9NT0RFTFZJRVcgKTsgZ2xQb3BNYXRyaXgoKTsKICB9IGdsTWF0cml4TW9kZSggR0xfUFJPSkVDVElPTiApOyBnbFBvcE1hdHJpeCgpOwp9Cgp2b2lkIHByaW50UGFyYW1ldGVyKCB2b2lkICkKewogIGNoYXIgYnVmZmVyWyAyNTYgXTsKICBzcHJpbnRmX3MoIGJ1ZmZlciwgc2l6ZW9mKCBidWZmZXIgKSwgIm1vZGUgICAgICAgOiBbICVzIF0iLAogICAgICAgICAgICAgMCA9PSBtb2RlID8gIlJPVEFURSIgOiAiV0FMSyIpOwogIHByaW50Q2hhcmFjdGVyKCBidWZmZXIsIDEwLCAzMCApOwoKICBzcHJpbnRmX3MoIGJ1ZmZlciwgc2l6ZW9mKCBidWZmZXIgKSwgImRpc3RhbmNlICAgOiBbICUrMy4yZiBdIiwgZGlzdGFuY2UpOwogIHByaW50Q2hhcmFjdGVyKCBidWZmZXIsIDEwLCA1MCApOwoKICBzcHJpbnRmX3MoIGJ1ZmZlciwgc2l6ZW9mKCBidWZmZXIgKSwgImFuZ2xlKGRlZykgOiBbICUrMy4yZiwgJSszLjJmIF0iLAogICAgICAgICAgICAgYW5nbGVYIC8gTV9QSSAqIDE4MC4wLCBhbmdsZVkgLyBNX1BJICogMTgwLjApOwogIHByaW50Q2hhcmFjdGVyKCBidWZmZXIsIDEwLCA3MCApOwp9Cgp2b2lkIGRpc3BsYXkoIHZvaWQgKQp7CiAgZ2xDbGVhciggR0xfQ09MT1JfQlVGRkVSX0JJVCB8IEdMX0RFUFRIX0JVRkZFUl9CSVQgKTsKCiAgcHJpbnRQYXJhbWV0ZXIoKTsKCiAgc2V0Q2FtZXJhKCk7CiAgc2V0TGlnaHQoKTsKCiAgZGlzcGxheUF4aXMoIDEwLmYgKTsKCiAgZ2xFbmFibGUoIEdMX0xJR0hUSU5HICk7CiAgZ2xFbmFibGUoIEdMX0xJR0hUMCApOwogIGdsdXRTb2xpZFRlYXBvdCgwLjUpOwoKICBnbHV0U3dhcEJ1ZmZlcnMoKTsKfQoKaW50IG1haW4oIGludCBhcmdjLCBjaGFyKiogYXJndiApCnsKICBnbHV0SW5pdCggJmFyZ2MsIGFyZ3YgKTsKICBnbHV0SW5pdERpc3BsYXlNb2RlKCBHTFVUX1JHQkEgfCBHTFVUX0RFUFRIIHwgR0xVVF9ET1VCTEUgKTsKICBnbHV0SW5pdFdpbmRvd1NpemUoIFdJTkRPV19XSURUSCwgV0lORE9XX0hFSUdIVCApOwogIGdsdXRDcmVhdGVXaW5kb3coICJPcGVuR0wgQmFzZWQgUmVuZGVyZXIiICk7CiAgZ2xDbGVhckNvbG9yKCAwLmYsIDAuZiwgMC5mLCAwLmYgKTsKICBnbEVuYWJsZSggR0xfREVQVEhfVEVTVCApOwogIGdsRGVwdGhGdW5jKCBHTF9MRVNTICk7CgogIGdsdXREaXNwbGF5RnVuYyggZGlzcGxheSApOwogIGdsdXRLZXlib2FyZEZ1bmMoIGtleWJvYXJkRnVuY3Rpb24gKTsKICBnbHV0TW91c2VGdW5jKCBtb3VzZUZ1bmN0aW9uICk7CiAgZ2x1dE1vdGlvbkZ1bmMoIG1vdGlvbkZ1bmN0aW9uICk7CgogIGdsdXRNYWluTG9vcCgpOwoKICByZXR1cm4gMDsKfQo=