// copyright ◆en3PGsfOXo http://t...content-available-to-author-only...h.net/test/read.cgi/tech/1363042502/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define SHOW_MARK 1
char *TITLE = "glyf";
BYTE *gflg = "AQv/8AIYH8k5JMkBA/ACCxeSSSQBA/ABDP/4ARLJ+SACEyDkknySAAIDB/8=";
BYTE *glyf = "AAwASAU7AAD/OgAAAAAC2f0ZAAAAAP0n/zoAAAAABdEAxgAAAAD9uALnAAAAAAJI"
"AMYAAAAgAGUEYAIb/MkAAAAA/5kAPv9nADb/zwA0/9AAj//QAFYAAAByAAAA5wBb"
"ADEALAAKAAAAAP8z/6H/2P86/8r/kwAA/uoAAP7IAS0AAAEVAAABEgErAUIA9AAA"
"AOIAAAD1/vgAAP8N/0kAKv//AJT/bQCi/2oAAP9pAAD/Tf9O//T/fAAEAGwBdwAA"
"/0QAAAAABhQAvAAAABgAbwRxAi4AAP7v/uj+xP8VAAD/EwAA/ukBPAAAAREAAAER"
"ARcBPQDtAAAA6wAAARj+w/8+/u8AAADZ/1YA0/9pAAD/ZwAA/1f/LQAA/ycAAP8u"
"AKr/JwCYAAAAlgAAAKsA1wAEACwCPwEd/ub9cf9uAAAArgKPAA0AdwY2BF3+3fuj"
"/1IAAP7hA13+4/yj/1MAAP7aBF0AxAAAAM38nwEXA2EAmwAAAR78nwDCA2EAEwBy"
"A3IDkP/2AAD/1gAK/7EACf/KAAD/qQAA/17/s/+1/8MAAPzn/0QAAAAABF0AvAAA"
"AAD/WwBwAFoAqwBLAFkAAAAxAAAALP/7ACz/+QAhAGQEQwAA/0QAAAAAAHX/r/+6"
"/1D/sv+ZAAD/OAAA/xUBNAAAAREAAACOAFEA3gBFAE4ARABMALUAUABhAAAAWAAA"
"AIj/2wBL/9kAAAHkALwAAP9E+v8AAAKB/7QAIv+IABr/uQAA/2IAAP9Q/yQAAP82"
"AAD/OQCI/zEAlgAAAFAAAACkAEcACAAhAgMF0f/m+8n/VgAA/+QENwDW+i//NAAA"
"AAAA0wDMAAA=";
int glyf_len = 0;
typedef struct _CurvePoint {
BYTE flg;
int x, y;
} CurvePoint;
typedef struct _DrawInfo {
HDC hdc;
int szx, szy, ox, oy, spx, spy, scale;
int state;
} DrawInfo;
int scalex(DrawInfo *di, int x)
{
return di->ox + x / di->scale;
}
int scaley(DrawInfo *di, int y)
{
return di->szy - (di->oy + y / di->scale);
}
int b64decode(BYTE *dst, size_t *dst_size, BYTE *src, int src_size)
{
static BYTE b64o[80] = {
62, 0, 62, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0,
0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
0, 0, 0, 62, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
int i, words = src_size/4, oversize = *dst_size+2, lasti = oversize/3-1;
if(src_size % 4) return 1;
if(*dst_size < words * 3) return 2;
for(i = 0; i <= lasti; i++){
int j;
BYTE c[4];
for(j = 0; j < sizeof(c); j++)
c[j] = b64o[(src[i * sizeof(c) + j] - '+') % sizeof(b64o)];
dst[i * 3 + 0] = ((c[0] << 2) & 0x00fc) | ((c[1] >> 4) & 0x03);
if(i < lasti || oversize % 3)
dst[i * 3 + 1] = ((c[1] << 4) & 0x00f0) | ((c[2] >> 2) & 0x0f);
if(i < lasti || (oversize % 3) == 2)
dst[i * 3 + 2] = ((c[2] << 6) & 0x00c0) | (c[3] & 0x3f);
}
if(src[src_size - 1] == '='){
--(*dst_size);
if(src[src_size - 2] == '=') --(*dst_size);
}
return 0;
}
int initGlyph(BYTE *str)
{
int len
= (strlen(str
) >> 2) * 3; if(b64decode
(str
, &len
, str
, strlen(str
))) return 0; return len;
}
short b2h(BYTE *b)
{
return (short)((b[0] << 8) | b[1]);
}
int getGlyphData(CurvePoint **cp, BYTE **epoc, int *numepoc, char ch)
{
int i, j, k, pos = 0, num = 0, code = 0, fpos = 0, epnum = 0, fnum = 0;
*cp = NULL, *epoc = NULL, *numepoc = 0;
while(pos < glyf_len){
num = b2h(&glyf[pos]), code = b2h(&glyf[pos + 2]);
epnum = gflg[fpos], fnum = (num + 7) / 8;
if(code == ch){
if(!(*cp
= (CurvePoint
*)malloc(num
* sizeof(CurvePoint
)))) break; if(!(*epoc
= (BYTE
*)malloc(*numepoc
= epnum
))) break; for(i = 0; i < epnum; ++i) (*epoc)[i] = gflg[fpos + 1 + i];
for(i = 0, k = 0; i < fnum; ++i){
BYTE b = gflg[fpos + 1 + epnum + i];
BYTE m = 0x80;
for(j = 0; j < 8 - (i == fnum - 1 ? fnum * 8 - num : 0); ++j, m >>= 1)
(*cp)[k++].flg = b & m ? 1 : 0;
}
for(i = 0; i < num; ++i){
(*cp)[i].x = (i ? (*cp)[i-1].x : 0) + b2h(&glyf[pos + (i+1)*4]);
(*cp)[i].y = (i ? (*cp)[i-1].y : 0) + b2h(&glyf[pos + (i+1)*4 + 2]);
}
return num;
}
pos += (num + 1) * 4;
fpos += epnum + fnum + 1;
}
return 0;
}
int drawGlyph(DrawInfo *di, int *w, int *h, int ch)
{
CurvePoint *cp;
BYTE *epoc;
int numepoc, i, j;
int numflags = getGlyphData(&cp, &epoc, &numepoc, ch);
*w = 80, *h = 160;
if(numflags){
BeginPath(di->hdc);
SetBkMode(di->hdc, TRANSPARENT);
for(j = 0; j < numepoc; ++j){
CurvePoint prv;
int k = j ? epoc[j - 1] + 1 : 0;
for(i = k; i <= epoc[j]; ++i){
CurvePoint cur = cp[i];
di->state = i - k;
if(i == k && !(cur.flg & 0x01))
MessageBox(NULL, "off curve first", TITLE, MB_ICONEXCLAMATION|IDOK);
if(i != k)
if(curve(di, &prv, &cur, &cp[i == epoc[j] ? k : i + 1])) continue;
prv = cur;
}
di->state = i - k;
curve(di, &prv, &cp[k], &cp[k + 1]);
}
EndPath(di->hdc);
FillPath(di->hdc);
if(SHOW_MARK){
for(j = 0; j < numepoc; ++j){
int k = j ? epoc[j - 1] + 1 : 0;
for(i = k; i <= epoc[j]; ++i){
CurvePoint cur = cp[i];
int r = i == k ? 4 : 3;
COLORREF col = cur.flg & 0x01 ? RGB(0, 0, 255) : RGB(255, 0, 0);
HPEN hpen = CreatePen(PS_SOLID, 1, col);
HPEN hopen = (HPEN)SelectObject(di->hdc, hpen);
HBRUSH hbrush, hobrush;
if(i == k) hbrush = CreateSolidBrush(RGB(0, 255, 0));
else hbrush = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
hobrush = (HBRUSH)SelectObject(di->hdc, hbrush);
Ellipse(di->hdc, scalex(di, cur.x) - r, scaley(di, cur.y) + r,
scalex(di, cur.x) + r, scaley(di, cur.y) - r);
SelectObject(di->hdc, hobrush);
if(i == k) DeleteObject(hbrush);
SelectObject(di->hdc, hopen);
DeleteObject(hpen);
}
}
}
}
return 0;
}
int bezier(DrawInfo *di, int px, int py, int x, int y, int nx, int ny)
{
#if 0
int t, m = ((nx - px) * (nx - px) + (ny - py) * (ny - py)) / 5000;
if(di->state == 1)
MoveToEx(di->hdc, scalex(di, px), scaley(di, py), NULL);
for(t = 1; t < m; ++t){
float f = t / (float)m;
float a[] = {(1 - f) * (1 - f), 2 * f * (1 - f), f * f};
int tx = a[0] * px + a[1] * x + a[2] * nx;
int ty = a[0] * py + a[1] * y + a[2] * ny;
LineTo(di->hdc, scalex(di, tx), scaley(di, ty));
}
LineTo(di->hdc, scalex(di, nx), scaley(di, ny));
#else
int i;
POINT lppt[4];
lppt[0].x = px, lppt[0].y = py;
lppt[1].x = px + (x - px) * 2 / 3, lppt[1].y = py + (y - py) * 2 / 3;
lppt[2].x = lppt[1].x + (nx - px) / 3, lppt[2].y = lppt[1].y + (ny - py) / 3;
lppt[3].x = nx, lppt[3].y = ny;
for(i = 0; i < sizeof(lppt) / sizeof(lppt[0]); ++i){
lppt[i].x = scalex(di, lppt[i].x);
lppt[i].y = scaley(di, lppt[i].y);
}
if(di->state == 1)
MoveToEx(di->hdc, scalex(di, px), scaley(di, py), NULL);
PolyBezierTo(di->hdc, lppt + 1, (sizeof(lppt) - 1) / sizeof(lppt[0]));
#endif
return 0;
}
int curve(DrawInfo *di, CurvePoint *prv, CurvePoint *cur, CurvePoint *nxt)
{
if(cur->flg & 0x01){
if(!(prv->flg & 0x01))
MessageBox(NULL, "off curve bug", TITLE, MB_ICONEXCLAMATION|IDOK);
stroke(di, prv->x, prv->y, cur->x, cur->y);
return 0;
}
if(nxt->flg & 0x01){
bezier(di, prv->x, prv->y, cur->x, cur->y, nxt->x, nxt->y);
*prv = *nxt;
return !0;
}else{
int mx = (cur->x + nxt->x) / 2, my = (cur->y + nxt->y) / 2;
bezier(di, prv->x, prv->y, cur->x, cur->y, mx, my);
prv->flg = 1, prv->x = mx, prv->y = my;
return !0;
}
}
int stroke(DrawInfo *di, int xs, int ys, int xe, int ye)
{
if(di->state == 1){
POINT p;
MoveToEx(di->hdc, scalex(di, xs), scaley(di, ys), &p);
}
LineTo(di->hdc, scalex(di, xe), scaley(di, ye));
return 0;
}
int drawStrokes(DrawInfo *di, COLORREF foreground_color, char *str)
{
int ox = di->ox, oy = di->oy;
HPEN hpen = CreatePen(PS_SOLID, 1, foreground_color);
HPEN hopen = (HPEN)SelectObject(di->hdc, hpen);
HBRUSH hbrush = CreateSolidBrush(foreground_color);
HBRUSH hobrush = (HBRUSH)SelectObject(di->hdc, hbrush);
char *p;
for(p = str; *p; ++p){
int w, h;
drawGlyph(di, &w, &h, *p);
if(*p == '\n') di->ox = ox, di->oy -= h + di->spy;
else di->ox += w + di->spx;
}
DeleteObject(SelectObject(di->hdc, hobrush));
DeleteObject(SelectObject(di->hdc, hopen));
return 0;
}
int drawCallback(HDC hdc, int szx, int szy, COLORREF transparent_color)
{
DrawInfo di = {hdc, szx, szy, 120, szy - 400, 40, 40, 10, 0};
HPEN hpen = CreatePen(PS_SOLID, 1, transparent_color);
HPEN hopen = (HPEN)SelectObject(hdc, hpen);
HBRUSH hbrush = CreateSolidBrush(transparent_color);
HBRUSH hobrush = (HBRUSH)SelectObject(hdc, hbrush);
Rectangle(hdc, 0, 0, szx, szy);
drawStrokes(&di, RGB(0, 255, 0), "Hello,\nworld!");
DeleteObject(SelectObject(hdc, hobrush));
DeleteObject(SelectObject(hdc, hopen));
return 0;
}
int drawTransparent(HDC hdc, int x, int y, int w, int h,
HDC hmdc, int szx, int szy,
COLORREF transparent_color, int (*callback)(HDC, int, int, COLORREF))
{
HDC hndc = CreateCompatibleDC(hmdc);
HBITMAP hnbmp = CreateBitmap(szx, szy, 1, 1, NULL);
HBITMAP honbmp = (HBITMAP)SelectObject(hndc, hnbmp);
HDC hgndc = CreateCompatibleDC(hmdc);
HBITMAP hgnbmp = CreateCompatibleBitmap(hmdc, szx, szy);
HBITMAP hognbmp = (HBITMAP)SelectObject(hgndc, hgnbmp);
HDC hpdc = CreateCompatibleDC(hmdc);
HBITMAP hpbmp = CreateBitmap(szx, szy, 1, 1, NULL);
HBITMAP hopbmp = (HBITMAP)SelectObject(hpdc, hpbmp);
COLORREF hocol = SetBkColor(hmdc, transparent_color);
callback(hmdc, szx, szy, transparent_color);
BitBlt(hndc, 0, 0, szx, szy, hmdc, 0, 0, SRCCOPY);
BitBlt(hgndc, 0, 0, szx, szy, hndc, 0, 0, SRCCOPY);
BitBlt(hpdc, 0, 0, szx, szy, hndc, 0, 0, NOTSRCCOPY);
SetBkColor(hmdc, hocol);
BitBlt(hmdc, 0, 0, szx, szy, hpdc, 0, 0, SRCAND);
BitBlt(hdc, x, y, w, h, hgndc, 0, 0, SRCAND);
BitBlt(hdc, x, y, w, h, hmdc, 0, 0, SRCPAINT);
DeleteObject(SelectObject(hpdc, hopbmp));
DeleteDC(hpdc);
DeleteObject(SelectObject(hgndc, hognbmp));
DeleteDC(hgndc);
DeleteObject(SelectObject(hndc, honbmp));
DeleteDC(hndc);
return 0;
}
BOOL versionCheck(DWORD major, DWORD minor, DWORD spmajor)
{
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if(osvi.dwMajorVersion > major) return TRUE;
if(osvi.dwMajorVersion < major) return FALSE;
if(osvi.dwMinorVersion > minor) return TRUE;
if(osvi.dwMinorVersion < minor) return FALSE;
if(spmajor && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT){
BOOL spCheck = FALSE;
HKEY hkey;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Control\\Windows",
0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS){
DWORD CSDVersion, sz = sizeof(DWORD);
if(RegQueryValueEx(hkey, "CSDVersion", NULL, NULL,
(BYTE *)&CSDVersion, &sz) == ERROR_SUCCESS)
spCheck = LOWORD(CSDVersion) >= spmajor;
RegCloseKey(hkey);
}
return spCheck;
}
return TRUE;
}
int main(int ac, char **av)
{
if(!versionCheck
(4, 0, 3)) fprintf(stderr
, "error 0"); if(!initGlyph
(gflg
)) fprintf(stderr
, "error 1"); if(!(glyf_len
= initGlyph
(glyf
))) fprintf(stderr
, "error 2"); {
HWND hwnd = GetDesktopWindow();
HDC hdc = GetDC(hwnd);
RECT rc;
GetClientRect(hwnd, &rc);
{
int szx = rc.right - rc.left, szy = rc.bottom - rc.top;
HDC hmdc = CreateCompatibleDC(hdc);
HBITMAP hbmp = CreateCompatibleBitmap(hdc, szx, szy);
HBITMAP hobmp = (HBITMAP)SelectObject(hmdc, hbmp);
BitBlt(hmdc, 0, 0, szx, szy, hdc, 0, 0, SRCCOPY); // for Aero
drawTransparent(hdc, 0, 0, szx, szy, hmdc, szx, szy,
RGB(255, 255, 0), drawCallback);
DeleteObject(SelectObject(hmdc, hobmp));
DeleteDC(hmdc);
}
ReleaseDC(hwnd, hdc);
}
return 0;
}
Ly8gY29weXJpZ2h0IOKXhmVuM1BHc2ZPWG8gaHR0cDovL3QuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmgubmV0L3Rlc3QvcmVhZC5jZ2kvdGVjaC8xMzYzMDQyNTAyLwoKI2luY2x1ZGUgPHdpbmRvd3MuaD4KI2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KCiNkZWZpbmUgU0hPV19NQVJLIDEKCmNoYXIgKlRJVExFID0gImdseWYiOwpCWVRFICpnZmxnID0gIkFRdi84QUlZSDhrNUpNa0JBL0FDQ3hlU1NTUUJBL0FCRFAvNEFSTEorU0FDRXlEa2tueVNBQUlEQi84PSI7CkJZVEUgKmdseWYgPSAiQUF3QVNBVTdBQUQvT2dBQUFBQUMyZjBaQUFBQUFQMG4vem9BQUFBQUJkRUF4Z0FBQUFEOXVBTG5BQUFBQUFKSSIKICAgICAgICAgICAgICJBTVlBQUFBZ0FHVUVZQUliL01rQUFBQUEvNWtBUHY5bkFEYi96d0EwLzlBQWovL1FBRllBQUFCeUFBQUE1d0JiIgogICAgICAgICAgICAgIkFERUFMQUFLQUFBQUFQOHovNkgvMlA4Ni84ci9rd0FBL3VvQUFQN0lBUzBBQUFFVkFBQUJFZ0VyQVVJQTlBQUEiCiAgICAgICAgICAgICAiQU9JQUFBRDEvdmdBQVA4Ti8wa0FLdi8vQUpUL2JRQ2kvMm9BQVA5cEFBRC9UZjlPLy9UL2ZBQUVBR3dCZHdBQSIKICAgICAgICAgICAgICIvMFFBQUFBQUJoUUF2QUFBQUJnQWJ3UnhBaTRBQVA3di91ait4UDhWQUFEL0V3QUEvdWtCUEFBQUFSRUFBQUVSIgogICAgICAgICAgICAgIkFSY0JQUUR0QUFBQTZ3QUFBUmordy84Ky91OEFBQURaLzFZQTAvOXBBQUQvWndBQS8xZi9MUUFBL3ljQUFQOHUiCiAgICAgICAgICAgICAiQUtyL0p3Q1lBQUFBbGdBQUFLc0Exd0FFQUN3Q1B3RWQvdWI5Y2Y5dUFBQUFyZ0tQQUEwQWR3WTJCRjMrM2Z1aiIKICAgICAgICAgICAgICIvMUlBQVA3aEExMys0L3lqLzFNQUFQN2FCRjBBeEFBQUFNMzhud0VYQTJFQW13QUFBUjc4bndEQ0EyRUFFd0J5IgogICAgICAgICAgICAgIkEzSURrUC8yQUFELzFnQUsvN0VBQ2YvS0FBRC9xUUFBLzE3L3MvKzEvOE1BQVB6bi8wUUFBQUFBQkYwQXZBQUEiCiAgICAgICAgICAgICAiQUFEL1d3QndBRm9BcXdCTEFGa0FBQUF4QUFBQUxQLzdBQ3ovK1FBaEFHUUVRd0FBLzBRQUFBQUFBSFgvci8rNiIKICAgICAgICAgICAgICIvMUQvc3YrWkFBRC9PQUFBL3hVQk5BQUFBUkVBQUFDT0FGRUEzZ0JGQUU0QVJBQk1BTFVBVUFCaEFBQUFXQUFBIgogICAgICAgICAgICAgIkFJai8yd0JMLzlrQUFBSGtBTHdBQVA5RSt2OEFBQUtCLzdRQUl2K0lBQnIvdVFBQS8ySUFBUDlRL3lRQUFQODIiCiAgICAgICAgICAgICAiQUFEL09RQ0kvekVBbGdBQUFGQUFBQUNrQUVjQUNBQWhBZ01GMGYvbSs4bi9WZ0FBLytRRU53RFcraS8vTkFBQSIKICAgICAgICAgICAgICJBQUFBMHdETUFBQT0iOwppbnQgZ2x5Zl9sZW4gPSAwOwoKdHlwZWRlZiBzdHJ1Y3QgX0N1cnZlUG9pbnQgewogIEJZVEUgZmxnOwogIGludCB4LCB5Owp9IEN1cnZlUG9pbnQ7Cgp0eXBlZGVmIHN0cnVjdCBfRHJhd0luZm8gewogIEhEQyBoZGM7CiAgaW50IHN6eCwgc3p5LCBveCwgb3ksIHNweCwgc3B5LCBzY2FsZTsKICBpbnQgc3RhdGU7Cn0gRHJhd0luZm87CgppbnQgc2NhbGV4KERyYXdJbmZvICpkaSwgaW50IHgpCnsKICByZXR1cm4gZGktPm94ICsgeCAvIGRpLT5zY2FsZTsKfQoKaW50IHNjYWxleShEcmF3SW5mbyAqZGksIGludCB5KQp7CiAgcmV0dXJuIGRpLT5zenkgLSAoZGktPm95ICsgeSAvIGRpLT5zY2FsZSk7Cn0KCmludCBiNjRkZWNvZGUoQllURSAqZHN0LCBzaXplX3QgKmRzdF9zaXplLCBCWVRFICpzcmMsIGludCBzcmNfc2l6ZSkKewogIHN0YXRpYyBCWVRFIGI2NG9bODBdID0gewogICAgNjIsICAwLCA2MiwgIDAsIDYzLCA1MiwgNTMsIDU0LCA1NSwgNTYsIDU3LCA1OCwgNTksIDYwLCA2MSwgIDAsCiAgICAgMCwgIDAsICAwLCAgMCwgIDAsICAwLCAgMCwgIDEsICAyLCAgMywgIDQsICA1LCAgNiwgIDcsICA4LCAgOSwKICAgIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTUsIDE2LCAxNywgMTgsIDE5LCAyMCwgMjEsIDIyLCAyMywgMjQsIDI1LAogICAgIDAsICAwLCAgMCwgNjIsIDYzLCAgMCwgMjYsIDI3LCAyOCwgMjksIDMwLCAzMSwgMzIsIDMzLCAzNCwgMzUsCiAgICAzNiwgMzcsIDM4LCAzOSwgNDAsIDQxLCA0MiwgNDMsIDQ0LCA0NSwgNDYsIDQ3LCA0OCwgNDksIDUwLCA1MX07CiAgaW50IGksIHdvcmRzID0gc3JjX3NpemUvNCwgb3ZlcnNpemUgPSAqZHN0X3NpemUrMiwgbGFzdGkgPSBvdmVyc2l6ZS8zLTE7CiAgaWYoc3JjX3NpemUgJSA0KSByZXR1cm4gMTsKICBpZigqZHN0X3NpemUgPCB3b3JkcyAqIDMpIHJldHVybiAyOwogIGZvcihpID0gMDsgaSA8PSBsYXN0aTsgaSsrKXsKICAgIGludCBqOwogICAgQllURSBjWzRdOwogICAgZm9yKGogPSAwOyBqIDwgc2l6ZW9mKGMpOyBqKyspCiAgICAgIGNbal0gPSBiNjRvWyhzcmNbaSAqIHNpemVvZihjKSArIGpdIC0gJysnKSAlIHNpemVvZihiNjRvKV07CiAgICBkc3RbaSAqIDMgKyAwXSA9ICgoY1swXSA8PCAyKSAmIDB4MDBmYykgfCAoKGNbMV0gPj4gNCkgJiAweDAzKTsKICAgIGlmKGkgPCBsYXN0aSB8fCBvdmVyc2l6ZSAlIDMpCiAgICAgIGRzdFtpICogMyArIDFdID0gKChjWzFdIDw8IDQpICYgMHgwMGYwKSB8ICgoY1syXSA+PiAyKSAmIDB4MGYpOwogICAgaWYoaSA8IGxhc3RpIHx8IChvdmVyc2l6ZSAlIDMpID09IDIpCiAgICAgIGRzdFtpICogMyArIDJdID0gKChjWzJdIDw8IDYpICYgMHgwMGMwKSB8IChjWzNdICYgMHgzZik7CiAgfQogIGlmKHNyY1tzcmNfc2l6ZSAtIDFdID09ICc9Jyl7CiAgICAtLSgqZHN0X3NpemUpOwogICAgaWYoc3JjW3NyY19zaXplIC0gMl0gPT0gJz0nKSAtLSgqZHN0X3NpemUpOwogIH0KICByZXR1cm4gMDsKfQoKaW50IGluaXRHbHlwaChCWVRFICpzdHIpCnsKICBpbnQgbGVuID0gKHN0cmxlbihzdHIpID4+IDIpICogMzsKICBpZihiNjRkZWNvZGUoc3RyLCAmbGVuLCBzdHIsIHN0cmxlbihzdHIpKSkgcmV0dXJuIDA7CiAgcmV0dXJuIGxlbjsKfQoKc2hvcnQgYjJoKEJZVEUgKmIpCnsKICByZXR1cm4gKHNob3J0KSgoYlswXSA8PCA4KSB8IGJbMV0pOwp9CgppbnQgZ2V0R2x5cGhEYXRhKEN1cnZlUG9pbnQgKipjcCwgQllURSAqKmVwb2MsIGludCAqbnVtZXBvYywgY2hhciBjaCkKewogIGludCBpLCBqLCBrLCBwb3MgPSAwLCBudW0gPSAwLCBjb2RlID0gMCwgZnBvcyA9IDAsIGVwbnVtID0gMCwgZm51bSA9IDA7CiAgKmNwID0gTlVMTCwgKmVwb2MgPSBOVUxMLCAqbnVtZXBvYyA9IDA7CiAgd2hpbGUocG9zIDwgZ2x5Zl9sZW4pewogICAgbnVtID0gYjJoKCZnbHlmW3Bvc10pLCBjb2RlID0gYjJoKCZnbHlmW3BvcyArIDJdKTsKICAgIGVwbnVtID0gZ2ZsZ1tmcG9zXSwgZm51bSA9IChudW0gKyA3KSAvIDg7CiAgICBpZihjb2RlID09IGNoKXsKICAgICAgaWYoISgqY3AgPSAoQ3VydmVQb2ludCAqKW1hbGxvYyhudW0gKiBzaXplb2YoQ3VydmVQb2ludCkpKSkgYnJlYWs7CiAgICAgIGlmKCEoKmVwb2MgPSAoQllURSAqKW1hbGxvYygqbnVtZXBvYyA9IGVwbnVtKSkpIGJyZWFrOwogICAgICBmb3IoaSA9IDA7IGkgPCBlcG51bTsgKytpKSAoKmVwb2MpW2ldID0gZ2ZsZ1tmcG9zICsgMSArIGldOwogICAgICBmb3IoaSA9IDAsIGsgPSAwOyBpIDwgZm51bTsgKytpKXsKICAgICAgICBCWVRFIGIgPSBnZmxnW2Zwb3MgKyAxICsgZXBudW0gKyBpXTsKICAgICAgICBCWVRFIG0gPSAweDgwOwogICAgICAgIGZvcihqID0gMDsgaiA8IDggLSAoaSA9PSBmbnVtIC0gMSA/IGZudW0gKiA4IC0gbnVtIDogMCk7ICsraiwgbSA+Pj0gMSkKICAgICAgICAgICgqY3ApW2srK10uZmxnID0gYiAmIG0gPyAxIDogMDsKICAgICAgfQogICAgICBmb3IoaSA9IDA7IGkgPCBudW07ICsraSl7CiAgICAgICAgKCpjcClbaV0ueCA9IChpID8gKCpjcClbaS0xXS54IDogMCkgKyBiMmgoJmdseWZbcG9zICsgKGkrMSkqNF0pOwogICAgICAgICgqY3ApW2ldLnkgPSAoaSA/ICgqY3ApW2ktMV0ueSA6IDApICsgYjJoKCZnbHlmW3BvcyArIChpKzEpKjQgKyAyXSk7CiAgICAgIH0KICAgICAgcmV0dXJuIG51bTsKICAgIH0KICAgIHBvcyArPSAobnVtICsgMSkgKiA0OwogICAgZnBvcyArPSBlcG51bSArIGZudW0gKyAxOwogIH0KICByZXR1cm4gMDsKfQoKaW50IGRyYXdHbHlwaChEcmF3SW5mbyAqZGksIGludCAqdywgaW50ICpoLCBpbnQgY2gpCnsKICBDdXJ2ZVBvaW50ICpjcDsKICBCWVRFICplcG9jOwogIGludCBudW1lcG9jLCBpLCBqOwogIGludCBudW1mbGFncyA9IGdldEdseXBoRGF0YSgmY3AsICZlcG9jLCAmbnVtZXBvYywgY2gpOwogICp3ID0gODAsICpoID0gMTYwOwogIGlmKG51bWZsYWdzKXsKICAgIEJlZ2luUGF0aChkaS0+aGRjKTsKICAgIFNldEJrTW9kZShkaS0+aGRjLCBUUkFOU1BBUkVOVCk7CiAgICBmb3IoaiA9IDA7IGogPCBudW1lcG9jOyArK2opewogICAgICBDdXJ2ZVBvaW50IHBydjsKICAgICAgaW50IGsgPSBqID8gZXBvY1tqIC0gMV0gKyAxIDogMDsKICAgICAgZm9yKGkgPSBrOyBpIDw9IGVwb2Nbal07ICsraSl7CiAgICAgICAgQ3VydmVQb2ludCBjdXIgPSBjcFtpXTsKICAgICAgICBkaS0+c3RhdGUgPSBpIC0gazsKICAgICAgICBpZihpID09IGsgJiYgIShjdXIuZmxnICYgMHgwMSkpCiAgICAgICAgICBNZXNzYWdlQm94KE5VTEwsICJvZmYgY3VydmUgZmlyc3QiLCBUSVRMRSwgTUJfSUNPTkVYQ0xBTUFUSU9OfElET0spOwogICAgICAgIGlmKGkgIT0gaykKICAgICAgICAgIGlmKGN1cnZlKGRpLCAmcHJ2LCAmY3VyLCAmY3BbaSA9PSBlcG9jW2pdID8gayA6IGkgKyAxXSkpIGNvbnRpbnVlOwogICAgICAgIHBydiA9IGN1cjsKICAgICAgfQogICAgICBkaS0+c3RhdGUgPSBpIC0gazsKICAgICAgY3VydmUoZGksICZwcnYsICZjcFtrXSwgJmNwW2sgKyAxXSk7CiAgICB9CiAgICBFbmRQYXRoKGRpLT5oZGMpOwogICAgRmlsbFBhdGgoZGktPmhkYyk7CiAgICBpZihTSE9XX01BUkspewogICAgICBmb3IoaiA9IDA7IGogPCBudW1lcG9jOyArK2opewogICAgICAgIGludCBrID0gaiA/IGVwb2NbaiAtIDFdICsgMSA6IDA7CiAgICAgICAgZm9yKGkgPSBrOyBpIDw9IGVwb2Nbal07ICsraSl7CiAgICAgICAgICBDdXJ2ZVBvaW50IGN1ciA9IGNwW2ldOwogICAgICAgICAgaW50IHIgPSBpID09IGsgPyA0IDogMzsKICAgICAgICAgIENPTE9SUkVGIGNvbCA9IGN1ci5mbGcgJiAweDAxID8gUkdCKDAsIDAsIDI1NSkgOiBSR0IoMjU1LCAwLCAwKTsKICAgICAgICAgIEhQRU4gaHBlbiA9IENyZWF0ZVBlbihQU19TT0xJRCwgMSwgY29sKTsKICAgICAgICAgIEhQRU4gaG9wZW4gPSAoSFBFTilTZWxlY3RPYmplY3QoZGktPmhkYywgaHBlbik7CiAgICAgICAgICBIQlJVU0ggaGJydXNoLCBob2JydXNoOwogICAgICAgICAgaWYoaSA9PSBrKSBoYnJ1c2ggPSBDcmVhdGVTb2xpZEJydXNoKFJHQigwLCAyNTUsIDApKTsKICAgICAgICAgIGVsc2UgaGJydXNoID0gKEhCUlVTSClHZXRTdG9ja09iamVjdChIT0xMT1dfQlJVU0gpOwogICAgICAgICAgaG9icnVzaCA9IChIQlJVU0gpU2VsZWN0T2JqZWN0KGRpLT5oZGMsIGhicnVzaCk7CiAgICAgICAgICBFbGxpcHNlKGRpLT5oZGMsIHNjYWxleChkaSwgY3VyLngpIC0gciwgc2NhbGV5KGRpLCBjdXIueSkgKyByLAogICAgICAgICAgICBzY2FsZXgoZGksIGN1ci54KSArIHIsIHNjYWxleShkaSwgY3VyLnkpIC0gcik7CiAgICAgICAgICBTZWxlY3RPYmplY3QoZGktPmhkYywgaG9icnVzaCk7CiAgICAgICAgICBpZihpID09IGspIERlbGV0ZU9iamVjdChoYnJ1c2gpOwogICAgICAgICAgU2VsZWN0T2JqZWN0KGRpLT5oZGMsIGhvcGVuKTsKICAgICAgICAgIERlbGV0ZU9iamVjdChocGVuKTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9CiAgaWYoY3ApIGZyZWUoY3ApOwogIGlmKGVwb2MpIGZyZWUoZXBvYyk7CiAgcmV0dXJuIDA7Cn0KCmludCBiZXppZXIoRHJhd0luZm8gKmRpLCBpbnQgcHgsIGludCBweSwgaW50IHgsIGludCB5LCBpbnQgbngsIGludCBueSkKewojaWYgMAogIGludCB0LCBtID0gKChueCAtIHB4KSAqIChueCAtIHB4KSArIChueSAtIHB5KSAqIChueSAtIHB5KSkgLyA1MDAwOwogIGlmKGRpLT5zdGF0ZSA9PSAxKQogICAgTW92ZVRvRXgoZGktPmhkYywgc2NhbGV4KGRpLCBweCksIHNjYWxleShkaSwgcHkpLCBOVUxMKTsKICBmb3IodCA9IDE7IHQgPCBtOyArK3QpewogICAgZmxvYXQgZiA9IHQgLyAoZmxvYXQpbTsKICAgIGZsb2F0IGFbXSA9IHsoMSAtIGYpICogKDEgLSBmKSwgMiAqIGYgKiAoMSAtIGYpLCBmICogZn07CiAgICBpbnQgdHggPSBhWzBdICogcHggKyBhWzFdICogeCArIGFbMl0gKiBueDsKICAgIGludCB0eSA9IGFbMF0gKiBweSArIGFbMV0gKiB5ICsgYVsyXSAqIG55OwogICAgTGluZVRvKGRpLT5oZGMsIHNjYWxleChkaSwgdHgpLCBzY2FsZXkoZGksIHR5KSk7CiAgfQogIExpbmVUbyhkaS0+aGRjLCBzY2FsZXgoZGksIG54KSwgc2NhbGV5KGRpLCBueSkpOwojZWxzZQogIGludCBpOwogIFBPSU5UIGxwcHRbNF07CiAgbHBwdFswXS54ID0gcHgsIGxwcHRbMF0ueSA9IHB5OwogIGxwcHRbMV0ueCA9IHB4ICsgKHggLSBweCkgKiAyIC8gMywgbHBwdFsxXS55ID0gcHkgKyAoeSAtIHB5KSAqIDIgLyAzOwogIGxwcHRbMl0ueCA9IGxwcHRbMV0ueCArIChueCAtIHB4KSAvIDMsIGxwcHRbMl0ueSA9IGxwcHRbMV0ueSArIChueSAtIHB5KSAvIDM7CiAgbHBwdFszXS54ID0gbngsIGxwcHRbM10ueSA9IG55OwogIGZvcihpID0gMDsgaSA8IHNpemVvZihscHB0KSAvIHNpemVvZihscHB0WzBdKTsgKytpKXsKICAgIGxwcHRbaV0ueCA9IHNjYWxleChkaSwgbHBwdFtpXS54KTsKICAgIGxwcHRbaV0ueSA9IHNjYWxleShkaSwgbHBwdFtpXS55KTsKICB9CiAgaWYoZGktPnN0YXRlID09IDEpCiAgICBNb3ZlVG9FeChkaS0+aGRjLCBzY2FsZXgoZGksIHB4KSwgc2NhbGV5KGRpLCBweSksIE5VTEwpOwogIFBvbHlCZXppZXJUbyhkaS0+aGRjLCBscHB0ICsgMSwgKHNpemVvZihscHB0KSAtIDEpIC8gc2l6ZW9mKGxwcHRbMF0pKTsKI2VuZGlmCiAgcmV0dXJuIDA7Cn0KCmludCBjdXJ2ZShEcmF3SW5mbyAqZGksIEN1cnZlUG9pbnQgKnBydiwgQ3VydmVQb2ludCAqY3VyLCBDdXJ2ZVBvaW50ICpueHQpCnsKICBpZihjdXItPmZsZyAmIDB4MDEpewogICAgaWYoIShwcnYtPmZsZyAmIDB4MDEpKQogICAgICBNZXNzYWdlQm94KE5VTEwsICJvZmYgY3VydmUgYnVnIiwgVElUTEUsIE1CX0lDT05FWENMQU1BVElPTnxJRE9LKTsKICAgIHN0cm9rZShkaSwgcHJ2LT54LCBwcnYtPnksIGN1ci0+eCwgY3VyLT55KTsKICAgIHJldHVybiAwOwogIH0KICBpZihueHQtPmZsZyAmIDB4MDEpewogICAgYmV6aWVyKGRpLCBwcnYtPngsIHBydi0+eSwgY3VyLT54LCBjdXItPnksIG54dC0+eCwgbnh0LT55KTsKICAgICpwcnYgPSAqbnh0OwogICAgcmV0dXJuICEwOwogIH1lbHNlewogICAgaW50IG14ID0gKGN1ci0+eCArIG54dC0+eCkgLyAyLCBteSA9IChjdXItPnkgKyBueHQtPnkpIC8gMjsKICAgIGJlemllcihkaSwgcHJ2LT54LCBwcnYtPnksIGN1ci0+eCwgY3VyLT55LCBteCwgbXkpOwogICAgcHJ2LT5mbGcgPSAxLCBwcnYtPnggPSBteCwgcHJ2LT55ID0gbXk7CiAgICByZXR1cm4gITA7CiAgfQp9CgppbnQgc3Ryb2tlKERyYXdJbmZvICpkaSwgaW50IHhzLCBpbnQgeXMsIGludCB4ZSwgaW50IHllKQp7CiAgaWYoZGktPnN0YXRlID09IDEpewogICAgUE9JTlQgcDsKICAgIE1vdmVUb0V4KGRpLT5oZGMsIHNjYWxleChkaSwgeHMpLCBzY2FsZXkoZGksIHlzKSwgJnApOwogIH0KICBMaW5lVG8oZGktPmhkYywgc2NhbGV4KGRpLCB4ZSksIHNjYWxleShkaSwgeWUpKTsKICByZXR1cm4gMDsKfQoKaW50IGRyYXdTdHJva2VzKERyYXdJbmZvICpkaSwgQ09MT1JSRUYgZm9yZWdyb3VuZF9jb2xvciwgY2hhciAqc3RyKQp7CiAgaW50IG94ID0gZGktPm94LCBveSA9IGRpLT5veTsKICBIUEVOIGhwZW4gPSBDcmVhdGVQZW4oUFNfU09MSUQsIDEsIGZvcmVncm91bmRfY29sb3IpOwogIEhQRU4gaG9wZW4gPSAoSFBFTilTZWxlY3RPYmplY3QoZGktPmhkYywgaHBlbik7CiAgSEJSVVNIIGhicnVzaCA9IENyZWF0ZVNvbGlkQnJ1c2goZm9yZWdyb3VuZF9jb2xvcik7CiAgSEJSVVNIIGhvYnJ1c2ggPSAoSEJSVVNIKVNlbGVjdE9iamVjdChkaS0+aGRjLCBoYnJ1c2gpOwogIGNoYXIgKnA7CiAgZm9yKHAgPSBzdHI7ICpwOyArK3ApewogICAgaW50IHcsIGg7CiAgICBkcmF3R2x5cGgoZGksICZ3LCAmaCwgKnApOwogICAgaWYoKnAgPT0gJ1xuJykgZGktPm94ID0gb3gsIGRpLT5veSAtPSBoICsgZGktPnNweTsKICAgIGVsc2UgZGktPm94ICs9IHcgKyBkaS0+c3B4OwogIH0KICBEZWxldGVPYmplY3QoU2VsZWN0T2JqZWN0KGRpLT5oZGMsIGhvYnJ1c2gpKTsKICBEZWxldGVPYmplY3QoU2VsZWN0T2JqZWN0KGRpLT5oZGMsIGhvcGVuKSk7CiAgcmV0dXJuIDA7Cn0KCmludCBkcmF3Q2FsbGJhY2soSERDIGhkYywgaW50IHN6eCwgaW50IHN6eSwgQ09MT1JSRUYgdHJhbnNwYXJlbnRfY29sb3IpCnsKICBEcmF3SW5mbyBkaSA9IHtoZGMsIHN6eCwgc3p5LCAxMjAsIHN6eSAtIDQwMCwgNDAsIDQwLCAxMCwgMH07CiAgSFBFTiBocGVuID0gQ3JlYXRlUGVuKFBTX1NPTElELCAxLCB0cmFuc3BhcmVudF9jb2xvcik7CiAgSFBFTiBob3BlbiA9IChIUEVOKVNlbGVjdE9iamVjdChoZGMsIGhwZW4pOwogIEhCUlVTSCBoYnJ1c2ggPSBDcmVhdGVTb2xpZEJydXNoKHRyYW5zcGFyZW50X2NvbG9yKTsKICBIQlJVU0ggaG9icnVzaCA9IChIQlJVU0gpU2VsZWN0T2JqZWN0KGhkYywgaGJydXNoKTsKICBSZWN0YW5nbGUoaGRjLCAwLCAwLCBzengsIHN6eSk7CiAgZHJhd1N0cm9rZXMoJmRpLCBSR0IoMCwgMjU1LCAwKSwgIkhlbGxvLFxud29ybGQhIik7CiAgRGVsZXRlT2JqZWN0KFNlbGVjdE9iamVjdChoZGMsIGhvYnJ1c2gpKTsKICBEZWxldGVPYmplY3QoU2VsZWN0T2JqZWN0KGhkYywgaG9wZW4pKTsKICByZXR1cm4gMDsKfQoKaW50IGRyYXdUcmFuc3BhcmVudChIREMgaGRjLCBpbnQgeCwgaW50IHksIGludCB3LCBpbnQgaCwKICBIREMgaG1kYywgaW50IHN6eCwgaW50IHN6eSwKICBDT0xPUlJFRiB0cmFuc3BhcmVudF9jb2xvciwgaW50ICgqY2FsbGJhY2spKEhEQywgaW50LCBpbnQsIENPTE9SUkVGKSkKewogIEhEQyBobmRjID0gQ3JlYXRlQ29tcGF0aWJsZURDKGhtZGMpOwogIEhCSVRNQVAgaG5ibXAgPSBDcmVhdGVCaXRtYXAoc3p4LCBzenksIDEsIDEsIE5VTEwpOwogIEhCSVRNQVAgaG9uYm1wID0gKEhCSVRNQVApU2VsZWN0T2JqZWN0KGhuZGMsIGhuYm1wKTsKICBIREMgaGduZGMgPSBDcmVhdGVDb21wYXRpYmxlREMoaG1kYyk7CiAgSEJJVE1BUCBoZ25ibXAgPSBDcmVhdGVDb21wYXRpYmxlQml0bWFwKGhtZGMsIHN6eCwgc3p5KTsKICBIQklUTUFQIGhvZ25ibXAgPSAoSEJJVE1BUClTZWxlY3RPYmplY3QoaGduZGMsIGhnbmJtcCk7CiAgSERDIGhwZGMgPSBDcmVhdGVDb21wYXRpYmxlREMoaG1kYyk7CiAgSEJJVE1BUCBocGJtcCA9IENyZWF0ZUJpdG1hcChzengsIHN6eSwgMSwgMSwgTlVMTCk7CiAgSEJJVE1BUCBob3BibXAgPSAoSEJJVE1BUClTZWxlY3RPYmplY3QoaHBkYywgaHBibXApOwogIENPTE9SUkVGIGhvY29sID0gU2V0QmtDb2xvcihobWRjLCB0cmFuc3BhcmVudF9jb2xvcik7CiAgY2FsbGJhY2soaG1kYywgc3p4LCBzenksIHRyYW5zcGFyZW50X2NvbG9yKTsKICBCaXRCbHQoaG5kYywgMCwgMCwgc3p4LCBzenksIGhtZGMsIDAsIDAsIFNSQ0NPUFkpOwogIEJpdEJsdChoZ25kYywgMCwgMCwgc3p4LCBzenksIGhuZGMsIDAsIDAsIFNSQ0NPUFkpOwogIEJpdEJsdChocGRjLCAwLCAwLCBzengsIHN6eSwgaG5kYywgMCwgMCwgTk9UU1JDQ09QWSk7CiAgU2V0QmtDb2xvcihobWRjLCBob2NvbCk7CiAgQml0Qmx0KGhtZGMsIDAsIDAsIHN6eCwgc3p5LCBocGRjLCAwLCAwLCBTUkNBTkQpOwogIEJpdEJsdChoZGMsIHgsIHksIHcsIGgsIGhnbmRjLCAwLCAwLCBTUkNBTkQpOwogIEJpdEJsdChoZGMsIHgsIHksIHcsIGgsIGhtZGMsIDAsIDAsIFNSQ1BBSU5UKTsKICBEZWxldGVPYmplY3QoU2VsZWN0T2JqZWN0KGhwZGMsIGhvcGJtcCkpOwogIERlbGV0ZURDKGhwZGMpOwogIERlbGV0ZU9iamVjdChTZWxlY3RPYmplY3QoaGduZGMsIGhvZ25ibXApKTsKICBEZWxldGVEQyhoZ25kYyk7CiAgRGVsZXRlT2JqZWN0KFNlbGVjdE9iamVjdChobmRjLCBob25ibXApKTsKICBEZWxldGVEQyhobmRjKTsKICByZXR1cm4gMDsKfQoKQk9PTCB2ZXJzaW9uQ2hlY2soRFdPUkQgbWFqb3IsIERXT1JEIG1pbm9yLCBEV09SRCBzcG1ham9yKQp7CiAgT1NWRVJTSU9OSU5GTyBvc3ZpOwogIFplcm9NZW1vcnkoJm9zdmksIHNpemVvZihPU1ZFUlNJT05JTkZPKSk7CiAgb3N2aS5kd09TVmVyc2lvbkluZm9TaXplID0gc2l6ZW9mKE9TVkVSU0lPTklORk8pOwogIEdldFZlcnNpb25FeCgmb3N2aSk7CiAgaWYob3N2aS5kd01ham9yVmVyc2lvbiA+IG1ham9yKSByZXR1cm4gVFJVRTsKICBpZihvc3ZpLmR3TWFqb3JWZXJzaW9uIDwgbWFqb3IpIHJldHVybiBGQUxTRTsKICBpZihvc3ZpLmR3TWlub3JWZXJzaW9uID4gbWlub3IpIHJldHVybiBUUlVFOwogIGlmKG9zdmkuZHdNaW5vclZlcnNpb24gPCBtaW5vcikgcmV0dXJuIEZBTFNFOwogIGlmKHNwbWFqb3IgJiYgb3N2aS5kd1BsYXRmb3JtSWQgPT0gVkVSX1BMQVRGT1JNX1dJTjMyX05UKXsKICAgIEJPT0wgc3BDaGVjayA9IEZBTFNFOwogICAgSEtFWSBoa2V5OwogICAgaWYoUmVnT3BlbktleUV4KEhLRVlfTE9DQUxfTUFDSElORSwKICAgICAgIlNZU1RFTVxcQ3VycmVudENvbnRyb2xTZXRcXENvbnRyb2xcXFdpbmRvd3MiLAogICAgICAwLCBLRVlfUVVFUllfVkFMVUUsICZoa2V5KSA9PSBFUlJPUl9TVUNDRVNTKXsKICAgICAgRFdPUkQgQ1NEVmVyc2lvbiwgc3ogPSBzaXplb2YoRFdPUkQpOwogICAgICBpZihSZWdRdWVyeVZhbHVlRXgoaGtleSwgIkNTRFZlcnNpb24iLCBOVUxMLCBOVUxMLAogICAgICAgIChCWVRFICopJkNTRFZlcnNpb24sICZzeikgPT0gRVJST1JfU1VDQ0VTUykKICAgICAgICBzcENoZWNrID0gTE9XT1JEKENTRFZlcnNpb24pID49IHNwbWFqb3I7CiAgICAgIFJlZ0Nsb3NlS2V5KGhrZXkpOwogICAgfQogICAgcmV0dXJuIHNwQ2hlY2s7CiAgfQogIHJldHVybiBUUlVFOwp9CgppbnQgbWFpbihpbnQgYWMsIGNoYXIgKiphdikKewogIGlmKCF2ZXJzaW9uQ2hlY2soNCwgMCwgMykpIGZwcmludGYoc3RkZXJyLCAiZXJyb3IgMCIpOwogIGlmKCFpbml0R2x5cGgoZ2ZsZykpIGZwcmludGYoc3RkZXJyLCAiZXJyb3IgMSIpOwogIGlmKCEoZ2x5Zl9sZW4gPSBpbml0R2x5cGgoZ2x5ZikpKSBmcHJpbnRmKHN0ZGVyciwgImVycm9yIDIiKTsKICB7CiAgICBIV05EIGh3bmQgPSBHZXREZXNrdG9wV2luZG93KCk7CiAgICBIREMgaGRjID0gR2V0REMoaHduZCk7CiAgICBSRUNUIHJjOwogICAgR2V0Q2xpZW50UmVjdChod25kLCAmcmMpOwogICAgewogICAgICBpbnQgc3p4ID0gcmMucmlnaHQgLSByYy5sZWZ0LCBzenkgPSByYy5ib3R0b20gLSByYy50b3A7CiAgICAgIEhEQyBobWRjID0gQ3JlYXRlQ29tcGF0aWJsZURDKGhkYyk7CiAgICAgIEhCSVRNQVAgaGJtcCA9IENyZWF0ZUNvbXBhdGlibGVCaXRtYXAoaGRjLCBzengsIHN6eSk7CiAgICAgIEhCSVRNQVAgaG9ibXAgPSAoSEJJVE1BUClTZWxlY3RPYmplY3QoaG1kYywgaGJtcCk7CiAgICAgIEJpdEJsdChobWRjLCAwLCAwLCBzengsIHN6eSwgaGRjLCAwLCAwLCBTUkNDT1BZKTsgLy8gZm9yIEFlcm8KICAgICAgZHJhd1RyYW5zcGFyZW50KGhkYywgMCwgMCwgc3p4LCBzenksIGhtZGMsIHN6eCwgc3p5LAogICAgICAgIFJHQigyNTUsIDI1NSwgMCksIGRyYXdDYWxsYmFjayk7CiAgICAgIERlbGV0ZU9iamVjdChTZWxlY3RPYmplY3QoaG1kYywgaG9ibXApKTsKICAgICAgRGVsZXRlREMoaG1kYyk7CiAgICB9CiAgICBSZWxlYXNlREMoaHduZCwgaGRjKTsKICB9CiAgcmV0dXJuIDA7Cn0=