/* Copyright (c) Mark J. Kilgard, 1996. */
/* This program is freely distributable without licensing fees
and is provided without guarantee or warrantee expressed or
implied. This program is -not- in the public domain. */
/* This program was originally written by someone else (Simon Hui?);
I just added a bit more GLUT stuff to it. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
#define VORDER 10
#define CORDER 10
#define TORDER 3
#define VMAJOR_ORDER 2
#define VMINOR_ORDER 3
#define CMAJOR_ORDER 2
#define CMINOR_ORDER 2
#define TMAJOR_ORDER 2
#define TMINOR_ORDER 2
#define VDIM 4
#define CDIM 4
#define TDIM 2
#define ONE_D 1
#define TWO_D 2
#define EVAL 3
#define MESH 4
GLenum doubleBuffer;
float rotX = 0.0, rotY = 0.0, translateZ = -1.0;
GLenum arrayType = ONE_D;
GLenum colorType = GL_FALSE;
GLenum textureType = GL_FALSE;
GLenum polygonFilled = GL_FALSE;
GLenum lighting = GL_FALSE;
GLenum mapPoint = GL_FALSE;
GLenum mapType = EVAL;
double point1[10 * 4] =
{
-0.5, 0.0, 0.0, 1.0,
-0.4, 0.5, 0.0, 1.0,
-0.3, -0.5, 0.0, 1.0,
-0.2, 0.5, 0.0, 1.0,
-0.1, -0.5, 0.0, 1.0,
0.0, 0.5, 0.0, 1.0,
0.1, -0.5, 0.0, 1.0,
0.2, 0.5, 0.0, 1.0,
0.3, -0.5, 0.0, 1.0,
0.4, 0.0, 0.0, 1.0,
};
double cpoint1[10 * 4] =
{
0.0, 0.0, 1.0, 1.0,
0.3, 0.0, 0.7, 1.0,
0.6, 0.0, 0.3, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 0.3, 0.0, 1.0,
1.0, 0.6, 0.0, 1.0,
1.0, 1.0, 0.0, 1.0,
1.0, 1.0, 0.5, 1.0,
1.0, 1.0, 1.0, 1.0,
};
double tpoint1[11 * 4] =
{
0.0, 0.0, 0.0, 1.0,
0.0, 0.1, 0.0, 1.0,
0.0, 0.2, 0.0, 1.0,
0.0, 0.3, 0.0, 1.0,
0.0, 0.4, 0.0, 1.0,
0.0, 0.5, 0.0, 1.0,
0.0, 0.6, 0.0, 1.0,
0.0, 0.7, 0.0, 1.0,
0.0, 0.8, 0.0, 1.0,
0.0, 0.9, 0.0, 1.0,
};
double point2[2 * 3 * 4] =
{
-0.5, -0.5, 0.5, 1.0,
0.0, 1.0, 0.5, 1.0,
0.5, -0.5, 0.5, 1.0,
-0.5, 0.5, -0.5, 1.0,
0.0, -1.0, -0.5, 1.0,
0.5, 0.5, -0.5, 1.0,
};
double cpoint2[2 * 2 * 4] =
{
0.0, 0.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0,
};
double tpoint2[2 * 2 * 2] =
{
0.0, 0.0, 0.0, 1.0,
1.0, 0.0, 1.0, 1.0,
};
float textureImage[4 * 2 * 4] =
{
1.0, 1.0, 1.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0,
};
static void
Init(void)
{
static float ambient[] =
{0.1, 0.1, 0.1, 1.0};
static float diffuse[] =
{1.0, 1.0, 1.0, 1.0};
static float position[] =
{0.0, 0.0, -150.0, 0.0};
static float front_mat_diffuse[] =
{1.0, 0.2, 1.0, 1.0};
static float back_mat_diffuse[] =
{1.0, 1.0, 0.2, 1.0};
static float lmodel_ambient[] =
{1.0, 1.0, 1.0, 1.0};
static float lmodel_twoside[] =
{GL_TRUE};
static float decal[] =
{GL_DECAL};
static float repeat[] =
{GL_REPEAT};
static float nr[] =
{GL_NEAREST};
glFrontFace(GL_CCW);
glEnable(GL_DEPTH_TEST);
glMap1d(GL_MAP1_VERTEX_4, 0.0, 1.0, VDIM, VORDER, point1);
glMap1d(GL_MAP1_COLOR_4, 0.0, 1.0, CDIM, CORDER, cpoint1);
glMap2d(GL_MAP2_VERTEX_4, 0.0, 1.0, VMINOR_ORDER * VDIM, VMAJOR_ORDER, 0.0,
1.0, VDIM, VMINOR_ORDER, point2);
glMap2d(GL_MAP2_COLOR_4, 0.0, 1.0, CMINOR_ORDER * CDIM, CMAJOR_ORDER, 0.0,
1.0, CDIM, CMINOR_ORDER, cpoint2);
glMap2d(GL_MAP2_TEXTURE_COORD_2, 0.0, 1.0, TMINOR_ORDER * TDIM,
TMAJOR_ORDER, 0.0, 1.0, TDIM, TMINOR_ORDER, tpoint2);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glMaterialfv(GL_FRONT, GL_DIFFUSE, front_mat_diffuse);
glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, decal);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, repeat);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, repeat);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nr);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nr);
glTexImage2D(GL_TEXTURE_2D, 0, 4, 2, 4, 0, GL_RGBA, GL_FLOAT,
(GLvoid *) textureImage);
}
static void
DrawPoints1(void)
{
GLint i;
glColor3f(0.0, 1.0, 0.0);
glPointSize(2);
glBegin(GL_POINTS);
for (i = 0; i < VORDER; i++) {
glVertex4dv(&point1[i * 4]);
}
glEnd();
}
static void
DrawPoints2(void)
{
GLint i, j;
glColor3f(1.0, 0.0, 1.0);
glPointSize(2);
glBegin(GL_POINTS);
for (i = 0; i < VMAJOR_ORDER; i++) {
for (j = 0; j < VMINOR_ORDER; j++) {
glVertex4dv(&point2[i * 4 * VMINOR_ORDER + j * 4]);
}
}
glEnd();
}
static void
DrawMapEval1(float du)
{
float u;
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_LINE_STRIP);
for (u = 0.0; u < 1.0; u += du) {
glEvalCoord1d(u);
}
glEvalCoord1d(1.0);
glEnd();
}
static void
DrawMapEval2(float du, float dv)
{
float u, v, tmp;
glColor3f(1.0, 0.0, 0.0);
for (v = 0.0; v < 1.0; v += dv) {
glBegin(GL_QUAD_STRIP);
for (u = 0.0; u <= 1.0; u += du) {
glEvalCoord2d(u, v);
tmp = (v + dv < 1.0) ? (v + dv) : 1.0;
glEvalCoord2d(u, tmp);
}
glEvalCoord2d(1.0, v);
glEvalCoord2d(1.0, v + dv);
glEnd();
}
}
static void
RenderEval(void)
{
if (colorType) {
glEnable(GL_MAP1_COLOR_4);
glEnable(GL_MAP2_COLOR_4);
} else {
glDisable(GL_MAP1_COLOR_4);
glDisable(GL_MAP2_COLOR_4);
}
if (textureType) {
glEnable(GL_TEXTURE_2D);
glEnable(GL_MAP2_TEXTURE_COORD_2);
} else {
glDisable(GL_TEXTURE_2D);
glDisable(GL_MAP2_TEXTURE_COORD_2);
}
if (polygonFilled) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
glShadeModel(GL_SMOOTH);
switch (mapType) {
case EVAL:
switch (arrayType) {
case ONE_D:
glDisable(GL_MAP2_VERTEX_4);
glEnable(GL_MAP1_VERTEX_4);
DrawPoints1();
DrawMapEval1(0.1 / VORDER);
break;
case TWO_D:
glDisable(GL_MAP1_VERTEX_4);
glEnable(GL_MAP2_VERTEX_4);
DrawPoints2();
DrawMapEval2(0.1 / VMAJOR_ORDER, 0.1 / VMINOR_ORDER);
break;
}
break;
case MESH:
switch (arrayType) {
case ONE_D:
DrawPoints1();
glDisable(GL_MAP2_VERTEX_4);
glEnable(GL_MAP1_VERTEX_4);
glColor3f(0.0, 0.0, 1.0);
glMapGrid1d(40, 0.0, 1.0);
if (mapPoint) {
glPointSize(2);
glEvalMesh1(GL_POINT, 0, 40);
} else {
glEvalMesh1(GL_LINE, 0, 40);
}
break;
case TWO_D:
DrawPoints2();
glDisable(GL_MAP1_VERTEX_4);
glEnable(GL_MAP2_VERTEX_4);
glColor3f(0.0, 0.0, 1.0);
glMapGrid2d(20, 0.0, 1.0, 20, 0.0, 1.0);
if (mapPoint) {
glPointSize(2);
glEvalMesh2(GL_POINT, 0, 20, 0, 20);
} else if (polygonFilled) {
glEvalMesh2(GL_FILL, 0, 20, 0, 20);
} else {
glEvalMesh2(GL_LINE, 0, 20, 0, 20);
}
break;
}
break;
}
}
static void
Reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 10.0);
glMatrixMode(GL_MODELVIEW);
}
/* ARGSUSED1 */
static void
Key(unsigned char key, int x, int y)
{
switch (key) {
case '1':
arrayType = ONE_D;
glDisable(GL_AUTO_NORMAL);
glutPostRedisplay();
break;
case '2':
arrayType = TWO_D;
glEnable(GL_AUTO_NORMAL);
glutPostRedisplay();
break;
case '3':
mapType = EVAL;
glutPostRedisplay();
break;
case '4':
mapType = MESH;
glutPostRedisplay();
break;
case '5':
polygonFilled = !polygonFilled;
glutPostRedisplay();
break;
case '6':
mapPoint = !mapPoint;
glutPostRedisplay();
break;
case '7':
colorType = !colorType;
glutPostRedisplay();
break;
case '8':
textureType = !textureType;
glutPostRedisplay();
break;
case '9':
lighting = !lighting;
if (lighting) {
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
if (arrayType == TWO_D) {
glEnable(GL_AUTO_NORMAL);
} else {
glDisable(GL_AUTO_NORMAL);
}
} else {
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glDisable(GL_AUTO_NORMAL);
}
glutPostRedisplay();
break;
case 27: /* Escape key. */
exit(0);
}
}
static void
Menu(int value)
{
/* Menu items have key values assigned to them. Just pass
this value to the key routine. */
Key(value, 0, 0);
}
/* ARGSUSED1 */
static void
SpecialKey(int key, int x, int y)
{
switch (key) {
case GLUT_KEY_LEFT:
rotY -= 30;
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT:
rotY += 30;
glutPostRedisplay();
break;
case GLUT_KEY_UP:
rotX -= 30;
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
rotX += 30;
glutPostRedisplay();
break;
}
}
static void
Draw(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0, 0.0, translateZ);
glRotatef(rotX, 1, 0, 0);
glRotatef(rotY, 0, 1, 0);
RenderEval();
glPopMatrix();
if (doubleBuffer) {
glutSwapBuffers();
} else {
glFlush();
}
}
static void
Args(int argc, char **argv)
{
GLint i;
doubleBuffer = GL_FALSE;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-sb") == 0) {
doubleBuffer = GL_FALSE;
} else if (strcmp(argv[i], "-db") == 0) {
doubleBuffer = GL_TRUE;
}
}
}
int
main(int argc, char **argv)
{
GLenum type;
glutInit(&argc, argv);
Args(argc, argv);
type = GLUT_RGB | GLUT_DEPTH;
type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE;
glutInitDisplayMode(type);
glutInitWindowSize(300, 300);
glutCreateWindow("Evaluator Test");
glutCreateMenu(Menu);
glutAddMenuEntry("One dimensional", '1');
glutAddMenuEntry("Two dimensional", '2');
glutAddMenuEntry("Eval map type", '3');
glutAddMenuEntry("Mesh map type", '4');
glutAddMenuEntry("Toggle filled", '5');
glutAddMenuEntry("Toggle map point", '6');
glutAddMenuEntry("Toggle color", '7');
glutAddMenuEntry("Toggle texture", '8');
glutAddMenuEntry("Toggle lighting", '9');
glutAddMenuEntry("Quit", 27);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutAttachMenu(GLUT_LEFT_BUTTON);
Init();
glutReshapeFunc(Reshape);
glutKeyboardFunc(Key);
glutSpecialFunc(SpecialKey);
glutDisplayFunc(Draw);
glutMainLoop();
return 0;
}
Ci8qIENvcHlyaWdodCAoYykgTWFyayBKLiBLaWxnYXJkLCAxOTk2LiAqLwoKLyogVGhpcyBwcm9ncmFtIGlzIGZyZWVseSBkaXN0cmlidXRhYmxlIHdpdGhvdXQgbGljZW5zaW5nIGZlZXMgCiAgIGFuZCBpcyBwcm92aWRlZCB3aXRob3V0IGd1YXJhbnRlZSBvciB3YXJyYW50ZWUgZXhwcmVzc2VkIG9yIAogICBpbXBsaWVkLiBUaGlzIHByb2dyYW0gaXMgLW5vdC0gaW4gdGhlIHB1YmxpYyBkb21haW4uICovCgovKiBUaGlzIHByb2dyYW0gd2FzIG9yaWdpbmFsbHkgd3JpdHRlbiBieSBzb21lb25lIGVsc2UgKFNpbW9uIEh1aT8pOwogICBJIGp1c3QgYWRkZWQgYSBiaXQgbW9yZSBHTFVUIHN0dWZmIHRvIGl0LiAqLwoKI2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdHJpbmcuaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8bWF0aC5oPgojaW5jbHVkZSA8R0wvZ2x1dC5oPgoKI2RlZmluZSBWT1JERVIgMTAKI2RlZmluZSBDT1JERVIgMTAKI2RlZmluZSBUT1JERVIgMwoKI2RlZmluZSBWTUFKT1JfT1JERVIgMgojZGVmaW5lIFZNSU5PUl9PUkRFUiAzCgojZGVmaW5lIENNQUpPUl9PUkRFUiAyCiNkZWZpbmUgQ01JTk9SX09SREVSIDIKCiNkZWZpbmUgVE1BSk9SX09SREVSIDIKI2RlZmluZSBUTUlOT1JfT1JERVIgMgoKI2RlZmluZSBWRElNIDQKI2RlZmluZSBDRElNIDQKI2RlZmluZSBURElNIDIKCiNkZWZpbmUgT05FX0QgMQojZGVmaW5lIFRXT19EIDIKCiNkZWZpbmUgRVZBTCAzCiNkZWZpbmUgTUVTSCA0CgpHTGVudW0gZG91YmxlQnVmZmVyOwoKZmxvYXQgcm90WCA9IDAuMCwgcm90WSA9IDAuMCwgdHJhbnNsYXRlWiA9IC0xLjA7CgpHTGVudW0gYXJyYXlUeXBlID0gT05FX0Q7CkdMZW51bSBjb2xvclR5cGUgPSBHTF9GQUxTRTsKR0xlbnVtIHRleHR1cmVUeXBlID0gR0xfRkFMU0U7CkdMZW51bSBwb2x5Z29uRmlsbGVkID0gR0xfRkFMU0U7CkdMZW51bSBsaWdodGluZyA9IEdMX0ZBTFNFOwpHTGVudW0gbWFwUG9pbnQgPSBHTF9GQUxTRTsKR0xlbnVtIG1hcFR5cGUgPSBFVkFMOwoKZG91YmxlIHBvaW50MVsxMCAqIDRdID0KewogIC0wLjUsIDAuMCwgMC4wLCAxLjAsCiAgLTAuNCwgMC41LCAwLjAsIDEuMCwKICAtMC4zLCAtMC41LCAwLjAsIDEuMCwKICAtMC4yLCAwLjUsIDAuMCwgMS4wLAogIC0wLjEsIC0wLjUsIDAuMCwgMS4wLAogIDAuMCwgMC41LCAwLjAsIDEuMCwKICAwLjEsIC0wLjUsIDAuMCwgMS4wLAogIDAuMiwgMC41LCAwLjAsIDEuMCwKICAwLjMsIC0wLjUsIDAuMCwgMS4wLAogIDAuNCwgMC4wLCAwLjAsIDEuMCwKfTsKZG91YmxlIGNwb2ludDFbMTAgKiA0XSA9CnsKICAwLjAsIDAuMCwgMS4wLCAxLjAsCiAgMC4zLCAwLjAsIDAuNywgMS4wLAogIDAuNiwgMC4wLCAwLjMsIDEuMCwKICAxLjAsIDAuMCwgMC4wLCAxLjAsCiAgMS4wLCAwLjMsIDAuMCwgMS4wLAogIDEuMCwgMC42LCAwLjAsIDEuMCwKICAxLjAsIDEuMCwgMC4wLCAxLjAsCiAgMS4wLCAxLjAsIDAuNSwgMS4wLAogIDEuMCwgMS4wLCAxLjAsIDEuMCwKfTsKZG91YmxlIHRwb2ludDFbMTEgKiA0XSA9CnsKICAwLjAsIDAuMCwgMC4wLCAxLjAsCiAgMC4wLCAwLjEsIDAuMCwgMS4wLAogIDAuMCwgMC4yLCAwLjAsIDEuMCwKICAwLjAsIDAuMywgMC4wLCAxLjAsCiAgMC4wLCAwLjQsIDAuMCwgMS4wLAogIDAuMCwgMC41LCAwLjAsIDEuMCwKICAwLjAsIDAuNiwgMC4wLCAxLjAsCiAgMC4wLCAwLjcsIDAuMCwgMS4wLAogIDAuMCwgMC44LCAwLjAsIDEuMCwKICAwLjAsIDAuOSwgMC4wLCAxLjAsCn07CmRvdWJsZSBwb2ludDJbMiAqIDMgKiA0XSA9CnsKICAtMC41LCAtMC41LCAwLjUsIDEuMCwKICAwLjAsIDEuMCwgMC41LCAxLjAsCiAgMC41LCAtMC41LCAwLjUsIDEuMCwKICAtMC41LCAwLjUsIC0wLjUsIDEuMCwKICAwLjAsIC0xLjAsIC0wLjUsIDEuMCwKICAwLjUsIDAuNSwgLTAuNSwgMS4wLAp9Owpkb3VibGUgY3BvaW50MlsyICogMiAqIDRdID0KewogIDAuMCwgMC4wLCAwLjAsIDEuMCwKICAwLjAsIDAuMCwgMS4wLCAxLjAsCiAgMC4wLCAxLjAsIDAuMCwgMS4wLAogIDEuMCwgMS4wLCAxLjAsIDEuMCwKfTsKZG91YmxlIHRwb2ludDJbMiAqIDIgKiAyXSA9CnsKICAwLjAsIDAuMCwgMC4wLCAxLjAsCiAgMS4wLCAwLjAsIDEuMCwgMS4wLAp9OwpmbG9hdCB0ZXh0dXJlSW1hZ2VbNCAqIDIgKiA0XSA9CnsKICAxLjAsIDEuMCwgMS4wLCAxLjAsCiAgMS4wLCAwLjAsIDAuMCwgMS4wLAogIDEuMCwgMC4wLCAwLjAsIDEuMCwKICAxLjAsIDEuMCwgMS4wLCAxLjAsCiAgMS4wLCAxLjAsIDEuMCwgMS4wLAogIDEuMCwgMC4wLCAwLjAsIDEuMCwKICAxLjAsIDAuMCwgMC4wLCAxLjAsCiAgMS4wLCAxLjAsIDEuMCwgMS4wLAp9OwoKc3RhdGljIHZvaWQKSW5pdCh2b2lkKQp7CiAgc3RhdGljIGZsb2F0IGFtYmllbnRbXSA9CiAgezAuMSwgMC4xLCAwLjEsIDEuMH07CiAgc3RhdGljIGZsb2F0IGRpZmZ1c2VbXSA9CiAgezEuMCwgMS4wLCAxLjAsIDEuMH07CiAgc3RhdGljIGZsb2F0IHBvc2l0aW9uW10gPQogIHswLjAsIDAuMCwgLTE1MC4wLCAwLjB9OwogIHN0YXRpYyBmbG9hdCBmcm9udF9tYXRfZGlmZnVzZVtdID0KICB7MS4wLCAwLjIsIDEuMCwgMS4wfTsKICBzdGF0aWMgZmxvYXQgYmFja19tYXRfZGlmZnVzZVtdID0KICB7MS4wLCAxLjAsIDAuMiwgMS4wfTsKICBzdGF0aWMgZmxvYXQgbG1vZGVsX2FtYmllbnRbXSA9CiAgezEuMCwgMS4wLCAxLjAsIDEuMH07CiAgc3RhdGljIGZsb2F0IGxtb2RlbF90d29zaWRlW10gPQogIHtHTF9UUlVFfTsKICBzdGF0aWMgZmxvYXQgZGVjYWxbXSA9CiAge0dMX0RFQ0FMfTsKICBzdGF0aWMgZmxvYXQgcmVwZWF0W10gPQogIHtHTF9SRVBFQVR9OwogIHN0YXRpYyBmbG9hdCBucltdID0KICB7R0xfTkVBUkVTVH07CgogIGdsRnJvbnRGYWNlKEdMX0NDVyk7CgogIGdsRW5hYmxlKEdMX0RFUFRIX1RFU1QpOwoKICBnbE1hcDFkKEdMX01BUDFfVkVSVEVYXzQsIDAuMCwgMS4wLCBWRElNLCBWT1JERVIsIHBvaW50MSk7CiAgZ2xNYXAxZChHTF9NQVAxX0NPTE9SXzQsIDAuMCwgMS4wLCBDRElNLCBDT1JERVIsIGNwb2ludDEpOwoKICBnbE1hcDJkKEdMX01BUDJfVkVSVEVYXzQsIDAuMCwgMS4wLCBWTUlOT1JfT1JERVIgKiBWRElNLCBWTUFKT1JfT1JERVIsIDAuMCwKICAgIDEuMCwgVkRJTSwgVk1JTk9SX09SREVSLCBwb2ludDIpOwogIGdsTWFwMmQoR0xfTUFQMl9DT0xPUl80LCAwLjAsIDEuMCwgQ01JTk9SX09SREVSICogQ0RJTSwgQ01BSk9SX09SREVSLCAwLjAsCiAgICAxLjAsIENESU0sIENNSU5PUl9PUkRFUiwgY3BvaW50Mik7CiAgZ2xNYXAyZChHTF9NQVAyX1RFWFRVUkVfQ09PUkRfMiwgMC4wLCAxLjAsIFRNSU5PUl9PUkRFUiAqIFRESU0sCiAgICBUTUFKT1JfT1JERVIsIDAuMCwgMS4wLCBURElNLCBUTUlOT1JfT1JERVIsIHRwb2ludDIpOwoKICBnbExpZ2h0ZnYoR0xfTElHSFQwLCBHTF9BTUJJRU5ULCBhbWJpZW50KTsKICBnbExpZ2h0ZnYoR0xfTElHSFQwLCBHTF9ESUZGVVNFLCBkaWZmdXNlKTsKICBnbExpZ2h0ZnYoR0xfTElHSFQwLCBHTF9QT1NJVElPTiwgcG9zaXRpb24pOwoKICBnbE1hdGVyaWFsZnYoR0xfRlJPTlQsIEdMX0RJRkZVU0UsIGZyb250X21hdF9kaWZmdXNlKTsKICBnbE1hdGVyaWFsZnYoR0xfQkFDSywgR0xfRElGRlVTRSwgYmFja19tYXRfZGlmZnVzZSk7CgogIGdsTGlnaHRNb2RlbGZ2KEdMX0xJR0hUX01PREVMX0FNQklFTlQsIGxtb2RlbF9hbWJpZW50KTsKICBnbExpZ2h0TW9kZWxmdihHTF9MSUdIVF9NT0RFTF9UV09fU0lERSwgbG1vZGVsX3R3b3NpZGUpOwoKICBnbFRleEVudmZ2KEdMX1RFWFRVUkVfRU5WLCBHTF9URVhUVVJFX0VOVl9NT0RFLCBkZWNhbCk7CiAgZ2xUZXhQYXJhbWV0ZXJmdihHTF9URVhUVVJFXzJELCBHTF9URVhUVVJFX1dSQVBfUywgcmVwZWF0KTsKICBnbFRleFBhcmFtZXRlcmZ2KEdMX1RFWFRVUkVfMkQsIEdMX1RFWFRVUkVfV1JBUF9ULCByZXBlYXQpOwogIGdsVGV4UGFyYW1ldGVyZnYoR0xfVEVYVFVSRV8yRCwgR0xfVEVYVFVSRV9NQUdfRklMVEVSLCBucik7CiAgZ2xUZXhQYXJhbWV0ZXJmdihHTF9URVhUVVJFXzJELCBHTF9URVhUVVJFX01JTl9GSUxURVIsIG5yKTsKICBnbFRleEltYWdlMkQoR0xfVEVYVFVSRV8yRCwgMCwgNCwgMiwgNCwgMCwgR0xfUkdCQSwgR0xfRkxPQVQsCiAgICAoR0x2b2lkICopIHRleHR1cmVJbWFnZSk7Cn0KCnN0YXRpYyB2b2lkCkRyYXdQb2ludHMxKHZvaWQpCnsKICBHTGludCBpOwoKICBnbENvbG9yM2YoMC4wLCAxLjAsIDAuMCk7CiAgZ2xQb2ludFNpemUoMik7CiAgZ2xCZWdpbihHTF9QT0lOVFMpOwogIGZvciAoaSA9IDA7IGkgPCBWT1JERVI7IGkrKykgewogICAgZ2xWZXJ0ZXg0ZHYoJnBvaW50MVtpICogNF0pOwogIH0KICBnbEVuZCgpOwp9CgpzdGF0aWMgdm9pZApEcmF3UG9pbnRzMih2b2lkKQp7CiAgR0xpbnQgaSwgajsKCiAgZ2xDb2xvcjNmKDEuMCwgMC4wLCAxLjApOwogIGdsUG9pbnRTaXplKDIpOwogIGdsQmVnaW4oR0xfUE9JTlRTKTsKICBmb3IgKGkgPSAwOyBpIDwgVk1BSk9SX09SREVSOyBpKyspIHsKICAgIGZvciAoaiA9IDA7IGogPCBWTUlOT1JfT1JERVI7IGorKykgewogICAgICBnbFZlcnRleDRkdigmcG9pbnQyW2kgKiA0ICogVk1JTk9SX09SREVSICsgaiAqIDRdKTsKICAgIH0KICB9CiAgZ2xFbmQoKTsKfQoKc3RhdGljIHZvaWQKRHJhd01hcEV2YWwxKGZsb2F0IGR1KQp7CiAgZmxvYXQgdTsKCiAgZ2xDb2xvcjNmKDEuMCwgMC4wLCAwLjApOwogIGdsQmVnaW4oR0xfTElORV9TVFJJUCk7CiAgZm9yICh1ID0gMC4wOyB1IDwgMS4wOyB1ICs9IGR1KSB7CiAgICBnbEV2YWxDb29yZDFkKHUpOwogIH0KICBnbEV2YWxDb29yZDFkKDEuMCk7CiAgZ2xFbmQoKTsKfQoKc3RhdGljIHZvaWQKRHJhd01hcEV2YWwyKGZsb2F0IGR1LCBmbG9hdCBkdikKewogIGZsb2F0IHUsIHYsIHRtcDsKCiAgZ2xDb2xvcjNmKDEuMCwgMC4wLCAwLjApOwogIGZvciAodiA9IDAuMDsgdiA8IDEuMDsgdiArPSBkdikgewogICAgZ2xCZWdpbihHTF9RVUFEX1NUUklQKTsKICAgIGZvciAodSA9IDAuMDsgdSA8PSAxLjA7IHUgKz0gZHUpIHsKICAgICAgZ2xFdmFsQ29vcmQyZCh1LCB2KTsKICAgICAgdG1wID0gKHYgKyBkdiA8IDEuMCkgPyAodiArIGR2KSA6IDEuMDsKICAgICAgZ2xFdmFsQ29vcmQyZCh1LCB0bXApOwogICAgfQogICAgZ2xFdmFsQ29vcmQyZCgxLjAsIHYpOwogICAgZ2xFdmFsQ29vcmQyZCgxLjAsIHYgKyBkdik7CiAgICBnbEVuZCgpOwogIH0KfQoKc3RhdGljIHZvaWQKUmVuZGVyRXZhbCh2b2lkKQp7CgogIGlmIChjb2xvclR5cGUpIHsKICAgIGdsRW5hYmxlKEdMX01BUDFfQ09MT1JfNCk7CiAgICBnbEVuYWJsZShHTF9NQVAyX0NPTE9SXzQpOwogIH0gZWxzZSB7CiAgICBnbERpc2FibGUoR0xfTUFQMV9DT0xPUl80KTsKICAgIGdsRGlzYWJsZShHTF9NQVAyX0NPTE9SXzQpOwogIH0KCiAgaWYgKHRleHR1cmVUeXBlKSB7CiAgICBnbEVuYWJsZShHTF9URVhUVVJFXzJEKTsKICAgIGdsRW5hYmxlKEdMX01BUDJfVEVYVFVSRV9DT09SRF8yKTsKICB9IGVsc2UgewogICAgZ2xEaXNhYmxlKEdMX1RFWFRVUkVfMkQpOwogICAgZ2xEaXNhYmxlKEdMX01BUDJfVEVYVFVSRV9DT09SRF8yKTsKICB9CgogIGlmIChwb2x5Z29uRmlsbGVkKSB7CiAgICBnbFBvbHlnb25Nb2RlKEdMX0ZST05UX0FORF9CQUNLLCBHTF9GSUxMKTsKICB9IGVsc2UgewogICAgZ2xQb2x5Z29uTW9kZShHTF9GUk9OVF9BTkRfQkFDSywgR0xfTElORSk7CiAgfQoKICBnbFNoYWRlTW9kZWwoR0xfU01PT1RIKTsKCiAgc3dpdGNoIChtYXBUeXBlKSB7CiAgY2FzZSBFVkFMOgogICAgc3dpdGNoIChhcnJheVR5cGUpIHsKICAgIGNhc2UgT05FX0Q6CiAgICAgIGdsRGlzYWJsZShHTF9NQVAyX1ZFUlRFWF80KTsKICAgICAgZ2xFbmFibGUoR0xfTUFQMV9WRVJURVhfNCk7CiAgICAgIERyYXdQb2ludHMxKCk7CiAgICAgIERyYXdNYXBFdmFsMSgwLjEgLyBWT1JERVIpOwogICAgICBicmVhazsKICAgIGNhc2UgVFdPX0Q6CiAgICAgIGdsRGlzYWJsZShHTF9NQVAxX1ZFUlRFWF80KTsKICAgICAgZ2xFbmFibGUoR0xfTUFQMl9WRVJURVhfNCk7CiAgICAgIERyYXdQb2ludHMyKCk7CiAgICAgIERyYXdNYXBFdmFsMigwLjEgLyBWTUFKT1JfT1JERVIsIDAuMSAvIFZNSU5PUl9PUkRFUik7CiAgICAgIGJyZWFrOwogICAgfQogICAgYnJlYWs7CiAgY2FzZSBNRVNIOgogICAgc3dpdGNoIChhcnJheVR5cGUpIHsKICAgIGNhc2UgT05FX0Q6CiAgICAgIERyYXdQb2ludHMxKCk7CiAgICAgIGdsRGlzYWJsZShHTF9NQVAyX1ZFUlRFWF80KTsKICAgICAgZ2xFbmFibGUoR0xfTUFQMV9WRVJURVhfNCk7CiAgICAgIGdsQ29sb3IzZigwLjAsIDAuMCwgMS4wKTsKICAgICAgZ2xNYXBHcmlkMWQoNDAsIDAuMCwgMS4wKTsKICAgICAgaWYgKG1hcFBvaW50KSB7CiAgICAgICAgZ2xQb2ludFNpemUoMik7CiAgICAgICAgZ2xFdmFsTWVzaDEoR0xfUE9JTlQsIDAsIDQwKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBnbEV2YWxNZXNoMShHTF9MSU5FLCAwLCA0MCk7CiAgICAgIH0KICAgICAgYnJlYWs7CiAgICBjYXNlIFRXT19EOgogICAgICBEcmF3UG9pbnRzMigpOwogICAgICBnbERpc2FibGUoR0xfTUFQMV9WRVJURVhfNCk7CiAgICAgIGdsRW5hYmxlKEdMX01BUDJfVkVSVEVYXzQpOwogICAgICBnbENvbG9yM2YoMC4wLCAwLjAsIDEuMCk7CiAgICAgIGdsTWFwR3JpZDJkKDIwLCAwLjAsIDEuMCwgMjAsIDAuMCwgMS4wKTsKICAgICAgaWYgKG1hcFBvaW50KSB7CiAgICAgICAgZ2xQb2ludFNpemUoMik7CiAgICAgICAgZ2xFdmFsTWVzaDIoR0xfUE9JTlQsIDAsIDIwLCAwLCAyMCk7CiAgICAgIH0gZWxzZSBpZiAocG9seWdvbkZpbGxlZCkgewogICAgICAgIGdsRXZhbE1lc2gyKEdMX0ZJTEwsIDAsIDIwLCAwLCAyMCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgZ2xFdmFsTWVzaDIoR0xfTElORSwgMCwgMjAsIDAsIDIwKTsKICAgICAgfQogICAgICBicmVhazsKICAgIH0KICAgIGJyZWFrOwogIH0KfQoKc3RhdGljIHZvaWQKUmVzaGFwZShpbnQgd2lkdGgsIGludCBoZWlnaHQpCnsKCiAgZ2xWaWV3cG9ydCgwLCAwLCB3aWR0aCwgaGVpZ2h0KTsKCiAgZ2xNYXRyaXhNb2RlKEdMX1BST0pFQ1RJT04pOwogIGdsTG9hZElkZW50aXR5KCk7CiAgZ2xPcnRobygtMS4wLCAxLjAsIC0xLjAsIDEuMCwgLTAuNSwgMTAuMCk7CiAgZ2xNYXRyaXhNb2RlKEdMX01PREVMVklFVyk7Cn0KCi8qIEFSR1NVU0VEMSAqLwpzdGF0aWMgdm9pZApLZXkodW5zaWduZWQgY2hhciBrZXksIGludCB4LCBpbnQgeSkKewogIHN3aXRjaCAoa2V5KSB7CiAgY2FzZSAnMSc6CiAgICBhcnJheVR5cGUgPSBPTkVfRDsKICAgIGdsRGlzYWJsZShHTF9BVVRPX05PUk1BTCk7CiAgICBnbHV0UG9zdFJlZGlzcGxheSgpOwogICAgYnJlYWs7CiAgY2FzZSAnMic6CiAgICBhcnJheVR5cGUgPSBUV09fRDsKICAgIGdsRW5hYmxlKEdMX0FVVE9fTk9STUFMKTsKICAgIGdsdXRQb3N0UmVkaXNwbGF5KCk7CiAgICBicmVhazsKICBjYXNlICczJzoKICAgIG1hcFR5cGUgPSBFVkFMOwogICAgZ2x1dFBvc3RSZWRpc3BsYXkoKTsKICAgIGJyZWFrOwogIGNhc2UgJzQnOgogICAgbWFwVHlwZSA9IE1FU0g7CiAgICBnbHV0UG9zdFJlZGlzcGxheSgpOwogICAgYnJlYWs7CiAgY2FzZSAnNSc6CiAgICBwb2x5Z29uRmlsbGVkID0gIXBvbHlnb25GaWxsZWQ7CiAgICBnbHV0UG9zdFJlZGlzcGxheSgpOwogICAgYnJlYWs7CiAgY2FzZSAnNic6CiAgICBtYXBQb2ludCA9ICFtYXBQb2ludDsKICAgIGdsdXRQb3N0UmVkaXNwbGF5KCk7CiAgICBicmVhazsKICBjYXNlICc3JzoKICAgIGNvbG9yVHlwZSA9ICFjb2xvclR5cGU7CiAgICBnbHV0UG9zdFJlZGlzcGxheSgpOwogICAgYnJlYWs7CiAgY2FzZSAnOCc6CiAgICB0ZXh0dXJlVHlwZSA9ICF0ZXh0dXJlVHlwZTsKICAgIGdsdXRQb3N0UmVkaXNwbGF5KCk7CiAgICBicmVhazsKICBjYXNlICc5JzoKICAgIGxpZ2h0aW5nID0gIWxpZ2h0aW5nOwogICAgaWYgKGxpZ2h0aW5nKSB7CiAgICAgIGdsRW5hYmxlKEdMX0xJR0hUSU5HKTsKICAgICAgZ2xFbmFibGUoR0xfTElHSFQwKTsKICAgICAgaWYgKGFycmF5VHlwZSA9PSBUV09fRCkgewogICAgICAgIGdsRW5hYmxlKEdMX0FVVE9fTk9STUFMKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBnbERpc2FibGUoR0xfQVVUT19OT1JNQUwpOwogICAgICB9CiAgICB9IGVsc2UgewogICAgICBnbERpc2FibGUoR0xfTElHSFRJTkcpOwogICAgICBnbERpc2FibGUoR0xfTElHSFQwKTsKICAgICAgZ2xEaXNhYmxlKEdMX0FVVE9fTk9STUFMKTsKICAgIH0KICAgIGdsdXRQb3N0UmVkaXNwbGF5KCk7CiAgICBicmVhazsKICBjYXNlIDI3OiAgICAgICAgICAgICAvKiBFc2NhcGUga2V5LiAqLwogICAgZXhpdCgwKTsKICB9Cn0KCnN0YXRpYyB2b2lkCk1lbnUoaW50IHZhbHVlKQp7CiAgLyogTWVudSBpdGVtcyBoYXZlIGtleSB2YWx1ZXMgYXNzaWduZWQgdG8gdGhlbS4gIEp1c3QgcGFzcwogICAgIHRoaXMgdmFsdWUgdG8gdGhlIGtleSByb3V0aW5lLiAqLwogIEtleSh2YWx1ZSwgMCwgMCk7Cn0KCi8qIEFSR1NVU0VEMSAqLwpzdGF0aWMgdm9pZApTcGVjaWFsS2V5KGludCBrZXksIGludCB4LCBpbnQgeSkKewoKICBzd2l0Y2ggKGtleSkgewogIGNhc2UgR0xVVF9LRVlfTEVGVDoKICAgIHJvdFkgLT0gMzA7CiAgICBnbHV0UG9zdFJlZGlzcGxheSgpOwogICAgYnJlYWs7CiAgY2FzZSBHTFVUX0tFWV9SSUdIVDoKICAgIHJvdFkgKz0gMzA7CiAgICBnbHV0UG9zdFJlZGlzcGxheSgpOwogICAgYnJlYWs7CiAgY2FzZSBHTFVUX0tFWV9VUDoKICAgIHJvdFggLT0gMzA7CiAgICBnbHV0UG9zdFJlZGlzcGxheSgpOwogICAgYnJlYWs7CiAgY2FzZSBHTFVUX0tFWV9ET1dOOgogICAgcm90WCArPSAzMDsKICAgIGdsdXRQb3N0UmVkaXNwbGF5KCk7CiAgICBicmVhazsKICB9Cn0KCnN0YXRpYyB2b2lkCkRyYXcodm9pZCkKewoKICBnbENsZWFyKEdMX0NPTE9SX0JVRkZFUl9CSVQgfCBHTF9ERVBUSF9CVUZGRVJfQklUKTsKCiAgZ2xQdXNoTWF0cml4KCk7CgogIGdsVHJhbnNsYXRlZigwLjAsIDAuMCwgdHJhbnNsYXRlWik7CiAgZ2xSb3RhdGVmKHJvdFgsIDEsIDAsIDApOwogIGdsUm90YXRlZihyb3RZLCAwLCAxLCAwKTsKICBSZW5kZXJFdmFsKCk7CgogIGdsUG9wTWF0cml4KCk7CgogIGlmIChkb3VibGVCdWZmZXIpIHsKICAgIGdsdXRTd2FwQnVmZmVycygpOwogIH0gZWxzZSB7CiAgICBnbEZsdXNoKCk7CiAgfQp9CgpzdGF0aWMgdm9pZApBcmdzKGludCBhcmdjLCBjaGFyICoqYXJndikKewogIEdMaW50IGk7CgogIGRvdWJsZUJ1ZmZlciA9IEdMX0ZBTFNFOwoKICBmb3IgKGkgPSAxOyBpIDwgYXJnYzsgaSsrKSB7CiAgICBpZiAoc3RyY21wKGFyZ3ZbaV0sICItc2IiKSA9PSAwKSB7CiAgICAgIGRvdWJsZUJ1ZmZlciA9IEdMX0ZBTFNFOwogICAgfSBlbHNlIGlmIChzdHJjbXAoYXJndltpXSwgIi1kYiIpID09IDApIHsKICAgICAgZG91YmxlQnVmZmVyID0gR0xfVFJVRTsKICAgIH0KICB9Cn0KCmludAptYWluKGludCBhcmdjLCBjaGFyICoqYXJndikKewogIEdMZW51bSB0eXBlOwoKICBnbHV0SW5pdCgmYXJnYywgYXJndik7CiAgQXJncyhhcmdjLCBhcmd2KTsKCiAgdHlwZSA9IEdMVVRfUkdCIHwgR0xVVF9ERVBUSDsKICB0eXBlIHw9IChkb3VibGVCdWZmZXIpID8gR0xVVF9ET1VCTEUgOiBHTFVUX1NJTkdMRTsKICBnbHV0SW5pdERpc3BsYXlNb2RlKHR5cGUpOwogIGdsdXRJbml0V2luZG93U2l6ZSgzMDAsIDMwMCk7CiAgZ2x1dENyZWF0ZVdpbmRvdygiRXZhbHVhdG9yIFRlc3QiKTsKCiAgZ2x1dENyZWF0ZU1lbnUoTWVudSk7CiAgZ2x1dEFkZE1lbnVFbnRyeSgiT25lIGRpbWVuc2lvbmFsIiwgJzEnKTsKICBnbHV0QWRkTWVudUVudHJ5KCJUd28gZGltZW5zaW9uYWwiLCAnMicpOwogIGdsdXRBZGRNZW51RW50cnkoIkV2YWwgbWFwIHR5cGUiLCAnMycpOwogIGdsdXRBZGRNZW51RW50cnkoIk1lc2ggbWFwIHR5cGUiLCAnNCcpOwogIGdsdXRBZGRNZW51RW50cnkoIlRvZ2dsZSBmaWxsZWQiLCAnNScpOwogIGdsdXRBZGRNZW51RW50cnkoIlRvZ2dsZSBtYXAgcG9pbnQiLCAnNicpOwogIGdsdXRBZGRNZW51RW50cnkoIlRvZ2dsZSBjb2xvciIsICc3Jyk7CiAgZ2x1dEFkZE1lbnVFbnRyeSgiVG9nZ2xlIHRleHR1cmUiLCAnOCcpOwogIGdsdXRBZGRNZW51RW50cnkoIlRvZ2dsZSBsaWdodGluZyIsICc5Jyk7CiAgZ2x1dEFkZE1lbnVFbnRyeSgiUXVpdCIsIDI3KTsKICBnbHV0QXR0YWNoTWVudShHTFVUX1JJR0hUX0JVVFRPTik7CiAgZ2x1dEF0dGFjaE1lbnUoR0xVVF9MRUZUX0JVVFRPTik7CgogIEluaXQoKTsKCiAgZ2x1dFJlc2hhcGVGdW5jKFJlc2hhcGUpOwogIGdsdXRLZXlib2FyZEZ1bmMoS2V5KTsKICBnbHV0U3BlY2lhbEZ1bmMoU3BlY2lhbEtleSk7CiAgZ2x1dERpc3BsYXlGdW5jKERyYXcpOwogIGdsdXRNYWluTG9vcCgpOwogIHJldHVybiAwOwp9