Update for stereo rendering and new headset API;

This commit is contained in:
bjorn 2018-09-09 10:58:20 -07:00
parent 75ca4b0cba
commit 72158f103a
8 changed files with 526 additions and 581 deletions

View File

@ -228,7 +228,7 @@ endif()
# Oculus
if (NOT EMSCRIPTEN AND LOVR_OCULUS_PATH)
include_directories("${LOVR_OCULUS_PATH}/LibOVR/Include")
link_directories("${LOVR_OCULUS_PATH}/LibOVR/Lib/Windows/x64/Release/VS2017")
link_directories("${LOVR_OCULUS_PATH}/LibOVR/Lib/Windows/Win32/Debug/VS2017")
set(LOVR_OCULUS LibOVR)
endif()

View File

@ -31,6 +31,7 @@ const char* ControllerHands[] = {
const char* HeadsetDrivers[] = {
[DRIVER_FAKE] = "fake",
[DRIVER_OCULUS] = "oculus",
[DRIVER_OPENVR] = "openvr",
[DRIVER_WEBVR] = "webvr",
NULL

View File

@ -948,8 +948,6 @@ Texture* lovrTextureCreate(TextureType type, TextureData** slices, int sliceCoun
}
Texture* lovrTextureCreateFromHandle(uint32_t handle, TextureType type) {
lovrAssert(glIsTexture(handle), "Invalid texture handle");
Texture* texture = lovrAlloc(Texture, lovrTextureDestroy);
if (!texture) return NULL;
@ -957,6 +955,10 @@ Texture* lovrTextureCreateFromHandle(uint32_t handle, TextureType type) {
texture->id = handle;
texture->target = convertTextureTarget(type);
lovrGpuBindTexture(texture, 0);
glGetTexLevelParameteriv(texture->target, 0, GL_TEXTURE_WIDTH, &texture->width);
glGetTexLevelParameteriv(texture->target, 0, GL_TEXTURE_HEIGHT, &texture->height);
return texture;
}
@ -1243,8 +1245,8 @@ void lovrCanvasSetAttachments(Canvas* canvas, Attachment* attachments, int count
Texture* texture = attachments[i].texture;
int width = lovrTextureGetWidth(texture, attachments[i].level);
int height = lovrTextureGetHeight(texture, attachments[i].level);
lovrAssert(!canvas->depthBuffer || width == canvas->width, "Texture width of %d does not match Canvas width", width);
lovrAssert(!canvas->depthBuffer || height == canvas->height, "Texture height of %d does not match Canvas height", height);
lovrAssert(!canvas->depthBuffer || width == canvas->width, "Texture width of %d does not match Canvas width (%d)", width, canvas->width);
lovrAssert(!canvas->depthBuffer || height == canvas->height, "Texture height of %d does not match Canvas height (%d)", height, canvas->height);
lovrAssert(texture->msaa == canvas->flags.msaa, "Texture MSAA does not match Canvas MSAA");
lovrRetain(texture);
}

View File

@ -14,6 +14,7 @@ void lovrHeadsetInit(HeadsetDriver* drivers, int count, float offset, int msaa)
switch (drivers[i]) {
case DRIVER_FAKE: interface = &lovrHeadsetFakeDriver; break;
#ifndef EMSCRIPTEN
case DRIVER_OCULUS: interface = &lovrHeadsetOculusDriver; break;
case DRIVER_OPENVR: interface = &lovrHeadsetOpenVRDriver; break;
#else
case DRIVER_WEBVR: interface = &lovrHeadsetWebVRDriver; break;

View File

@ -17,6 +17,7 @@ typedef enum {
typedef enum {
DRIVER_FAKE,
DRIVER_OCULUS,
DRIVER_OPENVR,
DRIVER_WEBVR
} HeadsetDriver;
@ -93,6 +94,7 @@ typedef struct {
} HeadsetInterface;
// Available drivers
extern HeadsetInterface lovrHeadsetOculusDriver;
extern HeadsetInterface lovrHeadsetOpenVRDriver;
extern HeadsetInterface lovrHeadsetWebVRDriver;
extern HeadsetInterface lovrHeadsetFakeDriver;

View File

@ -11,114 +11,43 @@
#include <OVR_CAPI_GL.h>
typedef struct {
bool isInitialized;
bool isRendering;
bool isMirrored;
bool hmdPresent;
bool needRefreshTracking;
bool needRefreshButtons;
void (*renderCallback)(void*);
vec_controller_t controllers;
ovrSession session;
ovrGraphicsLuid luid;
float clipNear;
float clipFar;
int lastButtonState;
struct {
ovrSizei size;
GLuint fboId;
GLuint depthId;
ovrTextureSwapChain chain;
} eyeTextures[2];
ovrMirrorTexture mirrorTexture;
GLuint mirrorFBO;
ovrSizei size;
Canvas* canvas;
ovrTextureSwapChain chain;
ovrMirrorTexture mirror;
map_void_t textureLookup;
} HeadsetState;
static HeadsetState state;
static void ovrInit(float offset, int msaa) {
ovrResult result = ovr_Initialize(NULL);
if (OVR_FAILURE(result))
return;
result = ovr_Create(&state.session, &state.luid);
if (OVR_FAILURE(result)) {
ovr_Shutdown();
return;
static Texture* lookupTexture(uint32_t handle) {
char key[4 + 1] = { 0 };
lovrAssert(handle < 9999, "Texture handle overflow");
sprintf(key, "%d", handle);
Texture** texture = map_get(&state.textureLookup, key);
if (!texture) {
map_set(&state.textureLookup, key, lovrTextureCreateFromHandle(handle, TEXTURE_2D));
texture = map_get(&state.textureLookup, key);
}
state.needRefreshTracking = true;
state.needRefreshButtons = true;
state.lastButtonState = 0;
state.isInitialized = true;
state.isMirrored = true;
state.mirrorTexture = NULL;
int i;
for (i = 0; i < 2; i++) {
state.eyeTextures[i].size.w = 0;
state.eyeTextures[i].size.h = 0;
state.eyeTextures[i].fboId = 0;
state.eyeTextures[i].depthId = 0;
state.eyeTextures[i].chain = NULL;
}
state.clipNear = 0.1f;
state.clipFar = 30.f;
vec_init(&state.controllers);
// per the docs, ovrHand* is intended as array indices - so we use it directly.
for (i = ovrHand_Left; i < ovrHand_Count; i++) {
Controller *controller = lovrAlloc(sizeof(Controller), lovrControllerDestroy);
controller->id = ovrHand_Left+i;
vec_push(&state.controllers, controller);
}
ovr_SetTrackingOriginType(state.session, ovrTrackingOrigin_FloorLevel);
lovrEventAddPump(lovrHeadsetPoll);
atexit(lovrHeadsetDestroy);
}
static void ovrDestroy() {
int i;
Controller *controller;
vec_foreach(&state.controllers, controller, i) {
lovrRelease(&controller->ref);
}
vec_deinit(&state.controllers);
if (state.mirrorTexture) {
ovr_DestroyMirrorTexture(state.session, state.mirrorTexture);
state.mirrorTexture = NULL;
}
for (i = 0; i < 2; i++) {
if (state.eyeTextures[i].chain) {
ovr_DestroyTextureSwapChain(state.session, state.eyeTextures[i].chain);
state.eyeTextures[i].chain = NULL;
}
}
ovr_Destroy(state.session);
ovr_Shutdown();
state.isInitialized = false;
return *texture;
}
static void checkInput(Controller *controller, int diff, int state, ovrButton button, ControllerButton target) {
if ((diff & button) > 0) {
Event e;
if ((state & button) > 0) {
e.type = EVENT_CONTROLLER_PRESSED;
e.data.controllerpressed.controller = controller;
e.data.controllerpressed.button = target;
}
else {
e.type = EVENT_CONTROLLER_RELEASED;
e.data.controllerreleased.controller = controller;
e.data.controllerreleased.button = target;
}
lovrEventPush(e);
lovrEventPush((Event) {
.type = (state & button) ? EVENT_CONTROLLER_PRESSED : EVENT_CONTROLLER_RELEASED,
.data.controller = { controller, target }
});
}
}
@ -154,27 +83,91 @@ static ovrInputState *refreshButtons() {
return &is;
}
int lovrHeadsetIsPresent() {
return state.hmdPresent? 1 : 0;
static bool oculusInit(float offset, int msaa) {
ovrResult result = ovr_Initialize(NULL);
if (OVR_FAILURE(result)) {
return false;
}
result = ovr_Create(&state.session, &state.luid);
if (OVR_FAILURE(result)) {
ovr_Shutdown();
return false;
}
state.needRefreshTracking = true;
state.needRefreshButtons = true;
state.lastButtonState = 0;
state.isMirrored = true;
state.clipNear = 0.1f;
state.clipFar = 30.f;
vec_init(&state.controllers);
for (ovrHandType hand = ovrHand_Left; hand < ovrHand_Count; hand++) {
Controller* controller = lovrAlloc(Controller, free);
controller->id = hand;
vec_push(&state.controllers, controller);
}
map_init(&state.textureLookup);
ovr_SetTrackingOriginType(state.session, ovrTrackingOrigin_FloorLevel);
return true;
}
HeadsetType lovrHeadsetGetType() {
static void oculusDestroy() {
Controller *controller; int i;
vec_foreach(&state.controllers, controller, i) {
lovrRelease(controller);
}
vec_deinit(&state.controllers);
const char* key;
map_iter_t iter = map_iter(&state.textureLookup);
while ((key = map_next(&state.textureLookup, &iter)) != NULL) {
Texture* texture = *(Texture**) map_get(&state.textureLookup, key);
lovrRelease(texture);
}
map_deinit(&state.textureLookup);
if (state.mirror) {
ovr_DestroyMirrorTexture(state.session, state.mirror);
state.mirror = NULL;
}
if (state.chain) {
ovr_DestroyTextureSwapChain(state.session, state.chain);
state.chain = NULL;
}
lovrRelease(state.canvas);
ovr_Destroy(state.session);
ovr_Shutdown();
memset(&state, 0, sizeof(state));
}
static HeadsetType oculusGetType() {
return HEADSET_RIFT;
}
HeadsetOrigin lovrHeadsetGetOriginType() {
static HeadsetOrigin oculusGetOriginType() {
return ORIGIN_FLOOR;
}
int lovrHeadsetIsMirrored() {
return (int)state.isMirrored;
static bool oculusIsMounted() {
return true;
}
void lovrHeadsetSetMirrored(int mirror) {
state.isMirrored = mirror? true : false;
static bool oculusIsMirrored() {
return state.isMirrored;
}
void lovrHeadsetGetDisplayDimensions(int* width, int* height) {
static void oculusSetMirrored(bool mirror) {
state.isMirrored = mirror;
}
static void oculusGetDisplayDimensions(int* width, int* height) {
ovrHmdDesc desc = ovr_GetHmdDesc(state.session);
ovrSizei size = ovr_GetFovTextureSize(state.session, ovrEye_Left, desc.DefaultEyeFov[0], 1.0f);
@ -182,56 +175,40 @@ void lovrHeadsetGetDisplayDimensions(int* width, int* height) {
*height = size.h;
}
void lovrHeadsetGetClipDistance(float* near, float* far) {
if (!state.isInitialized) {
*near = *far = 0.f;
} else {
*near = state.clipNear;
*far = state.clipFar;
}
static void oculusGetClipDistance(float* clipNear, float* clipFar) {
*clipNear = state.clipNear;
*clipFar = state.clipFar;
}
void lovrHeadsetSetClipDistance(float near, float far) {
if (!state.isInitialized) return;
state.clipNear = near;
state.clipFar = far;
static void oculusSetClipDistance(float clipNear, float clipFar) {
state.clipNear = clipNear;
state.clipFar = clipFar;
}
float lovrHeadsetGetBoundsWidth() {
static float oculusGetBoundsDimensions(float* width, float* depth) {
ovrVector3f dimensions;
ovr_GetBoundaryDimensions(state.session, ovrBoundary_PlayArea, &dimensions);
return dimensions.x;
*width = dimensions.x;
*depth = dimensions.z;
}
float lovrHeadsetGetBoundsDepth() {
ovrVector3f dimensions;
ovr_GetBoundaryDimensions(state.session, ovrBoundary_PlayArea, &dimensions);
return dimensions.z;
}
void lovrHeadsetGetPosition(float* x, float* y, float* z) {
static void oculusGetPose(float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
ovrTrackingState *ts = refreshTracking();
ovrVector3f pos = ts->HeadPose.ThePose.Position;
*x = pos.x;
*y = pos.y;
*z = pos.z;
}
void lovrHeadsetGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) {
// we don't actually know these until render time, does this even need to be exposed?
*x = 0.0f;
*y = 0.0f;
*z = 0.0f;
}
void lovrHeadsetGetOrientation(float* angle, float* x, float* y, float* z) {
ovrTrackingState *ts = refreshTracking();
ovrQuatf oq = ts->HeadPose.ThePose.Orientation;
float quat[] = { oq.x, oq.y, oq.z, oq.w };
quat_getAngleAxis(quat, angle, x, y, z);
quat_getAngleAxis(quat, angle, ax, ay, az);
}
void lovrHeadsetGetVelocity(float* x, float* y, float* z) {
static void oculusGetEyePose(HeadsetEye eye, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
// TODO
oculusGetPose(x, y, z, angle, ax, ay, az);
}
static void oculusGetVelocity(float* x, float* y, float* z) {
ovrTrackingState *ts = refreshTracking();
ovrVector3f vel = ts->HeadPose.LinearVelocity;
*x = vel.x;
@ -239,7 +216,7 @@ void lovrHeadsetGetVelocity(float* x, float* y, float* z) {
*z = vel.z;
}
void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) {
static void oculusGetAngularVelocity(float* x, float* y, float* z) {
ovrTrackingState *ts = refreshTracking();
ovrVector3f vel = ts->HeadPose.AngularVelocity;
*x = vel.x;
@ -247,45 +224,41 @@ void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) {
*z = vel.z;
}
vec_controller_t* lovrHeadsetGetControllers() {
return &state.controllers;
static Controller** oculusGetControllers(uint8_t* count) {
*count = state.controllers.length;
return state.controllers.data;
}
int lovrHeadsetControllerIsPresent(Controller* controller) {
static bool oculusControllerIsConnected(Controller* controller) {
ovrInputState *is = refreshButtons();
switch (controller->id) {
case ovrHand_Left: return (is->ControllerType & ovrControllerType_LTouch) == ovrControllerType_LTouch;
case ovrHand_Right: return (is->ControllerType & ovrControllerType_RTouch) == ovrControllerType_RTouch;
default: return 0;
default: return false;
}
return 0;
return false;
}
ControllerHand lovrHeadsetControllerGetHand(Controller* controller) {
static ControllerHand oculusControllerGetHand(Controller* controller) {
switch (controller->id) {
case ovrHand_Left: return HAND_LEFT;
case ovrHand_Right: return HAND_RIGHT;
default: return HAND_UNKNOWN;
}
return HAND_UNKNOWN;
}
void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y, float* z) {
static void oculusControllerGetPose(Controller* controller, float* x, float* y, float* z, float* angle, float* ax, float* ay, float* az) {
ovrTrackingState *ts = refreshTracking();
ovrVector3f pos = ts->HandPoses[controller->id].ThePose.Position;
*x = pos.x;
*y = pos.y;
*z = pos.z;
}
void lovrHeadsetControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z) {
ovrTrackingState *ts = refreshTracking();
ovrQuatf orient = ts->HandPoses[controller->id].ThePose.Orientation;
float quat[4] = { orient.x, orient.y, orient.z, orient.w };
quat_getAngleAxis(quat, angle, x, y, z);
quat_getAngleAxis(quat, angle, ax, ay, az);
}
float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) {
static float oculusControllerGetAxis(Controller* controller, ControllerAxis axis) {
ovrInputState *is = refreshButtons();
switch (axis) {
case CONTROLLER_AXIS_GRIP: return is->HandTriggerNoDeadzone[controller->id];
@ -297,7 +270,7 @@ float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis)
return 0.0f;
}
int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button) {
static int oculusControllerIsDown(Controller* controller, ControllerButton button) {
ovrInputState *is = refreshButtons();
int relevant = is->Buttons & ((controller->id == ovrHand_Left) ? ovrButton_LMask : ovrButton_RMask);
switch (button) {
@ -307,15 +280,13 @@ int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button)
case CONTROLLER_BUTTON_Y: return (relevant & ovrButton_Y) > 0;
case CONTROLLER_BUTTON_MENU: return (relevant & ovrButton_Enter) > 0;
case CONTROLLER_BUTTON_TRIGGER: return (relevant & (ovrButton_LShoulder | ovrButton_RShoulder)) > 0;
case CONTROLLER_BUTTON_TOUCHPAD:
case CONTROLLER_BUTTON_JOYSTICK: return (relevant & (ovrButton_LThumb | ovrButton_RThumb)) > 0;
case CONTROLLER_BUTTON_TOUCHPAD: return (relevant & (ovrButton_LThumb | ovrButton_RThumb)) > 0;
case CONTROLLER_BUTTON_GRIP: return is->HandTrigger[controller->id] > 0.0f;
default: return 0;
}
return 0;
}
int lovrHeadsetControllerIsTouched(Controller* controller, ControllerButton button) {
static bool oculusControllerIsTouched(Controller* controller, ControllerButton button) {
ovrInputState *is = refreshButtons();
int relevant = is->Touches & ((controller->id == ovrHand_Left) ? ovrTouch_LButtonMask : ovrTouch_RButtonMask);
switch (button) {
@ -324,112 +295,64 @@ int lovrHeadsetControllerIsTouched(Controller* controller, ControllerButton butt
case CONTROLLER_BUTTON_X: return (relevant & ovrTouch_X) > 0;
case CONTROLLER_BUTTON_Y: return (relevant & ovrTouch_Y) > 0;
case CONTROLLER_BUTTON_TRIGGER: return (relevant & (ovrTouch_LIndexTrigger | ovrTouch_RIndexTrigger)) > 0;
case CONTROLLER_BUTTON_TOUCHPAD:
case CONTROLLER_BUTTON_JOYSTICK: return (relevant & (ovrTouch_LThumb | ovrTouch_RThumb)) > 0;
default: return 0;
case CONTROLLER_BUTTON_TOUCHPAD:return (relevant & (ovrTouch_LThumb | ovrTouch_RThumb)) > 0;
default: return false;
}
return 0;
}
void lovrHeadsetControllerVibrate(Controller* controller, float duration, float power) {
static void oculusControllerVibrate(Controller* controller, float duration, float power) {
//ovr_SetControllerVibration(state.session, ovrControllerType_LTouch, freq, power);
// TODO
}
ModelData* lovrHeadsetControllerNewModelData(Controller* controller) {
static ModelData* oculusControllerNewModelData(Controller* controller) {
// TODO
return NULL;
}
// TODO: need to set up swap chain textures for the eyes and finish view transforms
void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) {
if (!state.isInitialized) return;
state.renderCallback = callback;
static void oculusRenderTo(void (*callback)(void*), void* userdata) {
ovrHmdDesc desc = ovr_GetHmdDesc(state.session);
if (!state.mirrorTexture) {
int i;
for (i = 0; i < 2; i++) {
state.eyeTextures[i].size = ovr_GetFovTextureSize(state.session, ovrEye_Left+i, desc.DefaultEyeFov[ovrEye_Left+i], 1.0f);
if (!state.canvas) {
state.size = ovr_GetFovTextureSize(state.session, ovrEye_Left, desc.DefaultEyeFov[ovrEye_Left], 1.0f);
ovrTextureSwapChainDesc swdesc = {0};
swdesc.Type = ovrTexture_2D;
swdesc.ArraySize = 1;
swdesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
swdesc.Width = state.eyeTextures[i].size.w;
swdesc.Height = state.eyeTextures[i].size.h;
swdesc.MipLevels = 1;
swdesc.SampleCount = 1;
swdesc.StaticImage = ovrFalse;
ovrTextureSwapChainDesc swdesc = {
.Type = ovrTexture_2D,
.ArraySize = 1,
.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB,
.Width = 2 * state.size.w,
.Height = state.size.h,
.MipLevels = 1,
.SampleCount = 1,
.StaticImage = ovrFalse
};
lovrAssert(OVR_SUCCESS(ovr_CreateTextureSwapChainGL(state.session, &swdesc, &state.chain)), "Unable to create swapchain");
ovrTextureSwapChain chain;
if (OVR_SUCCESS(ovr_CreateTextureSwapChainGL(state.session, &swdesc, &chain))) {
state.eyeTextures[i].chain = chain;
ovrMirrorTextureDesc mdesc = {
.Width = lovrGraphicsGetWidth(),
.Height = lovrGraphicsGetHeight(),
.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB,
.MirrorOptions = ovrMirrorOption_PostDistortion
};
lovrAssert(OVR_SUCCESS(ovr_CreateMirrorTextureWithOptionsGL(state.session, &mdesc, &state.mirror)), "Unable to create mirror texture");
int len;
ovr_GetTextureSwapChainLength(state.session, state.eyeTextures[i].chain, &len);
int j;
for (j = 0; j < len; j++) {
GLuint texId;
ovr_GetTextureSwapChainBufferGL(state.session, state.eyeTextures[i].chain, j, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
else {
lovrAssert(chain != NULL, "Unable to create swap chain.");
break;
}
glGenFramebuffers(1, &state.eyeTextures[i].fboId);
glGenTextures(1, &state.eyeTextures[i].depthId);
glBindTexture(GL_TEXTURE_2D, state.eyeTextures[i].depthId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, state.eyeTextures[i].size.w, state.eyeTextures[i].size.h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
}
ovrMirrorTextureDesc mdesc;
memset(&mdesc, 0, sizeof(mdesc));
mdesc.Width = lovrGraphicsGetWidth();
mdesc.Height = lovrGraphicsGetHeight();
mdesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
// Create mirror texture and an FBO used to copy mirror texture to back buffer
ovr_CreateMirrorTextureGL(state.session, &mdesc, &state.mirrorTexture);
GLuint texId;
ovr_GetMirrorTextureBufferGL(state.session, state.mirrorTexture, &texId);
glGenFramebuffers(1, &state.mirrorFBO);
glBindFramebuffer(GL_READ_FRAMEBUFFER, state.mirrorFBO);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
CanvasFlags flags = { .depth = DEPTH_D24S8, .stereo = true };
state.canvas = lovrCanvasCreate(2 * state.size.w, state.size.h, flags);
}
lovrGraphicsPushCanvas();
state.isRendering = true;
ovrEyeRenderDesc eyeRenderDesc[2];
eyeRenderDesc[0] = ovr_GetRenderDesc(state.session, ovrEye_Left, desc.DefaultEyeFov[0]);
eyeRenderDesc[1] = ovr_GetRenderDesc(state.session, ovrEye_Right, desc.DefaultEyeFov[1]);
ovrVector3f HmdToEyeOffset[2] = {
eyeRenderDesc[0].HmdToEyeOffset,
eyeRenderDesc[1].HmdToEyeOffset
ovrPosef HmdToEyeOffset[2] = {
eyeRenderDesc[0].HmdToEyePose,
eyeRenderDesc[1].HmdToEyePose
};
ovrPosef EyeRenderPose[2];
double sensorSampleTime;
ovr_GetEyePoses(state.session, 0, ovrTrue, HmdToEyeOffset, EyeRenderPose, &sensorSampleTime);
float transform[16];
float projection[16];
Camera camera = { .canvas = state.canvas };
for (HeadsetEye eye = EYE_LEFT; eye <= EYE_RIGHT; eye++) {
float orient[] = {
EyeRenderPose[eye].Orientation.x,
@ -442,55 +365,40 @@ void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) {
EyeRenderPose[eye].Position.y,
EyeRenderPose[eye].Position.z,
};
mat4 transform = camera.viewMatrix[eye];
mat4_identity(transform);
mat4_rotateQuat(transform, orient);
transform[12] = -(transform[0] * pos[0] + transform[4] * pos[1] + transform[8] * pos[2]);
transform[13] = -(transform[1] * pos[0] + transform[5] * pos[1] + transform[9] * pos[2]);
transform[14] = -(transform[2] * pos[0] + transform[6] * pos[1] + transform[10] * pos[2]);
ovrTextureSwapChain chain = state.eyeTextures[eye].chain;
if (chain == NULL) {
lovrAssert(chain != NULL, "Swap chain is broken. This is a bug.");
continue;
}
int curIndex;
GLuint curTexId;
ovr_GetTextureSwapChainCurrentIndex(state.session, chain, &curIndex);
ovr_GetTextureSwapChainBufferGL(state.session, chain, curIndex, &curTexId);
glBindFramebuffer(GL_FRAMEBUFFER, state.eyeTextures[eye].fboId);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, state.eyeTextures[eye].depthId, 0);
glViewport(0, 0, state.eyeTextures[eye].size.w, state.eyeTextures[eye].size.h);
lovrGraphicsPush();
lovrGraphicsMatrixTransform(MATRIX_VIEW, transform);
ovrMatrix4f proj = ovrMatrix4f_Projection(desc.DefaultEyeFov[eye], state.clipNear, state.clipFar, ovrProjection_ClipRangeOpenGL);
mat4_fromMat44(projection, proj.M);
lovrGraphicsSetProjection(projection);
lovrGraphicsClear(1, 1);
callback(eye, userdata);
lovrGraphicsPop();
glBindFramebuffer(GL_FRAMEBUFFER, state.eyeTextures[eye].fboId);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
ovr_CommitTextureSwapChain(state.session, chain);
ovrMatrix4f projection = ovrMatrix4f_Projection(desc.DefaultEyeFov[eye], state.clipNear, state.clipFar, ovrProjection_ClipRangeOpenGL);
mat4_fromMat44(camera.projection[eye], projection.M);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
int curIndex;
uint32_t curTexId;
ovr_GetTextureSwapChainCurrentIndex(state.session, state.chain, &curIndex);
ovr_GetTextureSwapChainBufferGL(state.session, state.chain, curIndex, &curTexId);
Texture* texture = lookupTexture(curTexId);
lovrCanvasSetAttachments(state.canvas, &(Attachment) { texture, 0, 0 }, 1);
lovrGraphicsSetCamera(&camera, true);
callback(userdata);
lovrGraphicsSetCamera(NULL, false);
ovr_CommitTextureSwapChain(state.session, state.chain);
ovrLayerEyeFov ld;
ld.Header.Type = ovrLayerType_EyeFov;
ld.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
for (int eye = 0; eye < 2; eye++) {
ld.ColorTexture[eye] = state.eyeTextures[eye].chain;
ld.ColorTexture[eye] = state.chain;
ovrRecti vp;
vp.Pos.x = 0;
vp.Pos.x = state.size.w * eye;
vp.Pos.y = 0;
vp.Size.w = state.eyeTextures[eye].size.w;
vp.Size.h = state.eyeTextures[eye].size.h;
vp.Size.w = state.size.w;
vp.Size.h = state.size.h;
ld.Viewport[eye] = vp;
ld.Fov[eye] = desc.DefaultEyeFov[eye];
ld.RenderPose[eye] = EyeRenderPose[eye];
@ -504,22 +412,22 @@ void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) {
// if (!OVR_SUCCESS(result))
// goto Done;
state.isRendering = false;
state.needRefreshTracking = true;
state.needRefreshButtons = true;
lovrGraphicsPopCanvas();
if (state.isMirrored || 1) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, state.mirrorFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
int w = lovrGraphicsGetWidth();
int h = lovrGraphicsGetHeight();
glBlitFramebuffer(0, h, w, 0, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
if (state.isMirrored) {
uint32_t handle;
ovr_GetMirrorTextureBufferGL(state.session, state.mirror, &handle);
Texture* texture = lookupTexture(handle);
lovrGraphicsPushPipeline();
lovrGraphicsSetColor((Color) { 1, 1, 1, 1 });
lovrGraphicsSetShader(NULL);
lovrGraphicsFill(texture);
lovrGraphicsPopPipeline();
}
}
static void ovrUpdate(float dt) {
static void oculusUpdate(float dt) {
ovrInputState *is = refreshButtons();
ovrSessionStatus status;
@ -543,13 +451,43 @@ static void ovrUpdate(float dt) {
checkInput(right, diff, istate, ovrButton_A, CONTROLLER_BUTTON_A);
checkInput(right, diff, istate, ovrButton_B, CONTROLLER_BUTTON_B);
checkInput(right, diff, istate, ovrButton_RShoulder, CONTROLLER_BUTTON_TRIGGER);
checkInput(right, diff, istate, ovrButton_RThumb, CONTROLLER_BUTTON_JOYSTICK);
checkInput(right, diff, istate, ovrButton_RThumb, CONTROLLER_BUTTON_TOUCHPAD);
checkInput(left, diff, istate, ovrButton_X, CONTROLLER_BUTTON_X);
checkInput(left, diff, istate, ovrButton_Y, CONTROLLER_BUTTON_Y);
checkInput(left, diff, istate, ovrButton_LShoulder, CONTROLLER_BUTTON_TRIGGER);
checkInput(left, diff, istate, ovrButton_LThumb, CONTROLLER_BUTTON_JOYSTICK);
checkInput(left, diff, istate, ovrButton_LThumb, CONTROLLER_BUTTON_TOUCHPAD);
checkInput(left, diff, istate, ovrButton_Enter, CONTROLLER_BUTTON_MENU);
state.lastButtonState = is->Buttons;
}
HeadsetInterface lovrHeadsetOculusDriver = {
DRIVER_OCULUS,
oculusInit,
oculusDestroy,
oculusGetType,
oculusGetOriginType,
oculusIsMounted,
oculusIsMirrored,
oculusSetMirrored,
oculusGetDisplayDimensions,
oculusGetClipDistance,
oculusSetClipDistance,
oculusGetBoundsDimensions,
oculusGetPose,
oculusGetEyePose,
oculusGetVelocity,
oculusGetAngularVelocity,
oculusGetControllers,
oculusControllerIsConnected,
oculusControllerGetHand,
oculusControllerGetPose,
oculusControllerGetAxis,
oculusControllerIsDown,
oculusControllerIsTouched,
oculusControllerVibrate,
oculusControllerNewModelData,
oculusRenderTo,
oculusUpdate
};

View File

@ -59,7 +59,7 @@ function lovr.boot()
},
gammacorrect = false,
headset = {
drivers = { 'openvr', 'webvr', 'fake' },
drivers = { 'oculus', 'openvr', 'webvr', 'fake' },
mirror = true,
offset = 1.7,
msaa = 4

View File

@ -159,306 +159,307 @@ unsigned char boot_lua[] = {
0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68, 0x65, 0x61, 0x64, 0x73,
0x65, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x7b,
0x20, 0x27, 0x6f, 0x70, 0x65, 0x6e, 0x76, 0x72, 0x27, 0x2c, 0x20, 0x27,
0x77, 0x65, 0x62, 0x76, 0x72, 0x27, 0x2c, 0x20, 0x27, 0x66, 0x61, 0x6b,
0x65, 0x27, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x6d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75,
0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x37, 0x2c, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x73, 0x61, 0x61, 0x20, 0x3d, 0x20,
0x34, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20,
0x3d, 0x20, 0x31, 0x30, 0x38, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x36,
0x30, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75,
0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x66,
0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x6d, 0x73, 0x61, 0x61, 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20,
0x27, 0x4c, 0xc3, 0x96, 0x56, 0x52, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x6e, 0x69,
0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x7d, 0x0a,
0x20, 0x27, 0x6f, 0x63, 0x75, 0x6c, 0x75, 0x73, 0x27, 0x2c, 0x20, 0x27,
0x6f, 0x70, 0x65, 0x6e, 0x76, 0x72, 0x27, 0x2c, 0x20, 0x27, 0x77, 0x65,
0x62, 0x76, 0x72, 0x27, 0x2c, 0x20, 0x27, 0x66, 0x61, 0x6b, 0x65, 0x27,
0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x69,
0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65,
0x74, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x37, 0x2c, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x6d, 0x73, 0x61, 0x61, 0x20, 0x3d, 0x20, 0x34, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x7d, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77,
0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20,
0x31, 0x30, 0x38, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x36, 0x30, 0x30,
0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6c, 0x6c,
0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c,
0x73, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x73,
0x61, 0x61, 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x27, 0x4c,
0xc3, 0x96, 0x56, 0x52, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79,
0x73, 0x74, 0x65, 0x6d, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69,
0x72, 0x65, 0x28, 0x27, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x27, 0x29, 0x0a, 0x20, 0x20,
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6e,
0x66, 0x2c, 0x20, 0x68, 0x61, 0x73, 0x4d, 0x61, 0x69, 0x6e, 0x20, 0x3d,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79,
0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28,
0x27, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6c, 0x75, 0x61, 0x27, 0x29, 0x2c,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79,
0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28,
0x27, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x27, 0x29, 0x0a,
0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
0x2e, 0x67, 0x65, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x28, 0x29,
0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x28, 0x68, 0x61, 0x73,
0x43, 0x6f, 0x6e, 0x66, 0x20, 0x6f, 0x72, 0x20, 0x68, 0x61, 0x73, 0x4d,
0x61, 0x69, 0x6e, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6e, 0x6f,
0x67, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x6b, 0x2c, 0x20,
0x63, 0x6f, 0x6e, 0x66, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x0a, 0x20, 0x20,
0x69, 0x66, 0x20, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x20, 0x6f, 0x6b, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66,
0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c,
0x6c, 0x28, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x2c, 0x20, 0x27,
0x63, 0x6f, 0x6e, 0x66, 0x27, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f, 0x6e,
0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6f, 0x6b, 0x2c, 0x20, 0x63,
0x6f, 0x6e, 0x66, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x70,
0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63, 0x6f,
0x6e, 0x66, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x29, 0x20, 0x65, 0x6e,
0x64, 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x5f, 0x73,
0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x28, 0x63, 0x6f, 0x6e, 0x66, 0x29,
0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71,
0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x27, 0x29, 0x0a,
0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x68, 0x61, 0x73, 0x43,
0x6f, 0x6e, 0x66, 0x2c, 0x20, 0x68, 0x61, 0x73, 0x4d, 0x61, 0x69, 0x6e,
0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c,
0x65, 0x28, 0x27, 0x63, 0x6f, 0x6e, 0x66, 0x2e, 0x6c, 0x75, 0x61, 0x27,
0x29, 0x2c, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c,
0x65, 0x28, 0x27, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x27,
0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c,
0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74,
0x65, 0x6d, 0x2e, 0x67, 0x65, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x28, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x28, 0x68,
0x61, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x20, 0x6f, 0x72, 0x20, 0x68, 0x61,
0x73, 0x4d, 0x61, 0x69, 0x6e, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
0x6e, 0x6f, 0x67, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64,
0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x6b,
0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x0a,
0x20, 0x20, 0x69, 0x66, 0x20, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x6e, 0x66,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6f, 0x6b, 0x2c, 0x20, 0x63, 0x6f,
0x6e, 0x66, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x70, 0x63,
0x61, 0x6c, 0x6c, 0x28, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x2c,
0x20, 0x27, 0x63, 0x6f, 0x6e, 0x66, 0x27, 0x29, 0x20, 0x65, 0x6e, 0x64,
0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x63,
0x6f, 0x6e, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6f, 0x6b, 0x2c,
0x20, 0x63, 0x6f, 0x6e, 0x66, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x3d,
0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x63, 0x6f, 0x6e, 0x66, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x29, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x5f, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x28, 0x63, 0x6f, 0x6e,
0x66, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69,
0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74,
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, 0x63, 0x6f, 0x6e,
0x66, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x29, 0x0a,
0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x6f, 0x64,
0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x27, 0x61, 0x75,
0x64, 0x69, 0x6f, 0x27, 0x2c, 0x20, 0x27, 0x64, 0x61, 0x74, 0x61, 0x27,
0x2c, 0x20, 0x27, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x27, 0x2c, 0x20, 0x27,
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x27, 0x2c, 0x20, 0x27,
0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x27, 0x2c, 0x20, 0x27, 0x6d,
0x61, 0x74, 0x68, 0x27, 0x2c, 0x20, 0x27, 0x70, 0x68, 0x79, 0x73, 0x69,
0x63, 0x73, 0x27, 0x2c, 0x20, 0x27, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64,
0x27, 0x2c, 0x20, 0x27, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x27, 0x20, 0x7d,
0x0a, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x5f, 0x2c, 0x20, 0x6d, 0x6f,
0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69,
0x72, 0x73, 0x28, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x29, 0x20,
0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x6f,
0x6e, 0x66, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x5b, 0x6d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x5b, 0x6d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71,
0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x27,
0x20, 0x2e, 0x2e, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x29, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e,
0x64, 0x0a, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x61,
0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x74,
0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x7b, 0x7d,
0x2c, 0x20, 0x7b, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20,
0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x20, 0x7d, 0x29, 0x0a, 0x20, 0x20,
0x69, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x45, 0x72, 0x72, 0x6f, 0x72,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28,
0x63, 0x6f, 0x6e, 0x66, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x20, 0x65,
0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x68, 0x61, 0x73, 0x4d,
0x61, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x71,
0x75, 0x69, 0x72, 0x65, 0x20, 0x27, 0x6d, 0x61, 0x69, 0x6e, 0x27, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x72, 0x75, 0x6e, 0x28, 0x29, 0x0a,
0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x72, 0x75, 0x6e, 0x28, 0x29,
0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65,
0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x69,
0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x20,
0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x6c, 0x6f,
0x61, 0x64, 0x28, 0x61, 0x72, 0x67, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70,
0x75, 0x6d, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f,
0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62,
0x2c, 0x20, 0x63, 0x2c, 0x20, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c,
0x6c, 0x28, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x69, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20,
0x27, 0x71, 0x75, 0x69, 0x74, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x28,
0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x71, 0x75, 0x69,
0x74, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x29, 0x20, 0x74, 0x68,
0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x6f, 0x72, 0x20, 0x30,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, 0x6e, 0x61,
0x6d, 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, 0x6e,
0x61, 0x6d, 0x65, 0x5d, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63,
0x2c, 0x20, 0x64, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
0x61, 0x6c, 0x20, 0x64, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28,
0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68,
0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x75, 0x70,
0x64, 0x61, 0x74, 0x65, 0x28, 0x64, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x75, 0x70, 0x64,
0x61, 0x74, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x73, 0x65, 0x74, 0x49, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x28, 0x63, 0x6f, 0x6e, 0x66, 0x2e,
0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x29, 0x0a, 0x0a, 0x20,
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x27, 0x61, 0x75, 0x64, 0x69,
0x6f, 0x27, 0x2c, 0x20, 0x27, 0x64, 0x61, 0x74, 0x61, 0x27, 0x2c, 0x20,
0x27, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x27, 0x2c, 0x20, 0x27, 0x67, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x27, 0x2c, 0x20, 0x27, 0x68, 0x65,
0x61, 0x64, 0x73, 0x65, 0x74, 0x27, 0x2c, 0x20, 0x27, 0x6d, 0x61, 0x74,
0x68, 0x27, 0x2c, 0x20, 0x27, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73,
0x27, 0x2c, 0x20, 0x27, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x27, 0x2c,
0x20, 0x27, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x27, 0x20, 0x7d, 0x0a, 0x20,
0x20, 0x66, 0x6f, 0x72, 0x20, 0x5f, 0x2c, 0x20, 0x6d, 0x6f, 0x64, 0x75,
0x6c, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73,
0x28, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x29, 0x20, 0x64, 0x6f,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x66,
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x5b, 0x6d, 0x6f, 0x64,
0x75, 0x6c, 0x65, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x5b, 0x6d, 0x6f, 0x64,
0x75, 0x6c, 0x65, 0x5d, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69,
0x72, 0x65, 0x28, 0x27, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x27, 0x20, 0x2e,
0x2e, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x29, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x61, 0x6e, 0x64,
0x6c, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x74, 0x6d, 0x65,
0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x7b, 0x7d, 0x2c, 0x20,
0x7b, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x20, 0x7d, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66,
0x20, 0x63, 0x6f, 0x6e, 0x66, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x63, 0x6f,
0x6e, 0x66, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x20, 0x65, 0x6e, 0x64,
0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x68, 0x61, 0x73, 0x4d, 0x61, 0x69,
0x6e, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69,
0x72, 0x65, 0x20, 0x27, 0x6d, 0x61, 0x69, 0x6e, 0x27, 0x20, 0x65, 0x6e,
0x64, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c,
0x6f, 0x76, 0x72, 0x2e, 0x72, 0x75, 0x6e, 0x28, 0x29, 0x0a, 0x65, 0x6e,
0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x72, 0x75, 0x6e, 0x28, 0x29, 0x0a, 0x20,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e,
0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68,
0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x64,
0x28, 0x61, 0x72, 0x67, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d,
0x70, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20,
0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20,
0x63, 0x2c, 0x20, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28,
0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69,
0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x71,
0x75, 0x69, 0x74, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x28, 0x6e, 0x6f,
0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x71, 0x75, 0x69, 0x74, 0x20,
0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68,
0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, 0x6e, 0x61, 0x6d, 0x65,
0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, 0x6e, 0x61, 0x6d,
0x65, 0x5d, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x2c, 0x20,
0x64, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
0x20, 0x64, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74,
0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x75, 0x70, 0x64, 0x61,
0x74, 0x65, 0x28, 0x64, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65,
0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69,
0x6f, 0x2e, 0x73, 0x65, 0x74, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65,
0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x4f, 0x72, 0x69,
0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x29, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x50, 0x6f,
0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x50,
0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x56, 0x65, 0x6c,
0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68,
0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x65,
0x6c, 0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c,
0x6f, 0x76, 0x72, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x75, 0x70, 0x64,
0x61, 0x74, 0x65, 0x28, 0x64, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x74, 0x68, 0x65,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6f, 0x72,
0x69, 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61,
0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68,
0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x72,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x54, 0x6f, 0x28, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x64, 0x72, 0x61, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67,
0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c, 0x65, 0x61,
0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28,
0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67,
0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x65, 0x73,
0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x65, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x28, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x62, 0x75,
0x67, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x28,
0x27, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x5c, 0x6e, 0x27, 0x20, 0x2e,
0x2e, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x32,
0x29, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x27, 0x5c, 0x6e, 0x5b, 0x5e,
0x5c, 0x6e, 0x5d, 0x2b, 0x24, 0x27, 0x2c, 0x20, 0x27, 0x27, 0x29, 0x3a,
0x67, 0x73, 0x75, 0x62, 0x28, 0x27, 0x5c, 0x74, 0x27, 0x2c, 0x20, 0x27,
0x27, 0x29, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x27, 0x73, 0x74, 0x61,
0x63, 0x6b, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63, 0x6b,
0x27, 0x2c, 0x20, 0x27, 0x5c, 0x6e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x27,
0x29, 0x0a, 0x20, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20,
0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61,
0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x28, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x31, 0x20, 0x65, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
0x73, 0x2e, 0x72, 0x65, 0x73, 0x65, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
0x73, 0x2e, 0x73, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f,
0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x2e, 0x31, 0x30,
0x35, 0x2c, 0x20, 0x2e, 0x30, 0x39, 0x38, 0x2c, 0x20, 0x2e, 0x31, 0x33,
0x37, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f,
0x6c, 0x6f, 0x72, 0x28, 0x2e, 0x38, 0x36, 0x33, 0x2c, 0x20, 0x2e, 0x38,
0x36, 0x33, 0x2c, 0x20, 0x2e, 0x38, 0x36, 0x33, 0x29, 0x0a, 0x20, 0x20,
0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64,
0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75,
0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x4f, 0x72, 0x69, 0x65, 0x6e,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x4f,
0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29,
0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74,
0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65,
0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x29,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x56,
0x65, 0x6c, 0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74,
0x56, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x29, 0x29, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x75,
0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x64, 0x74, 0x29, 0x20, 0x65, 0x6e,
0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x74,
0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x73, 0x65,
0x74, 0x4d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x28, 0x66, 0x61,
0x6c, 0x73, 0x65, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c,
0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x3d, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
0x73, 0x2e, 0x67, 0x65, 0x74, 0x46, 0x6f, 0x6e, 0x74, 0x28, 0x29, 0x0a,
0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x69, 0x78, 0x65,
0x6c, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x66,
0x6f, 0x6e, 0x74, 0x3a, 0x67, 0x65, 0x74, 0x50, 0x69, 0x78, 0x65, 0x6c,
0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x28, 0x29, 0x0a, 0x20, 0x20,
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20,
0x3d, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x3a, 0x67, 0x65, 0x74, 0x57, 0x69,
0x64, 0x74, 0x68, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c,
0x20, 0x2e, 0x35, 0x35, 0x20, 0x2a, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c,
0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x29, 0x0a, 0x20, 0x20, 0x6c,
0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70,
0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x2d, 0x77, 0x69, 0x64,
0x74, 0x68, 0x20, 0x2f, 0x20, 0x32, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x2d,
0x32, 0x30, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c,
0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x2e, 0x35, 0x35, 0x20, 0x2a,
0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74,
0x79, 0x2c, 0x20, 0x27, 0x6c, 0x65, 0x66, 0x74, 0x27, 0x29, 0x0a, 0x20,
0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76,
0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x28, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20,
0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76, 0x65, 0x6e,
0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28, 0x29, 0x20, 0x64, 0x6f, 0x20,
0x69, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27,
0x71, 0x75, 0x69, 0x74, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e, 0x64, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c,
0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e,
0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64,
0x72, 0x61, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74,
0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x54, 0x6f, 0x28, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c,
0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61,
0x77, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72,
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72,
0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e,
0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64,
0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0a, 0x20, 0x20,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x64, 0x65,
0x62, 0x75, 0x67, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61, 0x63,
0x6b, 0x28, 0x27, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a, 0x5c, 0x6e, 0x27,
0x20, 0x2e, 0x2e, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c,
0x20, 0x32, 0x29, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x27, 0x5c, 0x6e,
0x5b, 0x5e, 0x5c, 0x6e, 0x5d, 0x2b, 0x24, 0x27, 0x2c, 0x20, 0x27, 0x27,
0x29, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x27, 0x5c, 0x74, 0x27, 0x2c,
0x20, 0x27, 0x27, 0x29, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x27, 0x73,
0x74, 0x61, 0x63, 0x6b, 0x20, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x61,
0x63, 0x6b, 0x27, 0x2c, 0x20, 0x27, 0x5c, 0x6e, 0x53, 0x74, 0x61, 0x63,
0x6b, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x69,
0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67,
0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68,
0x69, 0x63, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x65, 0x74, 0x28, 0x29, 0x0a,
0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68,
0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67,
0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x2e,
0x31, 0x30, 0x35, 0x2c, 0x20, 0x2e, 0x30, 0x39, 0x38, 0x2c, 0x20, 0x2e,
0x31, 0x33, 0x37, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74,
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x2e, 0x38, 0x36, 0x33, 0x2c, 0x20,
0x2e, 0x38, 0x36, 0x33, 0x2c, 0x20, 0x2e, 0x38, 0x36, 0x33, 0x29, 0x0a,
0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65,
0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c,
0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e,
0x73, 0x65, 0x74, 0x4d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x28,
0x66, 0x61, 0x6c, 0x73, 0x65, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x20,
0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68,
0x69, 0x63, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x46, 0x6f, 0x6e, 0x74, 0x28,
0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x69,
0x78, 0x65, 0x6c, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x20, 0x3d,
0x20, 0x66, 0x6f, 0x6e, 0x74, 0x3a, 0x67, 0x65, 0x74, 0x50, 0x69, 0x78,
0x65, 0x6c, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x28, 0x29, 0x0a,
0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x77, 0x69, 0x64, 0x74,
0x68, 0x20, 0x3d, 0x20, 0x66, 0x6f, 0x6e, 0x74, 0x3a, 0x67, 0x65, 0x74,
0x57, 0x69, 0x64, 0x74, 0x68, 0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x2c, 0x20, 0x2e, 0x35, 0x35, 0x20, 0x2a, 0x20, 0x70, 0x69, 0x78,
0x65, 0x6c, 0x44, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x29, 0x0a, 0x20,
0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72,
0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x69, 0x6e, 0x74,
0x28, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x2d, 0x77,
0x69, 0x64, 0x74, 0x68, 0x20, 0x2f, 0x20, 0x32, 0x2c, 0x20, 0x30, 0x2c,
0x20, 0x2d, 0x32, 0x30, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x30, 0x2c, 0x20,
0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x2e, 0x35, 0x35,
0x20, 0x2a, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x44, 0x65, 0x6e, 0x73,
0x69, 0x74, 0x79, 0x2c, 0x20, 0x27, 0x6c, 0x65, 0x66, 0x74, 0x27, 0x29,
0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e,
0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x28, 0x29,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x61, 0x6d,
0x65, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x76,
0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28, 0x29, 0x20, 0x64,
0x6f, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x3d,
0x20, 0x27, 0x71, 0x75, 0x69, 0x74, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e,
0x64, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e,
0x63, 0x6c, 0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63,
0x73, 0x2e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68,
0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74,
0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x54, 0x6f, 0x28, 0x72, 0x65,
0x6e, 0x64, 0x65, 0x72, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70,
0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74,
0x28, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64,
0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c,
0x6f, 0x76, 0x72, 0x2e, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x2c, 0x20,
0x65, 0x72, 0x72, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x28, 0x27, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72,
0x6f, 0x72, 0x5c, 0x6e, 0x5c, 0x6e, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x65,
0x72, 0x72, 0x2c, 0x20, 0x30, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20,
0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f,
0x6e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x20,
0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65,
0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x20,
0x65, 0x6c, 0x73, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e, 0x64, 0x20,
0x65, 0x6e, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c, 0x6f,
0x63, 0x61, 0x6c, 0x20, 0x5f, 0x2c, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61,
0x64, 0x20, 0x3d, 0x20, 0x78, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c,
0x6f, 0x76, 0x72, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x2c, 0x20, 0x6f, 0x6e,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x77, 0x68,
0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x6b,
0x2c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x78,
0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64,
0x2c, 0x20, 0x6f, 0x6e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x6e,
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x69,
0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x6b, 0x20, 0x74, 0x68, 0x65,
0x6e, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x3d, 0x20, 0x72,
0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e,
0x79, 0x69, 0x65, 0x6c, 0x64, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e,
0x64, 0x0a, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x31, 0x0a, 0x65, 0x6e, 0x64, 0x0a
0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61,
0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f,
0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x72,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x54, 0x6f, 0x28, 0x72, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69,
0x63, 0x73, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29,
0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x2c, 0x20, 0x65, 0x72,
0x72, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x27,
0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x5c, 0x6e, 0x5c, 0x6e, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x65, 0x72, 0x72,
0x2c, 0x20, 0x30, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x72, 0x65,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x61,
0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, 0x65,
0x72, 0x72, 0x6f, 0x72, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x69, 0x66,
0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x65, 0x64,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x65,
0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x65, 0x72, 0x72,
0x68, 0x61, 0x6e, 0x64, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x65, 0x6c,
0x73, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75,
0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e, 0x64, 0x20, 0x65, 0x6e,
0x64, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
0x6c, 0x20, 0x5f, 0x2c, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20,
0x3d, 0x20, 0x78, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76,
0x72, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x2c, 0x20, 0x6f, 0x6e, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c,
0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x6b, 0x2c, 0x20,
0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x78, 0x70, 0x63,
0x61, 0x6c, 0x6c, 0x28, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x2c, 0x20,
0x6f, 0x6e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x29, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x69, 0x66, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x6f, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20,
0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73,
0x75, 0x6c, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x79, 0x69,
0x65, 0x6c, 0x64, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a,
0x65, 0x6e, 0x64, 0x0a
};
unsigned int boot_lua_len = 5526;
unsigned int boot_lua_len = 5536;