// 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;
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(BYTE **epoc, BYTE **flags, int **xcoords, int **ycoords,
int *numepoc, char ch)
{
int i, j, k, pos = 0, num = 0, code = 0, fpos = 0, epnum = 0, fnum = 0;
*epoc = *flags = NULL, *xcoords = *ycoords = 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(!(*epoc
= (BYTE
*)malloc(*numepoc
= epnum
))) break; for(i = 0; i < epnum; ++i) (*epoc)[i] = gflg[fpos + 1 + i];
if(!(*flags
= (BYTE
*)malloc(num
))) break; 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)
(*flags)[k++] = b & m ? 1 : 0;
}
break;
}
pos += (num + 1) * 4;
fpos += epnum + fnum + 1;
}
if(!*epoc || !*flags) return 0;
if(!(*xcoords
= (int *)malloc(num
* sizeof(int)))) return 0; if(!(*ycoords
= (int *)malloc(num
* sizeof(int)))) return 0; for(i = 0; i < num; ++i){
(*xcoords)[i] = (i ? (*xcoords)[i-1] : 0) + b2h(&glyf[pos + (i+1)*4]);
(*ycoords)[i] = (i ? (*ycoords)[i-1] : 0) + b2h(&glyf[pos + (i+1)*4 + 2]);
}
return num;
}
int drawGlyph(HDC hdc, int scale, int szx, int szy, int ox, int oy,
int *w, int *h, int ch)
{
BYTE *epoc, *flags;
int *xcoords, *ycoords, numepoc, i, j;
int numflags = getGlyphData(&epoc, &flags, &xcoords, &ycoords, &numepoc, ch);
*w = 80, *h = 160;
if(numflags){
for(j = 0; j < numepoc; ++j){
int pflg, px, py, k = j ? epoc[j - 1] + 1 : 0;
for(i = k; i <= epoc[j]; ++i){
int flg = flags[i], x = xcoords[i], y = ycoords[i];
if(SHOW_MARK){
int r = i == k ? 4 : 3;
COLORREF col = flg & 0x01 ? RGB(0, 0, 255) : RGB(255, 0, 0);
HPEN hpen = CreatePen(PS_SOLID, 1, col);
HPEN hopen = (HPEN)SelectObject(hdc, hpen);
HBRUSH hbrush, hobrush;
if(i == k) hbrush = CreateSolidBrush(RGB(0, 255, 0));
else hbrush = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
hobrush = (HBRUSH)SelectObject(hdc, hbrush);
Ellipse(hdc, ox - r + x / scale, szy - (oy - r + y / scale),
ox + r + x / scale, szy - (oy + r + y / scale));
SelectObject(hdc, hobrush);
if(i == k) DeleteObject(hbrush);
SelectObject(hdc, hopen);
DeleteObject(hpen);
}
if(i == k && !(flg & 0x01))
MessageBox(NULL, "off curve first", TITLE, MB_ICONEXCLAMATION|IDOK);
if(i != k){
int n = i == epoc[j] ? k : i + 1;
int nflg = flags[n], nx = xcoords[n], ny = ycoords[n];
if(curve(hdc, scale, szx, szy, ox, oy,
&pflg, &px, &py, flg, x, y, nflg, nx, ny)) continue;
}
pflg = flg, px = x, py = y;
}
curve(hdc, scale, szx, szy, ox, oy, &pflg, &px, &py,
flags[k], xcoords[k], ycoords[k],
flags[k + 1], xcoords[k + 1], ycoords[k + 1]);
}
}
if(xcoords
) free(xcoords
); if(ycoords
) free(ycoords
); return 0;
}
int bezier(HDC hdc, int scale, int szx, int szy, int ox, int oy,
int px, int py, int x, int y, int nx, int ny)
{
int t, m = ((nx - px) * (nx - px) + (ny - py) * (ny - py)) / 5000;
MoveToEx(hdc, ox + px / scale, szy - (oy + py / scale), 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(hdc, ox + tx / scale, szy - (oy + ty / scale));
}
LineTo(hdc, ox + nx / scale, szy - (oy + ny / scale));
return 0;
}
int curve(HDC hdc, int scale, int szx, int szy, int ox, int oy,
int *pflg, int *px, int *py, int flg, int x, int y, int nflg, int nx, int ny)
{
if(flg & 0x01){
if(!(*pflg & 0x01))
MessageBox(NULL, "off curve bug", TITLE, MB_ICONEXCLAMATION|IDOK);
stroke(hdc, scale, szx, szy, ox, oy, *px, *py, x, y);
return 0;
}
if(nflg & 0x01){
bezier(hdc, scale, szx, szy, ox, oy, *px, *py, x, y, nx, ny);
*pflg = nflg, *px = nx, *py = ny;
return !0;
}else{
int mx = (x + nx) / 2, my = (y + ny) / 2;
bezier(hdc, scale, szx, szy, ox, oy, *px, *py, x, y, mx, my);
*pflg = 1, *px = mx, *py = my;
return !0;
}
}
int stroke(HDC hdc, int scale, int szx, int szy, int ox, int oy,
int xs, int ys, int xe, int ye)
{
POINT p;
MoveToEx(hdc, ox + xs / scale, szy - (oy + ys / scale), &p);
LineTo(hdc, ox + xe / scale, szy - (oy + ye / scale));
return 0;
}
int drawStrokes(int scale, int ofx, int ofy, int spx, int spy, char *str)
{
int szx, szy, ox = ofx, oy = ofy;
char *p;
HWND hwnd = GetDesktopWindow();
HDC hdc = GetDC(hwnd);
HPEN hpen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
HPEN hopen = (HPEN)SelectObject(hdc, hpen);
RECT rc;
GetClientRect(hwnd, &rc);
szx = rc.right - rc.left, szy = rc.bottom - rc.top;
for(p = str; *p; ++p){
int w, h;
drawGlyph(hdc, scale, szx, szy, ox, oy, &w, &h, *p);
if(*p == '\n') ox = ofx, oy -= h + spy;
else ox += w + spx;
}
SelectObject(hdc, hopen);
DeleteObject(hpen);
ReleaseDC(hwnd, hdc);
return 0;
}
int main(int ac, char **av)
{
if(!initGlyph
(gflg
)) fprintf(stderr
, "error 1"); if(!(glyf_len
= initGlyph
(glyf
))) fprintf(stderr
, "error 2"); drawStrokes(10, 120, 480, 40, 40, "Hello,\nworld!");
return 0;
}
Ly8gY29weXJpZ2h0IOKXhmVuM1BHc2ZPWG8gaHR0cDovL3QuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmgubmV0L3Rlc3QvcmVhZC5jZ2kvdGVjaC8xMzYzMDQyNTAyLwoKI2luY2x1ZGUgPHdpbmRvd3MuaD4KI2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KCiNkZWZpbmUgU0hPV19NQVJLIDEKCmNoYXIgKlRJVExFID0gImdseWYiOwpCWVRFICpnZmxnID0gIkFRdi84QUlZSDhrNUpNa0JBL0FDQ3hlU1NTUUJBL0FCRFAvNEFSTEorU0FDRXlEa2tueVNBQUlEQi84PSI7CkJZVEUgKmdseWYgPSAiQUF3QVNBVTdBQUQvT2dBQUFBQUMyZjBaQUFBQUFQMG4vem9BQUFBQUJkRUF4Z0FBQUFEOXVBTG5BQUFBQUFKSSIKICAgICAgICAgICAgICJBTVlBQUFBZ0FHVUVZQUliL01rQUFBQUEvNWtBUHY5bkFEYi96d0EwLzlBQWovL1FBRllBQUFCeUFBQUE1d0JiIgogICAgICAgICAgICAgIkFERUFMQUFLQUFBQUFQOHovNkgvMlA4Ni84ci9rd0FBL3VvQUFQN0lBUzBBQUFFVkFBQUJFZ0VyQVVJQTlBQUEiCiAgICAgICAgICAgICAiQU9JQUFBRDEvdmdBQVA4Ti8wa0FLdi8vQUpUL2JRQ2kvMm9BQVA5cEFBRC9UZjlPLy9UL2ZBQUVBR3dCZHdBQSIKICAgICAgICAgICAgICIvMFFBQUFBQUJoUUF2QUFBQUJnQWJ3UnhBaTRBQVA3di91ait4UDhWQUFEL0V3QUEvdWtCUEFBQUFSRUFBQUVSIgogICAgICAgICAgICAgIkFSY0JQUUR0QUFBQTZ3QUFBUmordy84Ky91OEFBQURaLzFZQTAvOXBBQUQvWndBQS8xZi9MUUFBL3ljQUFQOHUiCiAgICAgICAgICAgICAiQUtyL0p3Q1lBQUFBbGdBQUFLc0Exd0FFQUN3Q1B3RWQvdWI5Y2Y5dUFBQUFyZ0tQQUEwQWR3WTJCRjMrM2Z1aiIKICAgICAgICAgICAgICIvMUlBQVA3aEExMys0L3lqLzFNQUFQN2FCRjBBeEFBQUFNMzhud0VYQTJFQW13QUFBUjc4bndEQ0EyRUFFd0J5IgogICAgICAgICAgICAgIkEzSURrUC8yQUFELzFnQUsvN0VBQ2YvS0FBRC9xUUFBLzE3L3MvKzEvOE1BQVB6bi8wUUFBQUFBQkYwQXZBQUEiCiAgICAgICAgICAgICAiQUFEL1d3QndBRm9BcXdCTEFGa0FBQUF4QUFBQUxQLzdBQ3ovK1FBaEFHUUVRd0FBLzBRQUFBQUFBSFgvci8rNiIKICAgICAgICAgICAgICIvMUQvc3YrWkFBRC9PQUFBL3hVQk5BQUFBUkVBQUFDT0FGRUEzZ0JGQUU0QVJBQk1BTFVBVUFCaEFBQUFXQUFBIgogICAgICAgICAgICAgIkFJai8yd0JMLzlrQUFBSGtBTHdBQVA5RSt2OEFBQUtCLzdRQUl2K0lBQnIvdVFBQS8ySUFBUDlRL3lRQUFQODIiCiAgICAgICAgICAgICAiQUFEL09RQ0kvekVBbGdBQUFGQUFBQUNrQUVjQUNBQWhBZ01GMGYvbSs4bi9WZ0FBLytRRU53RFcraS8vTkFBQSIKICAgICAgICAgICAgICJBQUFBMHdETUFBQT0iOwppbnQgZ2x5Zl9sZW4gPSAwOwoKaW50IGI2NGRlY29kZShCWVRFICpkc3QsIHNpemVfdCAqZHN0X3NpemUsIEJZVEUgKnNyYywgaW50IHNyY19zaXplKQp7CiAgc3RhdGljIEJZVEUgYjY0b1s4MF0gPSB7CiAgICA2MiwgIDAsIDYyLCAgMCwgNjMsIDUyLCA1MywgNTQsIDU1LCA1NiwgNTcsIDU4LCA1OSwgNjAsIDYxLCAgMCwKICAgICAwLCAgMCwgIDAsICAwLCAgMCwgIDAsICAwLCAgMSwgIDIsICAzLCAgNCwgIDUsICA2LCAgNywgIDgsICA5LAogICAgMTAsIDExLCAxMiwgMTMsIDE0LCAxNSwgMTYsIDE3LCAxOCwgMTksIDIwLCAyMSwgMjIsIDIzLCAyNCwgMjUsCiAgICAgMCwgIDAsICAwLCA2MiwgNjMsICAwLCAyNiwgMjcsIDI4LCAyOSwgMzAsIDMxLCAzMiwgMzMsIDM0LCAzNSwKICAgIDM2LCAzNywgMzgsIDM5LCA0MCwgNDEsIDQyLCA0MywgNDQsIDQ1LCA0NiwgNDcsIDQ4LCA0OSwgNTAsIDUxfTsKICBpbnQgaSwgd29yZHMgPSBzcmNfc2l6ZS80LCBvdmVyc2l6ZSA9ICpkc3Rfc2l6ZSsyLCBsYXN0aSA9IG92ZXJzaXplLzMtMTsKICBpZihzcmNfc2l6ZSAlIDQpIHJldHVybiAxOwogIGlmKCpkc3Rfc2l6ZSA8IHdvcmRzICogMykgcmV0dXJuIDI7CiAgZm9yKGkgPSAwOyBpIDw9IGxhc3RpOyBpKyspewogICAgaW50IGo7CiAgICBCWVRFIGNbNF07CiAgICBmb3IoaiA9IDA7IGogPCBzaXplb2YoYyk7IGorKykKICAgICAgY1tqXSA9IGI2NG9bKHNyY1tpICogc2l6ZW9mKGMpICsgal0gLSAnKycpICUgc2l6ZW9mKGI2NG8pXTsKICAgIGRzdFtpICogMyArIDBdID0gKChjWzBdIDw8IDIpICYgMHgwMGZjKSB8ICgoY1sxXSA+PiA0KSAmIDB4MDMpOwogICAgaWYoaSA8IGxhc3RpIHx8IG92ZXJzaXplICUgMykKICAgICAgZHN0W2kgKiAzICsgMV0gPSAoKGNbMV0gPDwgNCkgJiAweDAwZjApIHwgKChjWzJdID4+IDIpICYgMHgwZik7CiAgICBpZihpIDwgbGFzdGkgfHwgKG92ZXJzaXplICUgMykgPT0gMikKICAgICAgZHN0W2kgKiAzICsgMl0gPSAoKGNbMl0gPDwgNikgJiAweDAwYzApIHwgKGNbM10gJiAweDNmKTsKICB9CiAgaWYoc3JjW3NyY19zaXplIC0gMV0gPT0gJz0nKXsKICAgIC0tKCpkc3Rfc2l6ZSk7CiAgICBpZihzcmNbc3JjX3NpemUgLSAyXSA9PSAnPScpIC0tKCpkc3Rfc2l6ZSk7CiAgfQogIHJldHVybiAwOwp9CgppbnQgaW5pdEdseXBoKEJZVEUgKnN0cikKewogIGludCBsZW4gPSAoc3RybGVuKHN0cikgPj4gMikgKiAzOwogIGlmKGI2NGRlY29kZShzdHIsICZsZW4sIHN0ciwgc3RybGVuKHN0cikpKSByZXR1cm4gMDsKICByZXR1cm4gbGVuOwp9CgpzaG9ydCBiMmgoQllURSAqYikKewogIHJldHVybiAoc2hvcnQpKChiWzBdIDw8IDgpIHwgYlsxXSk7Cn0KCmludCBnZXRHbHlwaERhdGEoQllURSAqKmVwb2MsIEJZVEUgKipmbGFncywgaW50ICoqeGNvb3JkcywgaW50ICoqeWNvb3JkcywKICBpbnQgKm51bWVwb2MsIGNoYXIgY2gpCnsKICBpbnQgaSwgaiwgaywgcG9zID0gMCwgbnVtID0gMCwgY29kZSA9IDAsIGZwb3MgPSAwLCBlcG51bSA9IDAsIGZudW0gPSAwOwogICplcG9jID0gKmZsYWdzID0gTlVMTCwgKnhjb29yZHMgPSAqeWNvb3JkcyA9IE5VTEwsICpudW1lcG9jID0gMDsKICB3aGlsZShwb3MgPCBnbHlmX2xlbil7CiAgICBudW0gPSBiMmgoJmdseWZbcG9zXSksIGNvZGUgPSBiMmgoJmdseWZbcG9zICsgMl0pOwogICAgZXBudW0gPSBnZmxnW2Zwb3NdLCBmbnVtID0gKG51bSArIDcpIC8gODsKICAgIGlmKGNvZGUgPT0gY2gpewogICAgICBpZighKCplcG9jID0gKEJZVEUgKiltYWxsb2MoKm51bWVwb2MgPSBlcG51bSkpKSBicmVhazsKICAgICAgZm9yKGkgPSAwOyBpIDwgZXBudW07ICsraSkgKCplcG9jKVtpXSA9IGdmbGdbZnBvcyArIDEgKyBpXTsKICAgICAgaWYoISgqZmxhZ3MgPSAoQllURSAqKW1hbGxvYyhudW0pKSkgYnJlYWs7CiAgICAgIGZvcihpID0gMCwgayA9IDA7IGkgPCBmbnVtOyArK2kpewogICAgICAgIEJZVEUgYiA9IGdmbGdbZnBvcyArIDEgKyBlcG51bSArIGldOwogICAgICAgIEJZVEUgbSA9IDB4ODA7CiAgICAgICAgZm9yKGogPSAwOyBqIDwgOCAtIChpID09IGZudW0gLSAxID8gZm51bSAqIDggLSBudW0gOiAwKTsgKytqLCBtID4+PSAxKQogICAgICAgICAgKCpmbGFncylbaysrXSA9IGIgJiBtID8gMSA6IDA7CiAgICAgIH0KICAgICAgYnJlYWs7CiAgICB9CiAgICBwb3MgKz0gKG51bSArIDEpICogNDsKICAgIGZwb3MgKz0gZXBudW0gKyBmbnVtICsgMTsKICB9CiAgaWYoISplcG9jIHx8ICEqZmxhZ3MpIHJldHVybiAwOwogIGlmKCEoKnhjb29yZHMgPSAoaW50ICopbWFsbG9jKG51bSAqIHNpemVvZihpbnQpKSkpIHJldHVybiAwOwogIGlmKCEoKnljb29yZHMgPSAoaW50ICopbWFsbG9jKG51bSAqIHNpemVvZihpbnQpKSkpIHJldHVybiAwOwogIGZvcihpID0gMDsgaSA8IG51bTsgKytpKXsKICAgICgqeGNvb3JkcylbaV0gPSAoaSA/ICgqeGNvb3JkcylbaS0xXSA6IDApICsgYjJoKCZnbHlmW3BvcyArIChpKzEpKjRdKTsKICAgICgqeWNvb3JkcylbaV0gPSAoaSA/ICgqeWNvb3JkcylbaS0xXSA6IDApICsgYjJoKCZnbHlmW3BvcyArIChpKzEpKjQgKyAyXSk7CiAgfQogIHJldHVybiBudW07Cn0KCmludCBkcmF3R2x5cGgoSERDIGhkYywgaW50IHNjYWxlLCBpbnQgc3p4LCBpbnQgc3p5LCBpbnQgb3gsIGludCBveSwKICBpbnQgKncsIGludCAqaCwgaW50IGNoKQp7CiAgQllURSAqZXBvYywgKmZsYWdzOwogIGludCAqeGNvb3JkcywgKnljb29yZHMsIG51bWVwb2MsIGksIGo7CiAgaW50IG51bWZsYWdzID0gZ2V0R2x5cGhEYXRhKCZlcG9jLCAmZmxhZ3MsICZ4Y29vcmRzLCAmeWNvb3JkcywgJm51bWVwb2MsIGNoKTsKICAqdyA9IDgwLCAqaCA9IDE2MDsKICBpZihudW1mbGFncyl7CiAgICBmb3IoaiA9IDA7IGogPCBudW1lcG9jOyArK2opewogICAgICBpbnQgcGZsZywgcHgsIHB5LCBrID0gaiA/IGVwb2NbaiAtIDFdICsgMSA6IDA7CiAgICAgIGZvcihpID0gazsgaSA8PSBlcG9jW2pdOyArK2kpewogICAgICAgIGludCBmbGcgPSBmbGFnc1tpXSwgeCA9IHhjb29yZHNbaV0sIHkgPSB5Y29vcmRzW2ldOwogICAgICAgIGlmKFNIT1dfTUFSSyl7CiAgICAgICAgICBpbnQgciA9IGkgPT0gayA/IDQgOiAzOwogICAgICAgICAgQ09MT1JSRUYgY29sID0gZmxnICYgMHgwMSA/IFJHQigwLCAwLCAyNTUpIDogUkdCKDI1NSwgMCwgMCk7CiAgICAgICAgICBIUEVOIGhwZW4gPSBDcmVhdGVQZW4oUFNfU09MSUQsIDEsIGNvbCk7CiAgICAgICAgICBIUEVOIGhvcGVuID0gKEhQRU4pU2VsZWN0T2JqZWN0KGhkYywgaHBlbik7CiAgICAgICAgICBIQlJVU0ggaGJydXNoLCBob2JydXNoOwogICAgICAgICAgaWYoaSA9PSBrKSBoYnJ1c2ggPSBDcmVhdGVTb2xpZEJydXNoKFJHQigwLCAyNTUsIDApKTsKICAgICAgICAgIGVsc2UgaGJydXNoID0gKEhCUlVTSClHZXRTdG9ja09iamVjdChIT0xMT1dfQlJVU0gpOwogICAgICAgICAgaG9icnVzaCA9IChIQlJVU0gpU2VsZWN0T2JqZWN0KGhkYywgaGJydXNoKTsKICAgICAgICAgIEVsbGlwc2UoaGRjLCBveCAtIHIgKyB4IC8gc2NhbGUsIHN6eSAtIChveSAtIHIgKyB5IC8gc2NhbGUpLAogICAgICAgICAgICBveCArIHIgKyB4IC8gc2NhbGUsIHN6eSAtIChveSArIHIgKyB5IC8gc2NhbGUpKTsKICAgICAgICAgIFNlbGVjdE9iamVjdChoZGMsIGhvYnJ1c2gpOwogICAgICAgICAgaWYoaSA9PSBrKSBEZWxldGVPYmplY3QoaGJydXNoKTsKICAgICAgICAgIFNlbGVjdE9iamVjdChoZGMsIGhvcGVuKTsKICAgICAgICAgIERlbGV0ZU9iamVjdChocGVuKTsKICAgICAgICB9CiAgICAgICAgaWYoaSA9PSBrICYmICEoZmxnICYgMHgwMSkpCiAgICAgICAgICBNZXNzYWdlQm94KE5VTEwsICJvZmYgY3VydmUgZmlyc3QiLCBUSVRMRSwgTUJfSUNPTkVYQ0xBTUFUSU9OfElET0spOwogICAgICAgIGlmKGkgIT0gayl7CiAgICAgICAgICBpbnQgbiA9IGkgPT0gZXBvY1tqXSA/IGsgOiBpICsgMTsKICAgICAgICAgIGludCBuZmxnID0gZmxhZ3Nbbl0sIG54ID0geGNvb3Jkc1tuXSwgbnkgPSB5Y29vcmRzW25dOwogICAgICAgICAgaWYoY3VydmUoaGRjLCBzY2FsZSwgc3p4LCBzenksIG94LCBveSwKICAgICAgICAgICAgJnBmbGcsICZweCwgJnB5LCBmbGcsIHgsIHksIG5mbGcsIG54LCBueSkpIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgICBwZmxnID0gZmxnLCBweCA9IHgsIHB5ID0geTsKICAgICAgfQogICAgICBjdXJ2ZShoZGMsIHNjYWxlLCBzengsIHN6eSwgb3gsIG95LCAmcGZsZywgJnB4LCAmcHksCiAgICAgICAgZmxhZ3Nba10sIHhjb29yZHNba10sIHljb29yZHNba10sCiAgICAgICAgZmxhZ3NbayArIDFdLCB4Y29vcmRzW2sgKyAxXSwgeWNvb3Jkc1trICsgMV0pOwogICAgfQogIH0KICBpZihlcG9jKSBmcmVlKGVwb2MpOwogIGlmKGZsYWdzKSBmcmVlKGZsYWdzKTsKICBpZih4Y29vcmRzKSBmcmVlKHhjb29yZHMpOwogIGlmKHljb29yZHMpIGZyZWUoeWNvb3Jkcyk7CiAgcmV0dXJuIDA7Cn0KCmludCBiZXppZXIoSERDIGhkYywgaW50IHNjYWxlLCBpbnQgc3p4LCBpbnQgc3p5LCBpbnQgb3gsIGludCBveSwKICBpbnQgcHgsIGludCBweSwgaW50IHgsIGludCB5LCBpbnQgbngsIGludCBueSkKewogIGludCB0LCBtID0gKChueCAtIHB4KSAqIChueCAtIHB4KSArIChueSAtIHB5KSAqIChueSAtIHB5KSkgLyA1MDAwOwogIE1vdmVUb0V4KGhkYywgb3ggKyBweCAvIHNjYWxlLCBzenkgLSAob3kgKyBweSAvIHNjYWxlKSwgTlVMTCk7CiAgZm9yKHQgPSAxOyB0IDwgbTsgKyt0KXsKICAgIGZsb2F0IGYgPSB0IC8gKGZsb2F0KW07CiAgICBmbG9hdCBhW10gPSB7KDEgLSBmKSAqICgxIC0gZiksIDIgKiBmICogKDEgLSBmKSwgZiAqIGZ9OwogICAgaW50IHR4ID0gYVswXSAqIHB4ICsgYVsxXSAqIHggKyBhWzJdICogbng7CiAgICBpbnQgdHkgPSBhWzBdICogcHkgKyBhWzFdICogeSArIGFbMl0gKiBueTsKICAgIExpbmVUbyhoZGMsIG94ICsgdHggLyBzY2FsZSwgc3p5IC0gKG95ICsgdHkgLyBzY2FsZSkpOwogIH0KICBMaW5lVG8oaGRjLCBveCArIG54IC8gc2NhbGUsIHN6eSAtIChveSArIG55IC8gc2NhbGUpKTsKICByZXR1cm4gMDsKfQoKaW50IGN1cnZlKEhEQyBoZGMsIGludCBzY2FsZSwgaW50IHN6eCwgaW50IHN6eSwgaW50IG94LCBpbnQgb3ksCiAgaW50ICpwZmxnLCBpbnQgKnB4LCBpbnQgKnB5LCBpbnQgZmxnLCBpbnQgeCwgaW50IHksIGludCBuZmxnLCBpbnQgbngsIGludCBueSkKewogIGlmKGZsZyAmIDB4MDEpewogICAgaWYoISgqcGZsZyAmIDB4MDEpKQogICAgICBNZXNzYWdlQm94KE5VTEwsICJvZmYgY3VydmUgYnVnIiwgVElUTEUsIE1CX0lDT05FWENMQU1BVElPTnxJRE9LKTsKICAgIHN0cm9rZShoZGMsIHNjYWxlLCBzengsIHN6eSwgb3gsIG95LCAqcHgsICpweSwgeCwgeSk7CiAgICByZXR1cm4gMDsKICB9CiAgaWYobmZsZyAmIDB4MDEpewogICAgYmV6aWVyKGhkYywgc2NhbGUsIHN6eCwgc3p5LCBveCwgb3ksICpweCwgKnB5LCB4LCB5LCBueCwgbnkpOwogICAgKnBmbGcgPSBuZmxnLCAqcHggPSBueCwgKnB5ID0gbnk7CiAgICByZXR1cm4gITA7CiAgfWVsc2V7CiAgICBpbnQgbXggPSAoeCArIG54KSAvIDIsIG15ID0gKHkgKyBueSkgLyAyOwogICAgYmV6aWVyKGhkYywgc2NhbGUsIHN6eCwgc3p5LCBveCwgb3ksICpweCwgKnB5LCB4LCB5LCBteCwgbXkpOwogICAgKnBmbGcgPSAxLCAqcHggPSBteCwgKnB5ID0gbXk7CiAgICByZXR1cm4gITA7CiAgfQp9CgppbnQgc3Ryb2tlKEhEQyBoZGMsIGludCBzY2FsZSwgaW50IHN6eCwgaW50IHN6eSwgaW50IG94LCBpbnQgb3ksCiAgaW50IHhzLCBpbnQgeXMsIGludCB4ZSwgaW50IHllKQp7CiAgUE9JTlQgcDsKICBNb3ZlVG9FeChoZGMsIG94ICsgeHMgLyBzY2FsZSwgc3p5IC0gKG95ICsgeXMgLyBzY2FsZSksICZwKTsKICBMaW5lVG8oaGRjLCBveCArIHhlIC8gc2NhbGUsIHN6eSAtIChveSArIHllIC8gc2NhbGUpKTsKICByZXR1cm4gMDsKfQoKaW50IGRyYXdTdHJva2VzKGludCBzY2FsZSwgaW50IG9meCwgaW50IG9meSwgaW50IHNweCwgaW50IHNweSwgY2hhciAqc3RyKQp7CiAgaW50IHN6eCwgc3p5LCBveCA9IG9meCwgb3kgPSBvZnk7CiAgY2hhciAqcDsKICBIV05EIGh3bmQgPSBHZXREZXNrdG9wV2luZG93KCk7CiAgSERDIGhkYyA9IEdldERDKGh3bmQpOwogIEhQRU4gaHBlbiA9IENyZWF0ZVBlbihQU19TT0xJRCwgMSwgUkdCKDAsIDI1NSwgMCkpOwogIEhQRU4gaG9wZW4gPSAoSFBFTilTZWxlY3RPYmplY3QoaGRjLCBocGVuKTsKICBSRUNUIHJjOwogIEdldENsaWVudFJlY3QoaHduZCwgJnJjKTsKICBzenggPSByYy5yaWdodCAtIHJjLmxlZnQsIHN6eSA9IHJjLmJvdHRvbSAtIHJjLnRvcDsKICBmb3IocCA9IHN0cjsgKnA7ICsrcCl7CiAgICBpbnQgdywgaDsKICAgIGRyYXdHbHlwaChoZGMsIHNjYWxlLCBzengsIHN6eSwgb3gsIG95LCAmdywgJmgsICpwKTsKICAgIGlmKCpwID09ICdcbicpIG94ID0gb2Z4LCBveSAtPSBoICsgc3B5OwogICAgZWxzZSBveCArPSB3ICsgc3B4OwogIH0KICBTZWxlY3RPYmplY3QoaGRjLCBob3Blbik7CiAgRGVsZXRlT2JqZWN0KGhwZW4pOwogIFJlbGVhc2VEQyhod25kLCBoZGMpOwogIHJldHVybiAwOwp9CgppbnQgbWFpbihpbnQgYWMsIGNoYXIgKiphdikKewogIGlmKCFpbml0R2x5cGgoZ2ZsZykpIGZwcmludGYoc3RkZXJyLCAiZXJyb3IgMSIpOwogIGlmKCEoZ2x5Zl9sZW4gPSBpbml0R2x5cGgoZ2x5ZikpKSBmcHJpbnRmKHN0ZGVyciwgImVycm9yIDIiKTsKICBkcmF3U3Ryb2tlcygxMCwgMTIwLCA0ODAsIDQwLCA0MCwgIkhlbGxvLFxud29ybGQhIik7CiAgcmV0dXJuIDA7Cn0=