#include <windows.h>
#include <string>
#include <functional>
#define event(eventname, ... ) std::function<void(__VA_ARGS__ )> eventname
typedef COLORREF color;
using namespace std;
const char *labelpropname = "Cambalinho";
const char *labelclassprop = "classaddr";
enum MouseButtons
{
None=-1,
Left=0,
Right=1,
Middle=2,
X1=3,
X2=4
};
struct Position
{
int X;
int Y;
};
struct Size
{
int Width;
int Height;
};
class label
{
private:
HWND hwnd;
color clrTextColor=RGB(0,0,0);
color clrBackColor=RGB(255,255,255);
bool blnTransparent=false;
string caption="label";
HRGN CreateBitmapRgn(HWND image,color transparent=-1)
{
int x=0, y=0;
HRGN hrgn;
HRGN hrgnTmp;
RECT LabelSize;
GetWindowRect(image,&LabelSize);
int width=LabelSize.right-LabelSize.left;
int height=LabelSize.bottom-LabelSize.top;
hrgn = CreateRectRgn(0, 0, 0, 0);
color pixelcolor=0;
HDC hdcPixel=GetDC(image);
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
pixelcolor=GetPixel(hdcPixel,x,y);
if (pixelcolor!=transparent)
{
hrgnTmp = CreateRectRgn(x, y, x + 1, y + 1);
CombineRgn(hrgn, hrgn, hrgnTmp, RGN_OR);
DeleteObject(hrgnTmp);
}
}
}
return hrgn;
}
void TrackMouse(HWND hwnd)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE; //Type of events to track & trigger.
tme.dwHoverTime = 5000; //How long the mouse has to be in the window to trigger a hover event.
tme.hwndTrack = hwnd;
TrackMouseEvent(&tme);
}
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldproc = (WNDPROC)GetProp(GetParent(hwnd), labelpropname);
if (oldproc == NULL)
MessageBox(NULL, "oldprocnull", "oldprocnull", MB_OK);
label *inst = (label*)GetProp(hwnd, labelclassprop);
if (inst == NULL && msg == WM_CREATE)
inst = (label*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
if ((inst == NULL) && (msg != WM_NCCREATE && msg != WM_NCCALCSIZE))
MessageBox(NULL, "instnull", "instnull", MB_OK);
static bool TrackingMouse = false;
static bool WindowStopMoving = NULL;
static bool WindowStopResize = NULL;
static const UINT_PTR MouseStopTimerID = 1;
HBRUSH g_hbrBackground = CreateSolidBrush(NULL_BRUSH);
switch(msg)
{
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, inst->clrTextColor);
SetBkMode(hdcStatic, TRANSPARENT);
SetBkColor(hdcStatic,inst->clrBackColor);
g_hbrBackground = CreateSolidBrush(inst->clrBackColor);
return (LONG)g_hbrBackground;
}
break;
case WM_CREATE:
{
static int xPos = (int)(short) LOWORD(lParam);
static int yPos = (int)(short) HIWORD(lParam);
inst->Create(xPos,yPos);
}
break;
case WM_MOVE:
{
static int xPos = (int)(short) LOWORD(lParam);
static int yPos = (int)(short) HIWORD(lParam);
inst->Move(xPos,yPos);
WindowStopMoving=false;
WindowStopResize=true;
}
break;
case WM_SIZE :
{
WindowStopResize=false;
WindowStopMoving=true;
}
break;
case WM_EXITSIZEMOVE:
{
if(WindowStopResize==false)
{
WindowStopResize=true;
inst->NotResize();
}
else if (WindowStopMoving==false)
{
WindowStopMoving=true;
inst->Stop();
}
}
break;
case WM_NCHITTEST:
return DefWindowProc(hwnd, msg, wParam, lParam);
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_XBUTTONDOWN:
{
SetFocus(inst->hwnd);
static int xPos = (int)(short) LOWORD(lParam);
static int yPos = (int)(short) HIWORD(lParam);
bool blControl = ((wParam & MK_CONTROL) == MK_CONTROL);
bool blshift = ((wParam & MK_SHIFT) == MK_SHIFT);
MouseButtons MBButtons;
if((wParam & MK_LBUTTON)!= false)
MBButtons=Left;
else if (wParam & MK_RBUTTON)
MBButtons=Right;
else if (wParam & MK_MBUTTON)
MBButtons=Middle;
else if (wParam & MK_XBUTTON1)
MBButtons=X1;
else if (wParam & MK_XBUTTON2)
MBButtons=X2;
else
MBButtons=None;
inst->MouseDown(MBButtons,blControl,blshift,xPos,yPos);
}
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case WM_XBUTTONUP:
{
SetFocus(inst->hwnd);
static int xPos = (int)(short) LOWORD(lParam);
static int yPos = (int)(short) HIWORD(lParam);
bool blControl = ((wParam & MK_CONTROL) == MK_CONTROL);
bool blshift = ((wParam & MK_SHIFT) == MK_SHIFT);
MouseButtons MBButtons;
if (msg == WM_LBUTTONUP)
MBButtons=Left;
else if (msg == WM_RBUTTONUP)
MBButtons=Right;
else if (msg == WM_MBUTTONUP)
MBButtons=Middle;
else if (msg == WM_XBUTTONUP)
{
if (wParam & MK_XBUTTON1)
MBButtons=X1;
else if (wParam & MK_XBUTTON2)
MBButtons=X2;
}
else
MBButtons=None;
inst->MouseUp(MBButtons,blControl,blshift,xPos,yPos);
}
break;
case WM_MOUSELEAVE :
{
TrackingMouse = false;
inst->MouseLeave();
}
break;
case WM_NCMOUSEMOVE:
case WM_MOUSEMOVE:
{
if (!TrackingMouse)
{
inst->TrackMouse(hwnd);
TrackingMouse = true;
inst->MouseEnter();
}
static int xPos = (int)(short) LOWORD(lParam);
static int yPos = (int)(short) HIWORD(lParam);
static bool blControl = ((wParam & MK_CONTROL) == MK_CONTROL);
static bool blshift = ((wParam & MK_SHIFT) == MK_SHIFT);
static MouseButtons MBButtons;
if((wParam & MK_LBUTTON)!= false)
MBButtons=Left;
else if ((wParam & MK_RBUTTON)!= false)
MBButtons=Right;
else if ((wParam & MK_MBUTTON)!= false)
MBButtons=Middle;
else if ((wParam & MK_XBUTTON1)!= false)
MBButtons=X1;
else if ((wParam & MK_XBUTTON2)!= false)
MBButtons=X2;
else
MBButtons=None;
inst->MouseMove(MBButtons,blControl,blshift,xPos,yPos);
KillTimer(hwnd, MouseStopTimerID);
SetTimer(hwnd, MouseStopTimerID, 500, NULL);
}
break;
case WM_MOUSEHOVER:
{
inst->MouseHover();
}
break;
case WM_TIMER:
switch(wParam)
{
case MouseStopTimerID:
{
KillTimer(hwnd, MouseStopTimerID);
inst->MouseStoped();
}
}
break;
case WM_KEYUP:
inst->KeyUp(lParam,wParam);
break;
case WM_KEYDOWN:
inst->KeyDown(lParam,wParam);
break;
default:
break;
}
return oldproc ? CallWindowProc(oldproc, hwnd, msg, wParam, lParam) : DefWindowProc(hwnd, msg, wParam, lParam);
}
public:
//is these 2 lines ok?
//see the #define on top
event(NotResize)=[](){;};
event(Stop)=[](){;};
event(MouseEnter)=[](){;};
event(MouseLeave)=[](){;};
event(Create,(int x, int y))=[](int x, int y){;};
event(Move,(int x, int y))=[](int x, int y){;};
event(MouseDown,(MouseButtons Button,bool control, bool shift, int x, int y))=[](int Button, bool alt, bool shift,int x, int y){;};
event(MouseUp,(MouseButtons Button,bool control, bool shift, int x, int y))=[](int Button, bool alt, bool shift,int x, int y){;};
event(MouseMove,(MouseButtons Button,bool control, bool shift, int x, int y))=[](int Button, bool alt, bool shift,int x, int y){;};
event(MouseStoped)=[](){;};
event(MouseHover)=[](){;};
event(MouseClick,(MouseButtons Button,bool control, bool shift, int x, int y))=[](int Button, bool alt, bool shift,int x, int y){;};
event(MouseDoubleClick,(MouseButtons Button,bool control, bool shift, int x, int y))=[](int Button, bool alt, bool shift,int x, int y){;};
event(MouseWhell,(int Whell, MouseButtons Button,bool control, bool shift, int x, int y))=[](int Whell, int Button, bool alt, bool shift,int x, int y){;};
event(KeyDown,(int repeat,int Key))=[](int repeat,int Key){;};
event(KeyUp,(int repeat,int Key))=[](int repeat,int Key){;};
~label()
{
DestroyWindow(hwnd);
hwnd = 0;
}
label()
{
;
}
void setparent(HWND parent)
{
static int i = 0;
i++;
string strclass=labelclassprop + to_string(i);
labelclassprop=strclass.c_str();
WNDCLASS wc;
HINSTANCE mod = (HINSTANCE)GetModuleHandle(NULL);
ZeroMemory(&wc, sizeof(WNDCLASS));
GetClassInfo(mod, "STATIC", &wc);
wc.hInstance = mod;
wc.lpszClassName = labelclassprop;
wc.hbrBackground = CreateSolidBrush(RGB(255,0,0));
// store the old WNDPROC of the EDIT window class
SetProp(parent, labelpropname, (HANDLE)wc.lpfnWndProc);
// replace it with local WNDPROC
wc.lpfnWndProc = WndProc;
// register the new window class, "ShEdit"
if (!RegisterClass(&wc))
MessageBox(NULL, "error in register", "error", MB_OK);
hwnd = CreateWindowEx(
WS_EX_LEFT| WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_TRANSPARENT,
labelclassprop,
labelclassprop,
SS_LEFT|WS_CHILD|WS_VISIBLE|WS_OVERLAPPED,
100, 100, 100, 100,
parent,
NULL,
mod,
(LPVOID)this);
if (hwnd == NULL)
MessageBox(NULL, "error in create", "error", MB_OK);
SetProp(hwnd, labelclassprop, (HANDLE)this);
//SetWindowLongPtr(this->hwnd,GWLP_USERDATA,(LONG) this);
UpdateWindow(hwnd);
clrBackColor=GetPixel(GetDC(hwnd),0,0);
}
Size GetSize()
{
RECT LabelSize;
GetWindowRect(this->hwnd,&LabelSize);
Size crdSize = {LabelSize.right-LabelSize.left,LabelSize.bottom-LabelSize.top};
return crdSize;
}
void SetSize(int Width, int Height)
{
RECT LabelSize;
GetWindowRect(this->hwnd,&LabelSize);
LabelSize.right=LabelSize.left+Width;
LabelSize.bottom=LabelSize.top+Height;
SetWindowPos(this->hwnd,HWND_TOP,LabelSize.left,LabelSize.top,Width,Height,SWP_NOMOVE|SWP_NOZORDER);
}
Position GetPosition()
{
RECT LabelSize;
GetWindowRect(this->hwnd,&LabelSize);
Position crdSize = {LabelSize.left,LabelSize.top};
return crdSize;
}
void SetPosition(int x, int y)
{
RECT LabelSize;
GetWindowRect(this->hwnd,&LabelSize);
SetWindowPos(this->hwnd,HWND_TOP,x,y,0,0,SWP_NOSIZE|SWP_NOZORDER);
}
void Transparent()
{
RECT LabelSize;
GetWindowRect(this->hwnd,&LabelSize);
HRGN hRgn = CreateBitmapRgn(this->hwnd, this->clrBackColor);
SetWindowRgn(this->hwnd, hRgn, true);
}
void SetText(string text)
{
this->caption=text;
SetWindowText(this->hwnd,text.c_str());
}
string GetText()
{
return this->caption;
}
void SetBackColor(COLORREF color)
{
clrBackColor=color;
ShowWindow(this->hwnd,SW_HIDE);
ShowWindow(this->hwnd,SW_SHOW);
}
color GetBackColor()
{
return clrBackColor;
}
void SetColorText(COLORREF color)
{
clrTextColor=color;
ShowWindow(this->hwnd,SW_HIDE);
ShowWindow(this->hwnd,SW_SHOW);
}
color GetColorText()
{
return this->clrTextColor;
}
HFONT GetFont()
{
HFONT actual;
actual=(HFONT)SendMessage(hwnd,WM_GETFONT,0,0);
return actual;
}
void SetFont(HFONT newfont)
{
SendMessage(hwnd,WM_SETFONT,(WPARAM)newfont,0);
}
void SetImage(string FileName)
{
HBITMAP bmpSource = NULL;
bmpSource = (HBITMAP)LoadImage(NULL,FileName.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
SendMessage(this->hwnd,STM_SETICON,(WPARAM) IMAGE_ICON,(LPARAM) bmpSource);
}
HWND GetHWND()
{
return hwnd;
}
};
I2luY2x1ZGUgPHdpbmRvd3MuaD4KI2luY2x1ZGUgPHN0cmluZz4KI2luY2x1ZGUgPGZ1bmN0aW9uYWw+CiNkZWZpbmUgZXZlbnQoZXZlbnRuYW1lLCAuLi4gKSBzdGQ6OmZ1bmN0aW9uPHZvaWQoX19WQV9BUkdTX18gKT4gZXZlbnRuYW1lCgp0eXBlZGVmIENPTE9SUkVGIGNvbG9yOwoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCmNvbnN0IGNoYXIgKmxhYmVscHJvcG5hbWUgPSAiQ2FtYmFsaW5obyI7CmNvbnN0IGNoYXIgKmxhYmVsY2xhc3Nwcm9wID0gImNsYXNzYWRkciI7CgplbnVtIE1vdXNlQnV0dG9ucwp7CiAgICBOb25lPS0xLAogICAgTGVmdD0wLAogICAgUmlnaHQ9MSwKICAgIE1pZGRsZT0yLAogICAgWDE9MywKICAgIFgyPTQKfTsKCnN0cnVjdCBQb3NpdGlvbgp7CglpbnQgWDsKCWludCBZOwp9OwoKc3RydWN0IFNpemUKewoJaW50IFdpZHRoOwoJaW50IEhlaWdodDsKfTsKCmNsYXNzIGxhYmVsCnsKcHJpdmF0ZToKICAgIEhXTkQgaHduZDsKICAgIGNvbG9yIGNsclRleHRDb2xvcj1SR0IoMCwwLDApOwogICAgY29sb3IgY2xyQmFja0NvbG9yPVJHQigyNTUsMjU1LDI1NSk7CiAgICBib29sIGJsblRyYW5zcGFyZW50PWZhbHNlOwogICAgc3RyaW5nIGNhcHRpb249ImxhYmVsIjsKCiAgICBIUkdOIENyZWF0ZUJpdG1hcFJnbihIV05EIGltYWdlLGNvbG9yIHRyYW5zcGFyZW50PS0xKQogICAgewogICAgICAgIGludCAgICB4PTAsIHk9MDsKICAgICAgICBIUkdOICAgaHJnbjsKICAgICAgICBIUkdOICAgaHJnblRtcDsKICAgICAgICBSRUNUIExhYmVsU2l6ZTsKICAgICAgICBHZXRXaW5kb3dSZWN0KGltYWdlLCZMYWJlbFNpemUpOwogICAgICAgIGludCB3aWR0aD1MYWJlbFNpemUucmlnaHQtTGFiZWxTaXplLmxlZnQ7CiAgICAgICAgaW50IGhlaWdodD1MYWJlbFNpemUuYm90dG9tLUxhYmVsU2l6ZS50b3A7CiAgICAgICAgaHJnbiA9IENyZWF0ZVJlY3RSZ24oMCwgMCwgMCwgMCk7CiAgICAgICAgY29sb3IgcGl4ZWxjb2xvcj0wOwogICAgICAgIEhEQyBoZGNQaXhlbD1HZXREQyhpbWFnZSk7CiAgICAgICAgZm9yICh5ID0gMDsgeSA8IGhlaWdodDsgeSsrKQogICAgICAgIHsKICAgICAgICAgICAgZm9yICh4ID0gMDsgeCA8IHdpZHRoOyB4KyspCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHBpeGVsY29sb3I9R2V0UGl4ZWwoaGRjUGl4ZWwseCx5KTsKICAgICAgICAgICAgICAgIGlmIChwaXhlbGNvbG9yIT10cmFuc3BhcmVudCkKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBocmduVG1wID0gQ3JlYXRlUmVjdFJnbih4LCB5LCB4ICsgMSwgeSArIDEpOwogICAgICAgICAgICAgICAgICAgIENvbWJpbmVSZ24oaHJnbiwgaHJnbiwgaHJnblRtcCwgUkdOX09SKTsKICAgICAgICAgICAgICAgICAgICBEZWxldGVPYmplY3QoaHJnblRtcCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIHJldHVybiBocmduOwogICAgfQoKICAgIHZvaWQgVHJhY2tNb3VzZShIV05EIGh3bmQpCiAgICB7CiAgICAgICAgVFJBQ0tNT1VTRUVWRU5UIHRtZTsKICAgICAgICB0bWUuY2JTaXplID0gc2l6ZW9mKFRSQUNLTU9VU0VFVkVOVCk7CiAgICAgICAgdG1lLmR3RmxhZ3MgPSBUTUVfSE9WRVIgfCBUTUVfTEVBVkU7IC8vVHlwZSBvZiBldmVudHMgdG8gdHJhY2sgJiB0cmlnZ2VyLgogICAgICAgIHRtZS5kd0hvdmVyVGltZSA9IDUwMDA7IC8vSG93IGxvbmcgdGhlIG1vdXNlIGhhcyB0byBiZSBpbiB0aGUgd2luZG93IHRvIHRyaWdnZXIgYSBob3ZlciBldmVudC4KICAgICAgICB0bWUuaHduZFRyYWNrID0gaHduZDsKICAgICAgICBUcmFja01vdXNlRXZlbnQoJnRtZSk7CiAgICB9CgogICAgc3RhdGljIExSRVNVTFQgQ0FMTEJBQ0sgV25kUHJvYyhIV05EIGh3bmQsIFVJTlQgbXNnLCBXUEFSQU0gd1BhcmFtLCBMUEFSQU0gbFBhcmFtKQogICAgewogICAgICAgIFdORFBST0Mgb2xkcHJvYyA9IChXTkRQUk9DKUdldFByb3AoR2V0UGFyZW50KGh3bmQpLCBsYWJlbHByb3BuYW1lKTsKICAgICAgICBpZiAob2xkcHJvYyA9PSBOVUxMKQogICAgICAgICAgICBNZXNzYWdlQm94KE5VTEwsICJvbGRwcm9jbnVsbCIsICJvbGRwcm9jbnVsbCIsIE1CX09LKTsKCiAgICAgICAgbGFiZWwgKmluc3QgPSAobGFiZWwqKUdldFByb3AoaHduZCwgbGFiZWxjbGFzc3Byb3ApOwogICAgICAgIGlmIChpbnN0ID09IE5VTEwgJiYgbXNnID09IFdNX0NSRUFURSkKICAgICAgICAgaW5zdCA9IChsYWJlbCopKCgoTFBDUkVBVEVTVFJVQ1QpbFBhcmFtKS0+bHBDcmVhdGVQYXJhbXMpOwoKICAgICAgICBpZiAoKGluc3QgPT0gTlVMTCkgJiYgKG1zZyAhPSBXTV9OQ0NSRUFURSAmJiBtc2cgIT0gV01fTkNDQUxDU0laRSkpCiAgICAgICAgICAgIE1lc3NhZ2VCb3goTlVMTCwgImluc3RudWxsIiwgImluc3RudWxsIiwgTUJfT0spOwogICAgICAgIHN0YXRpYyBib29sIFRyYWNraW5nTW91c2UgPSBmYWxzZTsKICAgICAgICBzdGF0aWMgYm9vbCBXaW5kb3dTdG9wTW92aW5nID0gTlVMTDsKICAgICAgICBzdGF0aWMgYm9vbCBXaW5kb3dTdG9wUmVzaXplID0gTlVMTDsKICAgICAgICBzdGF0aWMgY29uc3QgVUlOVF9QVFIgTW91c2VTdG9wVGltZXJJRCA9IDE7CiAgICAgICAgSEJSVVNIIGdfaGJyQmFja2dyb3VuZCA9IENyZWF0ZVNvbGlkQnJ1c2goTlVMTF9CUlVTSCk7CgogICAgICAgIHN3aXRjaChtc2cpCiAgICAgICAgewogICAgICAgICAgICBjYXNlIFdNX0NUTENPTE9SU1RBVElDOgogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBIREMgaGRjU3RhdGljID0gKEhEQyl3UGFyYW07CiAgICAgICAgICAgICAgICBTZXRUZXh0Q29sb3IoaGRjU3RhdGljLCBpbnN0LT5jbHJUZXh0Q29sb3IpOwogICAgICAgICAgICAgICAgU2V0QmtNb2RlKGhkY1N0YXRpYywgVFJBTlNQQVJFTlQpOwogICAgICAgICAgICAgICAgU2V0QmtDb2xvcihoZGNTdGF0aWMsaW5zdC0+Y2xyQmFja0NvbG9yKTsKICAgICAgICAgICAgICAgIGdfaGJyQmFja2dyb3VuZCA9IENyZWF0ZVNvbGlkQnJ1c2goaW5zdC0+Y2xyQmFja0NvbG9yKTsKICAgICAgICAgICAgICAgIHJldHVybiAoTE9ORylnX2hickJhY2tncm91bmQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgV01fQ1JFQVRFOgogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBzdGF0aWMgaW50IHhQb3MgPSAoaW50KShzaG9ydCkgTE9XT1JEKGxQYXJhbSk7CiAgICAgICAgICAgICAgICBzdGF0aWMgaW50IHlQb3MgPSAoaW50KShzaG9ydCkgSElXT1JEKGxQYXJhbSk7CiAgICAgICAgICAgICAgICBpbnN0LT5DcmVhdGUoeFBvcyx5UG9zKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhazsKCiAgICAgICAgICAgIGNhc2UgV01fTU9WRToKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgc3RhdGljIGludCB4UG9zID0gKGludCkoc2hvcnQpIExPV09SRChsUGFyYW0pOwogICAgICAgICAgICAgICAgc3RhdGljIGludCB5UG9zID0gKGludCkoc2hvcnQpIEhJV09SRChsUGFyYW0pOwogICAgICAgICAgICAgICAgaW5zdC0+TW92ZSh4UG9zLHlQb3MpOwogICAgICAgICAgICAgICAgV2luZG93U3RvcE1vdmluZz1mYWxzZTsKICAgICAgICAgICAgICAgIFdpbmRvd1N0b3BSZXNpemU9dHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSBXTV9TSVpFIDoKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgV2luZG93U3RvcFJlc2l6ZT1mYWxzZTsKICAgICAgICAgICAgICAgIFdpbmRvd1N0b3BNb3Zpbmc9dHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSBXTV9FWElUU0laRU1PVkU6CiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGlmKFdpbmRvd1N0b3BSZXNpemU9PWZhbHNlKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIFdpbmRvd1N0b3BSZXNpemU9dHJ1ZTsKICAgICAgICAgICAgICAgICAgICBpbnN0LT5Ob3RSZXNpemUoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGVsc2UgaWYgKFdpbmRvd1N0b3BNb3Zpbmc9PWZhbHNlKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIFdpbmRvd1N0b3BNb3Zpbmc9dHJ1ZTsKICAgICAgICAgICAgICAgICAgICBpbnN0LT5TdG9wKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYnJlYWs7CgogICAgICAgICAgICBjYXNlIFdNX05DSElUVEVTVDoKICAgICAgICAgICAgICAgIHJldHVybiBEZWZXaW5kb3dQcm9jKGh3bmQsIG1zZywgd1BhcmFtLCBsUGFyYW0pOwoKICAgICAgICAgICAgY2FzZSBXTV9MQlVUVE9ORE9XTjoKICAgICAgICAgICAgY2FzZSBXTV9SQlVUVE9ORE9XTjoKICAgICAgICAgICAgY2FzZSBXTV9NQlVUVE9ORE9XTjoKICAgICAgICAgICAgY2FzZSBXTV9YQlVUVE9ORE9XTjoKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgU2V0Rm9jdXMoaW5zdC0+aHduZCk7CiAgICAgICAgICAgICAgICBzdGF0aWMgaW50IHhQb3MgPSAoaW50KShzaG9ydCkgTE9XT1JEKGxQYXJhbSk7CiAgICAgICAgICAgICAgICBzdGF0aWMgaW50IHlQb3MgPSAoaW50KShzaG9ydCkgSElXT1JEKGxQYXJhbSk7CiAgICAgICAgICAgICAgICBib29sIGJsQ29udHJvbCA9ICgod1BhcmFtICYgTUtfQ09OVFJPTCkgPT0gTUtfQ09OVFJPTCk7CiAgICAgICAgICAgICAgICBib29sIGJsc2hpZnQgPSAoKHdQYXJhbSAmIE1LX1NISUZUKSA9PSBNS19TSElGVCk7CiAgICAgICAgICAgICAgICBNb3VzZUJ1dHRvbnMgTUJCdXR0b25zOwogICAgICAgICAgICAgICAgaWYoKHdQYXJhbSAmIE1LX0xCVVRUT04pIT0gZmFsc2UpCiAgICAgICAgICAgICAgICAgICAgTUJCdXR0b25zPUxlZnQ7CiAgICAgICAgICAgICAgICBlbHNlIGlmICh3UGFyYW0gJiBNS19SQlVUVE9OKQogICAgICAgICAgICAgICAgICAgIE1CQnV0dG9ucz1SaWdodDsKICAgICAgICAgICAgICAgIGVsc2UgaWYgKHdQYXJhbSAmIE1LX01CVVRUT04pCiAgICAgICAgICAgICAgICAgICAgTUJCdXR0b25zPU1pZGRsZTsKICAgICAgICAgICAgICAgIGVsc2UgaWYgKHdQYXJhbSAmIE1LX1hCVVRUT04xKQogICAgICAgICAgICAgICAgICAgIE1CQnV0dG9ucz1YMTsKICAgICAgICAgICAgICAgIGVsc2UgaWYgKHdQYXJhbSAmIE1LX1hCVVRUT04yKQogICAgICAgICAgICAgICAgICAgIE1CQnV0dG9ucz1YMjsKICAgICAgICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICAgICAgICBNQkJ1dHRvbnM9Tm9uZTsKICAgICAgICAgICAgICAgIGluc3QtPk1vdXNlRG93bihNQkJ1dHRvbnMsYmxDb250cm9sLGJsc2hpZnQseFBvcyx5UG9zKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSBXTV9MQlVUVE9OVVA6CiAgICAgICAgICAgIGNhc2UgV01fUkJVVFRPTlVQOgogICAgICAgICAgICBjYXNlIFdNX01CVVRUT05VUDoKICAgICAgICAgICAgY2FzZSBXTV9YQlVUVE9OVVA6CiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIFNldEZvY3VzKGluc3QtPmh3bmQpOwogICAgICAgICAgICAgICAgc3RhdGljIGludCB4UG9zID0gKGludCkoc2hvcnQpIExPV09SRChsUGFyYW0pOwogICAgICAgICAgICAgICAgc3RhdGljIGludCB5UG9zID0gKGludCkoc2hvcnQpIEhJV09SRChsUGFyYW0pOwogICAgICAgICAgICAgICAgYm9vbCBibENvbnRyb2wgPSAoKHdQYXJhbSAmIE1LX0NPTlRST0wpID09IE1LX0NPTlRST0wpOwogICAgICAgICAgICAgICAgYm9vbCBibHNoaWZ0ID0gKCh3UGFyYW0gJiBNS19TSElGVCkgPT0gTUtfU0hJRlQpOwogICAgICAgICAgICAgICAgTW91c2VCdXR0b25zIE1CQnV0dG9uczsKICAgICAgICAgICAgICAgIGlmIChtc2cgPT0gV01fTEJVVFRPTlVQKQogICAgICAgICAgICAgICAgICAgIE1CQnV0dG9ucz1MZWZ0OwogICAgICAgICAgICAgICAgZWxzZSBpZiAobXNnID09IFdNX1JCVVRUT05VUCkKICAgICAgICAgICAgICAgICAgICBNQkJ1dHRvbnM9UmlnaHQ7CiAgICAgICAgICAgICAgICBlbHNlIGlmIChtc2cgPT0gV01fTUJVVFRPTlVQKQogICAgICAgICAgICAgICAgICAgIE1CQnV0dG9ucz1NaWRkbGU7CgkJCQllbHNlIGlmIChtc2cgPT0gV01fWEJVVFRPTlVQKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGlmICh3UGFyYW0gJiBNS19YQlVUVE9OMSkKICAgICAgICAgICAgICAgICAgICAgICAgTUJCdXR0b25zPVgxOwogICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKHdQYXJhbSAmIE1LX1hCVVRUT04yKQogICAgICAgICAgICAgICAgICAgICAgICBNQkJ1dHRvbnM9WDI7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICAgICAgTUJCdXR0b25zPU5vbmU7CiAgICAgICAgICAgICAgICBpbnN0LT5Nb3VzZVVwKE1CQnV0dG9ucyxibENvbnRyb2wsYmxzaGlmdCx4UG9zLHlQb3MpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICBjYXNlIFdNX01PVVNFTEVBVkUgOgogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBUcmFja2luZ01vdXNlID0gZmFsc2U7CiAgICAgICAgICAgICAgICBpbnN0LT5Nb3VzZUxlYXZlKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgV01fTkNNT1VTRU1PVkU6CiAgICAgICAgICAgIGNhc2UgV01fTU9VU0VNT1ZFOgogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBpZiAoIVRyYWNraW5nTW91c2UpCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaW5zdC0+VHJhY2tNb3VzZShod25kKTsKICAgICAgICAgICAgICAgICAgICBUcmFja2luZ01vdXNlID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICBpbnN0LT5Nb3VzZUVudGVyKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBzdGF0aWMgaW50IHhQb3MgPSAoaW50KShzaG9ydCkgTE9XT1JEKGxQYXJhbSk7CiAgICAgICAgICAgICAgICBzdGF0aWMgaW50IHlQb3MgPSAoaW50KShzaG9ydCkgSElXT1JEKGxQYXJhbSk7CiAgICAgICAgICAgICAgICBzdGF0aWMgYm9vbCBibENvbnRyb2wgPSAoKHdQYXJhbSAmIE1LX0NPTlRST0wpID09IE1LX0NPTlRST0wpOwogICAgICAgICAgICAgICAgc3RhdGljIGJvb2wgYmxzaGlmdCA9ICgod1BhcmFtICYgTUtfU0hJRlQpID09IE1LX1NISUZUKTsKICAgICAgICAgICAgICAgIHN0YXRpYyBNb3VzZUJ1dHRvbnMgTUJCdXR0b25zOwogICAgICAgICAgICAgICAgaWYoKHdQYXJhbSAmIE1LX0xCVVRUT04pIT0gZmFsc2UpCiAgICAgICAgICAgICAgICAgICAgTUJCdXR0b25zPUxlZnQ7CiAgICAgICAgICAgICAgICBlbHNlIGlmICgod1BhcmFtICYgTUtfUkJVVFRPTikhPSBmYWxzZSkKICAgICAgICAgICAgICAgICAgICBNQkJ1dHRvbnM9UmlnaHQ7CiAgICAgICAgICAgICAgICBlbHNlIGlmICgod1BhcmFtICYgTUtfTUJVVFRPTikhPSBmYWxzZSkKICAgICAgICAgICAgICAgICAgICBNQkJ1dHRvbnM9TWlkZGxlOwogICAgICAgICAgICAgICAgZWxzZSBpZiAoKHdQYXJhbSAmIE1LX1hCVVRUT04xKSE9IGZhbHNlKQogICAgICAgICAgICAgICAgICAgIE1CQnV0dG9ucz1YMTsKICAgICAgICAgICAgICAgIGVsc2UgaWYgKCh3UGFyYW0gJiBNS19YQlVUVE9OMikhPSBmYWxzZSkKICAgICAgICAgICAgICAgICAgICBNQkJ1dHRvbnM9WDI7CiAgICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICAgICAgTUJCdXR0b25zPU5vbmU7CgogICAgICAgICAgICAgICAgaW5zdC0+TW91c2VNb3ZlKE1CQnV0dG9ucyxibENvbnRyb2wsYmxzaGlmdCx4UG9zLHlQb3MpOwogICAgICAgICAgICAgICAgS2lsbFRpbWVyKGh3bmQsIE1vdXNlU3RvcFRpbWVySUQpOwogICAgICAgICAgICAgICAgU2V0VGltZXIoaHduZCwgTW91c2VTdG9wVGltZXJJRCwgNTAwLCBOVUxMKTsKICAgICAgICAgICAgfQoJCQlicmVhazsKICAgICAgICAgICAgY2FzZSBXTV9NT1VTRUhPVkVSOgogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBpbnN0LT5Nb3VzZUhvdmVyKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgV01fVElNRVI6CiAgICAgICAgICAgIHN3aXRjaCh3UGFyYW0pCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGNhc2UgTW91c2VTdG9wVGltZXJJRDoKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBLaWxsVGltZXIoaHduZCwgTW91c2VTdG9wVGltZXJJRCk7CiAgICAgICAgICAgICAgICAgICAgaW5zdC0+TW91c2VTdG9wZWQoKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSBXTV9LRVlVUDoKICAgICAgICAgICAgICAgIGluc3QtPktleVVwKGxQYXJhbSx3UGFyYW0pOwoJCQlicmVhazsKICAgICAgICAgICAgY2FzZSBXTV9LRVlET1dOOgogICAgICAgICAgICAgICAgaW5zdC0+S2V5RG93bihsUGFyYW0sd1BhcmFtKTsKCQkJYnJlYWs7CgogICAgICAgICAgICBkZWZhdWx0OgoJCQlicmVhazsKICAgICAgICB9CgogICAgICAgIHJldHVybiBvbGRwcm9jID8gQ2FsbFdpbmRvd1Byb2Mob2xkcHJvYywgaHduZCwgbXNnLCB3UGFyYW0sIGxQYXJhbSkgOiBEZWZXaW5kb3dQcm9jKGh3bmQsIG1zZywgd1BhcmFtLCBsUGFyYW0pOwogICAgfQoKCnB1YmxpYzoKCiAgICAvL2lzIHRoZXNlIDIgbGluZXMgb2s/CiAgICAvL3NlZSB0aGUgI2RlZmluZSBvbiB0b3AKICAgIGV2ZW50KE5vdFJlc2l6ZSk9W10oKXs7fTsKICAgIGV2ZW50KFN0b3ApPVtdKCl7O307CiAgICBldmVudChNb3VzZUVudGVyKT1bXSgpezt9OwogICAgZXZlbnQoTW91c2VMZWF2ZSk9W10oKXs7fTsKICAgIGV2ZW50KENyZWF0ZSwoaW50IHgsIGludCB5KSk9W10oaW50IHgsIGludCB5KXs7fTsKICAgIGV2ZW50KE1vdmUsKGludCB4LCBpbnQgeSkpPVtdKGludCB4LCBpbnQgeSl7O307CiAgICBldmVudChNb3VzZURvd24sKE1vdXNlQnV0dG9ucyBCdXR0b24sYm9vbCBjb250cm9sLCBib29sIHNoaWZ0LCBpbnQgeCwgaW50IHkpKT1bXShpbnQgQnV0dG9uLCBib29sIGFsdCwgYm9vbCBzaGlmdCxpbnQgeCwgaW50IHkpezt9OwogICAgZXZlbnQoTW91c2VVcCwoTW91c2VCdXR0b25zIEJ1dHRvbixib29sIGNvbnRyb2wsIGJvb2wgc2hpZnQsIGludCB4LCBpbnQgeSkpPVtdKGludCBCdXR0b24sIGJvb2wgYWx0LCBib29sIHNoaWZ0LGludCB4LCBpbnQgeSl7O307CiAgICBldmVudChNb3VzZU1vdmUsKE1vdXNlQnV0dG9ucyBCdXR0b24sYm9vbCBjb250cm9sLCBib29sIHNoaWZ0LCBpbnQgeCwgaW50IHkpKT1bXShpbnQgQnV0dG9uLCBib29sIGFsdCwgYm9vbCBzaGlmdCxpbnQgeCwgaW50IHkpezt9OwogICAgZXZlbnQoTW91c2VTdG9wZWQpPVtdKCl7O307CiAgICBldmVudChNb3VzZUhvdmVyKT1bXSgpezt9OwogICAgZXZlbnQoTW91c2VDbGljaywoTW91c2VCdXR0b25zIEJ1dHRvbixib29sIGNvbnRyb2wsIGJvb2wgc2hpZnQsIGludCB4LCBpbnQgeSkpPVtdKGludCBCdXR0b24sIGJvb2wgYWx0LCBib29sIHNoaWZ0LGludCB4LCBpbnQgeSl7O307CiAgICBldmVudChNb3VzZURvdWJsZUNsaWNrLChNb3VzZUJ1dHRvbnMgQnV0dG9uLGJvb2wgY29udHJvbCwgYm9vbCBzaGlmdCwgaW50IHgsIGludCB5KSk9W10oaW50IEJ1dHRvbiwgYm9vbCBhbHQsIGJvb2wgc2hpZnQsaW50IHgsIGludCB5KXs7fTsKICAgIGV2ZW50KE1vdXNlV2hlbGwsKGludCBXaGVsbCwgTW91c2VCdXR0b25zIEJ1dHRvbixib29sIGNvbnRyb2wsIGJvb2wgc2hpZnQsIGludCB4LCBpbnQgeSkpPVtdKGludCBXaGVsbCwgaW50IEJ1dHRvbiwgYm9vbCBhbHQsIGJvb2wgc2hpZnQsaW50IHgsIGludCB5KXs7fTsKICAgIGV2ZW50KEtleURvd24sKGludCByZXBlYXQsaW50IEtleSkpPVtdKGludCByZXBlYXQsaW50IEtleSl7O307CiAgICBldmVudChLZXlVcCwoaW50IHJlcGVhdCxpbnQgS2V5KSk9W10oaW50IHJlcGVhdCxpbnQgS2V5KXs7fTsKCgl+bGFiZWwoKQoJewoJCURlc3Ryb3lXaW5kb3coaHduZCk7CgkJaHduZCA9IDA7Cgl9CiAgICBsYWJlbCgpCiAgICB7CiAgICAgICAgOwogICAgfQoKICAgIHZvaWQgc2V0cGFyZW50KEhXTkQgcGFyZW50KQogICAgewogICAgICAgIHN0YXRpYyBpbnQgaSA9IDA7CiAgICAgICAgaSsrOwogICAgICAgIHN0cmluZyBzdHJjbGFzcz1sYWJlbGNsYXNzcHJvcCArIHRvX3N0cmluZyhpKTsKICAgICAgICBsYWJlbGNsYXNzcHJvcD1zdHJjbGFzcy5jX3N0cigpOwogICAgICAgIFdORENMQVNTIHdjOwoJCUhJTlNUQU5DRSBtb2QgPSAoSElOU1RBTkNFKUdldE1vZHVsZUhhbmRsZShOVUxMKTsKCgkgICAgWmVyb01lbW9yeSgmd2MsIHNpemVvZihXTkRDTEFTUykpOwoJCUdldENsYXNzSW5mbyhtb2QsICJTVEFUSUMiLCAmd2MpOwoKCQl3Yy5oSW5zdGFuY2UgPSBtb2Q7CgkJd2MubHBzekNsYXNzTmFtZSA9IGxhYmVsY2xhc3Nwcm9wOwoJCXdjLmhickJhY2tncm91bmQgPSAgQ3JlYXRlU29saWRCcnVzaChSR0IoMjU1LDAsMCkpOwoKCQkvLyBzdG9yZSB0aGUgb2xkIFdORFBST0Mgb2YgdGhlIEVESVQgd2luZG93IGNsYXNzCiAgICAgICAgU2V0UHJvcChwYXJlbnQsIGxhYmVscHJvcG5hbWUsIChIQU5ETEUpd2MubHBmblduZFByb2MpOwoKCS8vIHJlcGxhY2UgaXQgd2l0aCBsb2NhbCBXTkRQUk9DCgl3Yy5scGZuV25kUHJvYyA9IFduZFByb2M7CgoJLy8gcmVnaXN0ZXIgdGhlIG5ldyB3aW5kb3cgY2xhc3MsICJTaEVkaXQiCglpZiAoIVJlZ2lzdGVyQ2xhc3MoJndjKSkKCQlNZXNzYWdlQm94KE5VTEwsICJlcnJvciBpbiByZWdpc3RlciIsICJlcnJvciIsIE1CX09LKTsKCiAgICAgICAgaHduZCA9IENyZWF0ZVdpbmRvd0V4KAogICAgICAgICAgICBXU19FWF9MRUZUfCBXU19FWF9MVFJSRUFESU5HIHwgV1NfRVhfUklHSFRTQ1JPTExCQVIgfCBXU19FWF9UUkFOU1BBUkVOVCwKICAgICAgICAgICAgbGFiZWxjbGFzc3Byb3AsCiAgICAgICAgICAgIGxhYmVsY2xhc3Nwcm9wLAogICAgICAgICAgICBTU19MRUZUfFdTX0NISUxEfFdTX1ZJU0lCTEV8V1NfT1ZFUkxBUFBFRCwKICAgICAgICAgICAgMTAwLCAxMDAsIDEwMCwgMTAwLAogICAgICAgICAgICBwYXJlbnQsCiAgICAgICAgICAgIE5VTEwsCiAgICAgICAgICAgIG1vZCwKICAgICAgICAgICAgKExQVk9JRCl0aGlzKTsKCglpZiAoaHduZCA9PSBOVUxMKQoJCU1lc3NhZ2VCb3goTlVMTCwgImVycm9yIGluIGNyZWF0ZSIsICJlcnJvciIsIE1CX09LKTsKCiAgICAgICAgU2V0UHJvcChod25kLCBsYWJlbGNsYXNzcHJvcCwgKEhBTkRMRSl0aGlzKTsKICAgICAgICAvL1NldFdpbmRvd0xvbmdQdHIodGhpcy0+aHduZCxHV0xQX1VTRVJEQVRBLChMT05HKSB0aGlzKTsKICAgICAgICBVcGRhdGVXaW5kb3coaHduZCk7CiAgICAgICAgY2xyQmFja0NvbG9yPUdldFBpeGVsKEdldERDKGh3bmQpLDAsMCk7CiAgICB9CgogICAgU2l6ZSBHZXRTaXplKCkKICAgIHsKICAgICAgICBSRUNUIExhYmVsU2l6ZTsKICAgICAgICBHZXRXaW5kb3dSZWN0KHRoaXMtPmh3bmQsJkxhYmVsU2l6ZSk7CiAgICAgICAgU2l6ZSBjcmRTaXplID0ge0xhYmVsU2l6ZS5yaWdodC1MYWJlbFNpemUubGVmdCxMYWJlbFNpemUuYm90dG9tLUxhYmVsU2l6ZS50b3B9OwogICAgICAgIHJldHVybiBjcmRTaXplOwogICAgfQoKICAgIHZvaWQgU2V0U2l6ZShpbnQgV2lkdGgsIGludCBIZWlnaHQpCiAgICB7CiAgICAgICAgUkVDVCBMYWJlbFNpemU7CiAgICAgICAgR2V0V2luZG93UmVjdCh0aGlzLT5od25kLCZMYWJlbFNpemUpOwogICAgICAgIExhYmVsU2l6ZS5yaWdodD1MYWJlbFNpemUubGVmdCtXaWR0aDsKICAgICAgICBMYWJlbFNpemUuYm90dG9tPUxhYmVsU2l6ZS50b3ArSGVpZ2h0OwogICAgICAgIFNldFdpbmRvd1Bvcyh0aGlzLT5od25kLEhXTkRfVE9QLExhYmVsU2l6ZS5sZWZ0LExhYmVsU2l6ZS50b3AsV2lkdGgsSGVpZ2h0LFNXUF9OT01PVkV8U1dQX05PWk9SREVSKTsKICAgIH0KCiAgICBQb3NpdGlvbiBHZXRQb3NpdGlvbigpCiAgICB7CiAgICAgICAgUkVDVCBMYWJlbFNpemU7CiAgICAgICAgR2V0V2luZG93UmVjdCh0aGlzLT5od25kLCZMYWJlbFNpemUpOwogICAgICAgIFBvc2l0aW9uIGNyZFNpemUgPSB7TGFiZWxTaXplLmxlZnQsTGFiZWxTaXplLnRvcH07CiAgICAgICAgcmV0dXJuIGNyZFNpemU7CiAgICB9CgogICAgdm9pZCBTZXRQb3NpdGlvbihpbnQgeCwgaW50IHkpCiAgICB7CiAgICAgICAgUkVDVCBMYWJlbFNpemU7CiAgICAgICAgR2V0V2luZG93UmVjdCh0aGlzLT5od25kLCZMYWJlbFNpemUpOwogICAgICAgIFNldFdpbmRvd1Bvcyh0aGlzLT5od25kLEhXTkRfVE9QLHgseSwwLDAsU1dQX05PU0laRXxTV1BfTk9aT1JERVIpOwogICAgfQoKCgogICAgdm9pZCBUcmFuc3BhcmVudCgpCiAgICB7CiAgICAgICAgUkVDVCBMYWJlbFNpemU7CiAgICAgICAgR2V0V2luZG93UmVjdCh0aGlzLT5od25kLCZMYWJlbFNpemUpOwogICAgICAgIEhSR04gaFJnbiA9IENyZWF0ZUJpdG1hcFJnbih0aGlzLT5od25kLCB0aGlzLT5jbHJCYWNrQ29sb3IpOwogICAgICAgIFNldFdpbmRvd1Jnbih0aGlzLT5od25kLCBoUmduLCB0cnVlKTsKICAgIH0KCiAgICB2b2lkIFNldFRleHQoc3RyaW5nIHRleHQpCiAgICB7CiAgICAgICAgdGhpcy0+Y2FwdGlvbj10ZXh0OwogICAgICAgIFNldFdpbmRvd1RleHQodGhpcy0+aHduZCx0ZXh0LmNfc3RyKCkpOwogICAgfQoKICAgIHN0cmluZyBHZXRUZXh0KCkKICAgIHsKICAgICAgICByZXR1cm4gdGhpcy0+Y2FwdGlvbjsKICAgIH0KCiAgICB2b2lkIFNldEJhY2tDb2xvcihDT0xPUlJFRiBjb2xvcikKICAgIHsKICAgICAgICBjbHJCYWNrQ29sb3I9Y29sb3I7CiAgICAgICAgU2hvd1dpbmRvdyh0aGlzLT5od25kLFNXX0hJREUpOwogICAgICAgIFNob3dXaW5kb3codGhpcy0+aHduZCxTV19TSE9XKTsKICAgIH0KCiAgICBjb2xvciBHZXRCYWNrQ29sb3IoKQogICAgewogICAgICAgIHJldHVybiBjbHJCYWNrQ29sb3I7CiAgICB9CgogICAgdm9pZCBTZXRDb2xvclRleHQoQ09MT1JSRUYgY29sb3IpCiAgICB7CiAgICAgICAgY2xyVGV4dENvbG9yPWNvbG9yOwogICAgICAgIFNob3dXaW5kb3codGhpcy0+aHduZCxTV19ISURFKTsKICAgICAgICBTaG93V2luZG93KHRoaXMtPmh3bmQsU1dfU0hPVyk7CiAgICB9CgogICAgY29sb3IgR2V0Q29sb3JUZXh0KCkKICAgIHsKICAgICAgICByZXR1cm4gdGhpcy0+Y2xyVGV4dENvbG9yOwogICAgfQoKICAgIEhGT05UIEdldEZvbnQoKQogICAgewogICAgICAgIEhGT05UIGFjdHVhbDsKICAgICAgICBhY3R1YWw9KEhGT05UKVNlbmRNZXNzYWdlKGh3bmQsV01fR0VURk9OVCwwLDApOwogICAgICAgIHJldHVybiBhY3R1YWw7CiAgICB9CiAgICB2b2lkIFNldEZvbnQoSEZPTlQgbmV3Zm9udCkKICAgIHsKICAgICAgICBTZW5kTWVzc2FnZShod25kLFdNX1NFVEZPTlQsKFdQQVJBTSluZXdmb250LDApOwogICAgfQogICAgdm9pZCBTZXRJbWFnZShzdHJpbmcgRmlsZU5hbWUpCiAgICB7CiAgICAgICAgSEJJVE1BUCBibXBTb3VyY2UgPSBOVUxMOwogICAgICAgIGJtcFNvdXJjZSA9IChIQklUTUFQKUxvYWRJbWFnZShOVUxMLEZpbGVOYW1lLmNfc3RyKCksIElNQUdFX0lDT04sIDAsIDAsIExSX0xPQURGUk9NRklMRSk7CiAgICAgICAgU2VuZE1lc3NhZ2UodGhpcy0+aHduZCxTVE1fU0VUSUNPTiwoV1BBUkFNKSBJTUFHRV9JQ09OLChMUEFSQU0pIGJtcFNvdXJjZSk7CiAgICB9CgogICAgSFdORCBHZXRIV05EKCkKICAgIHsKICAgICAgICByZXR1cm4gaHduZDsKICAgIH0KfTsK