#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define FIXED_POINT_SCALE 256
#define CORDIC_NTAB 64
#define N_MAX 16
// === Function prototypes for printing helpers (updated) ===
void print_matrix(const char* title, float* mat, int n);
void print_matrix_double(const char* title, double* mat, int n);
void print_matrix_int64(const char* title, int64_t* mat, int n);
void print_zigzag_int64(const char* title, int64_t* arr, int n);
// === Quantization Matrix Selector ===
void select_quant_matrix(int n, int quant_matrix[N_MAX][N_MAX]) {
int i, j;
memset(quant_matrix
, 0, sizeof(int) * N_MAX
* N_MAX
);
if (n == 4) {
int tmp[4][4] = {
{16, 12, 34, 61},
{14, 20, 57, 58},
{22, 52, 95, 87},
{72, 96, 104, 99}
};
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
quant_matrix[i][j] = tmp[i][j];
} else if (n == 6) {
int tmp[6][6] = {
{16, 11, 15, 27, 46, 61},
{13, 13, 19, 35, 61, 55},
{14, 18, 26, 54, 79, 61},
{19, 30, 54, 77, 106, 80},
{37, 57, 75, 97, 116, 97},
{72, 93, 97, 109, 102, 99}
};
for (i = 0; i < 6; i++)
for (j = 0; j < 6; j++)
quant_matrix[i][j] = tmp[i][j];
} else if (n == 8) {
int tmp[8][8] = {
{16, 11, 10, 16, 24, 40, 51, 61},
{12, 12, 14, 19, 26, 58, 60, 55},
{14, 13, 16, 24, 40, 57, 69, 56},
{14, 17, 22, 29, 51, 87, 80, 62},
{18, 22, 37, 56, 68, 109, 103, 77},
{24, 35, 55, 64, 81, 104, 113, 92},
{49, 64, 78, 87, 103, 121, 120, 101},
{72, 92, 95, 98, 112, 100, 103, 99}
};
for (i = 0; i < 8; i++)
for (j = 0; j < 8; j++)
quant_matrix[i][j] = tmp[i][j];
} else if (n == 10) {
int tmp[10][10] = {
{16, 12, 10, 12, 17, 23, 34, 45, 53, 61},
{13, 12, 12, 15, 19, 25, 42, 55, 58, 56},
{13, 13, 14, 17, 23, 32, 48, 61, 63, 56},
{14, 14, 16, 20, 27, 41, 57, 69, 69, 58},
{14, 17, 21, 26, 33, 50, 75, 86, 78, 64},
{18, 20, 28, 40, 53, 64, 91, 104, 94, 75},
{22, 28, 39, 52, 63, 75, 95, 107, 104, 87},
{33, 43, 55, 67, 75, 88, 104, 113, 111, 96},
{53, 65, 76, 84, 91, 103, 112, 116, 112, 101},
{72, 87, 94, 96, 99, 110, 104, 101, 102, 99}
};
for (i = 0; i < 10; i++)
for (j = 0; j < 10; j++)
quant_matrix[i][j] = tmp[i][j];
} else if (n == 12) {
int tmp[12][12] = {
{16, 13, 11, 10, 13, 17, 22, 30, 41, 48, 54, 61},
{13, 12, 12, 12, 15, 19, 24, 35, 51, 55, 57, 57},
{13, 12, 13, 14, 17, 22, 27, 40, 58, 61, 60, 55},
{14, 13, 14, 16, 20, 26, 35, 46, 58, 65, 63, 56},
{14, 15, 16, 19, 23, 29, 41, 56, 72, 74, 69, 59},
{15, 17, 19, 24, 29, 36, 49, 68, 90, 86, 76, 64},
{17, 20, 24, 32, 42, 52, 62, 80, 104, 100, 89, 74},
{21, 25, 31, 42, 52, 62, 71, 87, 107, 107, 98, 83},
{26, 32, 42, 55, 62, 69, 79, 92, 106, 111, 106, 93},
{40, 49, 58, 69, 76, 83, 93, 105, 116, 118, 111, 98},
{56, 66, 76, 83, 88, 93, 103, 109, 113, 113, 109, 100},
{72, 84, 93, 95, 97, 100, 109, 106, 100, 102, 102, 99}
};
for (i = 0; i < 12; i++)
for (j = 0; j < 12; j++)
quant_matrix[i][j] = tmp[i][j];
} else if (n == 14) {
int tmp[14][14] = {
{16, 13, 11, 10, 11, 14, 18, 22, 28, 37, 44, 50, 55, 61},
{14, 12, 12, 12, 13, 16, 19, 23, 31, 44, 51, 55, 57, 58},
{12, 12, 12, 13, 15, 18, 21, 25, 34, 51, 59, 60, 58, 55},
{13, 13, 13, 14, 16, 20, 24, 31, 40, 53, 60, 65, 61, 56},
{14, 14, 14, 15, 18, 22, 28, 37, 47, 57, 64, 70, 64, 57},
{14, 15, 16, 18, 21, 25, 31, 42, 55, 71, 76, 76, 68, 60},
{15, 16, 18, 22, 26, 31, 38, 49, 64, 85, 89, 85, 75, 65},
{17, 19, 21, 28, 35, 43, 51, 60, 74, 96, 101, 98, 85, 73},
{20, 23, 26, 35, 44, 53, 61, 68, 81, 101, 107, 106, 94, 81},
{23, 28, 34, 43, 53, 59, 66, 75, 86, 100, 107, 111, 101, 90},
{32, 38, 45, 55, 64, 69, 76, 85, 95, 107, 112, 115, 106, 95},
{46, 54, 62, 70, 77, 82, 88, 97, 106, 117, 120, 119, 110, 100},
{59, 67, 76, 82, 86, 90, 95, 103, 108, 110, 111, 112, 106, 100},
{72, 82, 92, 94, 95, 97, 101, 109, 108, 102, 101, 103, 101, 99}
};
for (i = 0; i < 14; i++)
for (j = 0; j < 14; j++)
quant_matrix[i][j] = tmp[i][j];
} else if (n == 16) {
int tmp[16][16] = {
{16, 13, 11, 11, 10, 12, 15, 18, 22, 27, 34, 41, 46, 52, 56, 61},
{14, 13, 12, 12, 12, 13, 16, 19, 23, 28, 38, 49, 52, 55, 57, 58},
{12, 12, 12, 13, 13, 15, 18, 20, 24, 30, 44, 57, 58, 59, 57, 55},
{13, 13, 12, 13, 14, 17, 19, 23, 28, 35, 47, 58, 61, 63, 59, 55},
{14, 13, 13, 14, 15, 18, 22, 26, 33, 41, 50, 58, 63, 67, 61, 56},
{14, 14, 14, 16, 17, 20, 24, 29, 38, 47, 57, 67, 70, 71, 64, 58},
{14, 15, 16, 18, 20, 23, 26, 32, 42, 54, 68, 80, 79, 76, 68, 61},
{15, 16, 18, 21, 24, 28, 32, 39, 49, 61, 78, 91, 88, 84, 74, 66},
{17, 18, 20, 25, 30, 37, 44, 51, 58, 69, 87, 102, 99, 94, 83, 73},
{19, 21, 24, 30, 37, 45, 54, 61, 67, 77, 94, 108, 106, 103, 91, 80},
{22, 25, 29, 36, 45, 52, 58, 65, 72, 82, 95, 106, 108, 108, 97, 87},
{26, 31, 37, 45, 54, 60, 65, 71, 79, 88, 98, 107, 111, 112, 102, 93},
{37, 43, 49, 57, 65, 71, 75, 81, 89, 97, 107, 114, 116, 116, 106, 97},
{50, 57, 64, 71, 77, 82, 86, 92, 99, 107, 114, 119, 119, 117, 109, 101},
{60, 68, 76, 81, 85, 89, 91, 96, 103, 108, 109, 109, 110, 110, 105, 100},
{72, 81, 91, 93, 95, 96, 97, 102, 108, 109, 104, 100, 102, 103, 101, 99}
};
for (i = 0; i < 16; i++)
for (j = 0; j < 16; j++)
quant_matrix[i][j] = tmp[i][j];
}
}
int rotations(int bpp){
if(bpp>3 & bpp<9){
return 16;
}
else if(bpp>9 & bpp<17){
return 32;
}
else{
return 55;
}
}
static const __uint128_t atanh_fixed55[56] = {
0,
231808622658467921920, 136844620538003570688, 72304939235532316672, 36703116139066482688, 8422781014094860288,
9220371395095598080, 4611310773424436736, 2305796098435487488, 1152915640598518656, 576460019297349376,
288230284525795200, 144115176622611392, 72057592606272224, 36028796840007000, 18014398487112362,
9007199251944789, 4503599627020970, 2251799813641557, 1125899906837163, 562949953420629,
281474976710571, 140737488355317, 70368744177663, 35184372088832, 17592186044416,
8796093022208, 4398046511104, 2199023255552, 1099511627776, 549755813888,
274877906944, 137438953472, 68719476736, 34359738368, 17179869184,
8589934592, 4294967296, 2147483648, 1073741824, 536870912,
268435456, 134217728, 67108864, 33554432, 16777216,
8388608, 4194304, 2097152, 1048576, 524288,
262144, 131072, 65536, 32768, 16384
};
const uint64_t k = 11201839480116572000ULL;
//uint64_t K = k >> (63 - TP_WR_WIDTH - 12);
int clog2_n2(int n) {
int v = n*n, count = 0;
while (v > 1) { v >>= 1; ++count; }
return count + 1;
}
void print_matrix(const char* title, float* mat, int n) {
for (int i = 0; i < n; i++) {
for (int j
= 0; j
< n
; j
++) printf("%8.4f ", mat
[i
*n
+ j
]); }
}
void print_matrix_double(const char* title, double* mat, int n) {
printf("\n%s (double):\n", title
); for (int i = 0; i < n; i++) {
for (int j
= 0; j
< n
; j
++) printf("%12.4f ", mat
[i
*n
+ j
]); }
}
void print_matrix_int64(const char* title, int64_t* mat, int n) {
printf("\n%s (int64_t):\n", title
); for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
printf("%12lld ", (long long)mat
[i
*n
+ j
]); }
}
void print_zigzag_int64(const char* title, int64_t* arr, int n) {
int total = n * n;
printf("\n%s (length %d):\n", title
, total
); for (int i = 0; i < total; ++i) {
printf("[%3d]=%6lld ", i
, (long long)arr
[i
]); if ((i
+ 1) % 8 == 0) printf("\n"); }
if (total
% 8 != 0) printf("\n"); }
void cordic_rotation(uint64_t theta, int rot, int64_t* c, int64_t* s, int bpp,int tc_mode,int idct_mode) {
uint64_t atanh_fixed[56];
const uint64_t m_pi = 14488038916154245000LL;
int TP_WR_WIDTH = bpp/2+bpp+3+(1-tc_mode)*(1-idct_mode);
uint64_t K = k >> (64 - TP_WR_WIDTH - 12);
for (int i = 1; i <= 56; i++) {
atanh_fixed[i] = (uint64_t)(atanh_fixed55[i] >> (63 - TP_WR_WIDTH - 12));
}
while (theta < -m_pi)
theta += (m_pi << 1);
while (theta > m_pi)
theta -= (m_pi << 1);
int sign = 1;
if(theta < -(2*m_pi)){
theta += m_pi;
sign = -1;
}
else if(theta > (2*m_pi)){
theta -= m_pi;
sign = -1;
}
uint64_t x = K, y = 0, z = theta;
for (int i = 0; i < rot; ++i){
int64_t di = (z >= 0) ? 1 : -1;
int64_t x_new = x - di * (y >> i);
int64_t y_new = y + di * (x >> i);
int64_t z_new = z - di * atanh_fixed[i];
x = x_new;
y = y_new;
z = z_new;
}
*c = sign * x;
*s = sign * y;
}
void cordic_dct_1d(const uint64_t* in, uint64_t* out, int n, int rot, int bpp, int tc_mode, int idct_mode) {
static int64_t alpha[N_MAX];
const uint64_t m_pi = 14488038916154245000LL;
static int inited = 0;
if (!inited){
for (int k = 1; k < n; ++k)
inited = 1;
}
for (int k = 0; k < n; ++k) {
int64_t acc = 0;
for(int m = 0; m < n; ++m) {
int64_t angle = (m_pi * (2LL * m + 1LL) * k) / (2LL * n);
int64_t c, s;
cordic_rotation(angle, rot, &c, &s, bpp, tc_mode, idct_mode);
acc += in[m] * c;
}
out[k] = alpha[k] * acc;
}
}
// quantize from int64_t (signed) to int64_t (signed)
void quantize_fixed(int64_t* in, int64_t* out, int n,int rt_mode, int quant_matrix[N_MAX][N_MAX]) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
int q = quant_matrix[i][j];
if (q == 0) q = 1; // safety
if(rt_mode==0) {
double v = (double)in[i*n + j] / (double)q;
out[i*n + j] = (int64_t)llround(v);
}
else{
out[i*n+j] = in[i*n+j]/q;
}
}
}
void zigzag_traversal_int64(int64_t* mat, int64_t* out, int n) {
int i = 0, j = 0, index = 0, up = 1;
for (int k = 0; k < n * n; k++) {
out[index++] = mat[i*n + j];
if (up) {
if (j == n - 1) { i++; up = 0; }
else if (i == 0) { j++; up = 0; }
else { i--; j++; }
} else {
if (i == n - 1) { j++; up = 1; }
else if (j == 0) { i++; up = 1; }
else { i++; j--; }
}
}
}
static inline int64_t limit_bits_signed(int64_t x, int bits) {
int64_t min, max;
if (bits >= 63) return x;
min = -(1LL << (bits - 1));
max = (1LL << (bits - 1)) - 1;
if (x < min) x = min;
else if (x > max) x = max;
return x;
}
static inline int64_t inverse_limit_bits_signed(int64_t x, int bits)
{
if (bits >= 63) return x; // No limit needed
int64_t max = (1LL << bits) - 1; // Max unsigned value with N bits
if (x < 0)
return 0; // Negative → clamp to 0
if (x > max)
return max; // Overflow → clamp to max
return x; // Within range
}
// === MAIN FUNCTION ===
int main() {
int n = 8, bpp = 8;
printf("Set matrix size n (even, 4–16, default 8): "); int tmpn;
if (scanf("%d", &tmpn
) == 1 && tmpn
>= 4 && tmpn
<= 16 && tmpn
% 2 == 0) n = tmpn;
printf("Set bits per pixel bpp (4–32, default 8): "); int tmpb;
if (scanf("%d", &tmpb
) == 1 && tmpb
>= 4 && tmpb
<= 32) bpp = tmpb;
int tc_mode;
printf("enter the tc_mode (0=normal signed, 1=normal signed – currently same): "); scanf("%d", &tc_mode
); // kept for interface; not changing behavior
int idct_mode;
printf("enter the idct_mode (0=DCT, 1=IDCT): ");
int rt_mode;
printf("enter the rt_mode (0 :rounded up 1:truncate): ");
int addr_bits = clog2_n2(n);
printf("For n=%d, RAM address width: %d bits\n", n
, addr_bits
);
// Select quantization matrix
int quant_matrix[N_MAX][N_MAX], rot;
select_quant_matrix(n, quant_matrix);
rot = rotations(bpp);
// Effective input width (for range limit only)
// int input_bits = (idct_mode == 0) ? bpp : (n/2 + bpp);
// unsigned long long max_val = (input_bits >= 63) ? ((1ULL << 62) - 1ULL)
// : ((1ULL << (input_bits - 1)) - 1ULL);
// Buffers
int64_t dct_mem[N_MAX*N_MAX]; // generic float buffer (spatial or freq)
int64_t tp_mem[N_MAX*N_MAX]; // after row transform
int64_t tp_transposed[N_MAX*N_MAX]; // transposed intermediate
int64_t fixed[N_MAX*N_MAX]; // integer-rounded values
int64_t quantized[N_MAX*N_MAX]; // quantized coefficients
int64_t zigzag[N_MAX*N_MAX]; // zigzag order
int64_t zigzag_matrix[N_MAX*N_MAX]; // zigzag array reshaped as matrix
int64_t idct_matrix[N_MAX*N_MAX]; // de-zigzagged quantized
int64_t idct_mem[N_MAX*N_MAX]; // dequantized freq-domain (int64)
if (idct_mode == 0) {
int done=0;
// ==========================
// Forward 2D DCT + Quant + Zigzag
// ==========================
int input_bits = (idct_mode == 0) ? bpp : (n/2 + bpp);
unsigned long long max_val = (input_bits >= 64) ? ~0ULL : ((1ULL << input_bits) - 1ULL);
printf("Enter %d input values (decimal, 0–%llu):\n", n
* n
, max_val
); for (int addr = 0; addr < n * n; ++addr) {
unsigned long long uval;
if (scanf("%llu", &uval
) != 1 || uval
> max_val
) { fprintf(stderr
, "Input out of range (0–%llu)\n", max_val
); return 1;
}
// Interpret as unsigned or signed (two's complement) depending on tc_mode
if (tc_mode == 1) {
dct_mem[addr] = (~uval+1) & ((((uint64_t)1 << input_bits) - 1));;
printf("WR dct_mem[%d] = %.0f\n", addr
, dct_mem
[addr
]); done=1;
//int64_t sval = tc_to_signed(uval, input_bits);
// dct_mem[addr] = twos_complement_to_signed(uval, input_bits);
// printf("WR dct_mem[%d] = %lld (from 0x%llX, %d-bit two's complement)\n",
// addr, (long long)sval, uval, input_bits);
} else {
dct_mem[addr] = (int64_t)uval;
printf("WR dct_mem[%d] = %.0f\n", addr
, dct_mem
[addr
]); done=1;
}
}
// Step 1: Row-wise DCT
for (int i = 0; i < n; i++) {
int64_t in_row[N_MAX], out_row[N_MAX];
for (int j = 0; j < n; j++)
in_row[j] = dct_mem[i*n + j];
cordic_dct_1d(in_row, out_row, n, rot, bpp, tc_mode, idct_mode);
for (int j = 0; j < n; j++)
tp_mem[i*n + j] = (int64_t)out_row[j];
}
print_matrix_int64("1D DCT (Rows) Output", tp_mem, n);
// Step 2: Transpose after rounding
//float_to_int64(tp_mem, fixed, n, rt_mode);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
tp_transposed[i*n + j] = (int64_t)fixed[j*n + i];
//print_matrix_double("Transpose after 1D DCT (double)", tp_transposed, n);
// Step 3: Column-wise DCT on transposed
for (int i = 0; i < n; i++) {
int64_t in_col[N_MAX], out_col[N_MAX];
for (int j = 0; j < n; j++)
in_col[j] = tp_transposed[i*n + j];
cordic_dct_1d(in_col, out_col, n, rot, bpp, tc_mode, idct_mode);
for (int j = 0; j < n; j++)
dct_mem[i*n + j] = (int64_t)out_col[j];
}
print_matrix_int64("Final 2D DCT Result", dct_mem, n);
// Step 4: Quantization + Zigzag
//float_to_int64(dct_mem, fixed, n, rt_mode);
print_matrix_int64("DCT rounded to int64 (before quant)", fixed, n);
quantize_fixed(fixed, quantized, n,rt_mode, quant_matrix);
int dct_bits=(n/2+bpp);
for (int i = 0; i < n*n; ++i)
quantized[i] = limit_bits_signed(quantized[i], dct_bits);
print_matrix_int64("Quantized Matrix (int64)", quantized, n);
zigzag_traversal_int64(quantized, zigzag, n);
print_zigzag_int64("Zig-Zag Output Array", zigzag, n);
// Also reshape zigzag as n x n matrix (for easier visual)
for (int idx = 0; idx < n*n; idx++)
zigzag_matrix[idx] = zigzag[idx];
print_matrix_int64("Zig-Zag Output (as n x n matrix)", zigzag_matrix, n);
} return 0;
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRpbnQuaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8bWF0aC5oPgojaW5jbHVkZSA8c3RyaW5nLmg+CgojZGVmaW5lIEZJWEVEX1BPSU5UX1NDQUxFIDI1NgojZGVmaW5lIENPUkRJQ19OVEFCIDY0CiNkZWZpbmUgTl9NQVggMTYKCi8vID09PSBGdW5jdGlvbiBwcm90b3R5cGVzIGZvciBwcmludGluZyBoZWxwZXJzICh1cGRhdGVkKSA9PT0Kdm9pZCBwcmludF9tYXRyaXgoY29uc3QgY2hhciogdGl0bGUsIGZsb2F0KiBtYXQsIGludCBuKTsKdm9pZCBwcmludF9tYXRyaXhfZG91YmxlKGNvbnN0IGNoYXIqIHRpdGxlLCBkb3VibGUqIG1hdCwgaW50IG4pOwp2b2lkIHByaW50X21hdHJpeF9pbnQ2NChjb25zdCBjaGFyKiB0aXRsZSwgaW50NjRfdCogbWF0LCBpbnQgbik7CnZvaWQgcHJpbnRfemlnemFnX2ludDY0KGNvbnN0IGNoYXIqIHRpdGxlLCBpbnQ2NF90KiBhcnIsIGludCBuKTsKCi8vID09PSBRdWFudGl6YXRpb24gTWF0cml4IFNlbGVjdG9yID09PQp2b2lkIHNlbGVjdF9xdWFudF9tYXRyaXgoaW50IG4sIGludCBxdWFudF9tYXRyaXhbTl9NQVhdW05fTUFYXSkgewogICAgaW50IGksIGo7CgogICAgbWVtc2V0KHF1YW50X21hdHJpeCwgMCwgc2l6ZW9mKGludCkgKiBOX01BWCAqIE5fTUFYKTsKCiAgICBpZiAobiA9PSA0KSB7CiAgICAgICAgaW50IHRtcFs0XVs0XSA9IHsKICAgICAgICAgICAgezE2LCAxMiwgMzQsIDYxfSwKICAgICAgICAgICAgezE0LCAyMCwgNTcsIDU4fSwKICAgICAgICAgICAgezIyLCA1MiwgOTUsIDg3fSwKICAgICAgICAgICAgezcyLCA5NiwgMTA0LCA5OX0KICAgICAgICB9OwogICAgICAgIGZvciAoaSA9IDA7IGkgPCA0OyBpKyspCiAgICAgICAgICAgIGZvciAoaiA9IDA7IGogPCA0OyBqKyspCiAgICAgICAgICAgICAgICBxdWFudF9tYXRyaXhbaV1bal0gPSB0bXBbaV1bal07CiAgICB9IGVsc2UgaWYgKG4gPT0gNikgewogICAgICAgIGludCB0bXBbNl1bNl0gPSB7CiAgICAgICAgICAgICAgICB7MTYsIDExLCAxNSwgMjcsIDQ2LCA2MX0sCiAgICAgICAgICAgICAgICB7MTMsIDEzLCAxOSwgMzUsIDYxLCA1NX0sCiAgICAgICAgICAgICAgICB7MTQsIDE4LCAyNiwgNTQsIDc5LCA2MX0sCiAgICAgICAgICAgICAgICB7MTksIDMwLCA1NCwgNzcsIDEwNiwgODB9LAogICAgICAgICAgICAgICAgezM3LCA1NywgNzUsIDk3LCAxMTYsIDk3fSwKICAgICAgICAgICAgICAgIHs3MiwgOTMsIDk3LCAxMDksIDEwMiwgOTl9CiAgICAgICAgICAgIH07CiAgICAgICAgZm9yIChpID0gMDsgaSA8IDY7IGkrKykKICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IDY7IGorKykKICAgICAgICAgICAgICAgIHF1YW50X21hdHJpeFtpXVtqXSA9IHRtcFtpXVtqXTsKICAgIH0gZWxzZSBpZiAobiA9PSA4KSB7CiAgICAgICAgaW50IHRtcFs4XVs4XSA9IHsKICAgICAgICAgICAgezE2LCAxMSwgMTAsIDE2LCAyNCwgNDAsIDUxLCA2MX0sCiAgICAgICAgICAgIHsxMiwgMTIsIDE0LCAxOSwgMjYsIDU4LCA2MCwgNTV9LAogICAgICAgICAgICB7MTQsIDEzLCAxNiwgMjQsIDQwLCA1NywgNjksIDU2fSwKICAgICAgICAgICAgezE0LCAxNywgMjIsIDI5LCA1MSwgODcsIDgwLCA2Mn0sCiAgICAgICAgICAgIHsxOCwgMjIsIDM3LCA1NiwgNjgsIDEwOSwgMTAzLCA3N30sCiAgICAgICAgICAgIHsyNCwgMzUsIDU1LCA2NCwgODEsIDEwNCwgMTEzLCA5Mn0sCiAgICAgICAgICAgIHs0OSwgNjQsIDc4LCA4NywgMTAzLCAxMjEsIDEyMCwgMTAxfSwKICAgICAgICAgICAgezcyLCA5MiwgOTUsIDk4LCAxMTIsIDEwMCwgMTAzLCA5OX0KICAgICAgICB9OwogICAgICAgIGZvciAoaSA9IDA7IGkgPCA4OyBpKyspCiAgICAgICAgICAgIGZvciAoaiA9IDA7IGogPCA4OyBqKyspCiAgICAgICAgICAgICAgICBxdWFudF9tYXRyaXhbaV1bal0gPSB0bXBbaV1bal07CiAgICB9IGVsc2UgaWYgKG4gPT0gMTApIHsKICAgICAgICBpbnQgdG1wWzEwXVsxMF0gPSB7CiAgICAgICAgICAgIHsxNiwgMTIsIDEwLCAxMiwgMTcsIDIzLCAzNCwgNDUsIDUzLCA2MX0sCiAgICAgICAgICAgIHsxMywgMTIsIDEyLCAxNSwgMTksIDI1LCA0MiwgNTUsIDU4LCA1Nn0sCiAgICAgICAgICAgIHsxMywgMTMsIDE0LCAxNywgMjMsIDMyLCA0OCwgNjEsIDYzLCA1Nn0sCiAgICAgICAgICAgIHsxNCwgMTQsIDE2LCAyMCwgMjcsIDQxLCA1NywgNjksIDY5LCA1OH0sCiAgICAgICAgICAgIHsxNCwgMTcsIDIxLCAyNiwgMzMsIDUwLCA3NSwgODYsIDc4LCA2NH0sCiAgICAgICAgICAgIHsxOCwgMjAsIDI4LCA0MCwgNTMsIDY0LCA5MSwgMTA0LCA5NCwgNzV9LAogICAgICAgICAgICB7MjIsIDI4LCAzOSwgNTIsIDYzLCA3NSwgOTUsIDEwNywgMTA0LCA4N30sCiAgICAgICAgICAgIHszMywgNDMsIDU1LCA2NywgNzUsIDg4LCAxMDQsIDExMywgMTExLCA5Nn0sCiAgICAgICAgICAgIHs1MywgNjUsIDc2LCA4NCwgOTEsIDEwMywgMTEyLCAxMTYsIDExMiwgMTAxfSwKICAgICAgICAgICAgezcyLCA4NywgOTQsIDk2LCA5OSwgMTEwLCAxMDQsIDEwMSwgMTAyLCA5OX0KICAgICAgICB9OwogICAgICAgIGZvciAoaSA9IDA7IGkgPCAxMDsgaSsrKQogICAgICAgICAgICBmb3IgKGogPSAwOyBqIDwgMTA7IGorKykKICAgICAgICAgICAgICAgIHF1YW50X21hdHJpeFtpXVtqXSA9IHRtcFtpXVtqXTsKICAgIH0gZWxzZSBpZiAobiA9PSAxMikgewogICAgICAgIGludCB0bXBbMTJdWzEyXSA9IHsKICAgICAgICAgICAgezE2LCAxMywgMTEsIDEwLCAxMywgMTcsIDIyLCAzMCwgNDEsIDQ4LCA1NCwgNjF9LAogICAgICAgICAgICB7MTMsIDEyLCAxMiwgMTIsIDE1LCAxOSwgMjQsIDM1LCA1MSwgNTUsIDU3LCA1N30sCiAgICAgICAgICAgIHsxMywgMTIsIDEzLCAxNCwgMTcsIDIyLCAyNywgNDAsIDU4LCA2MSwgNjAsIDU1fSwKICAgICAgICAgICAgezE0LCAxMywgMTQsIDE2LCAyMCwgMjYsIDM1LCA0NiwgNTgsIDY1LCA2MywgNTZ9LAogICAgICAgICAgICB7MTQsIDE1LCAxNiwgMTksIDIzLCAyOSwgNDEsIDU2LCA3MiwgNzQsIDY5LCA1OX0sCiAgICAgICAgICAgIHsxNSwgMTcsIDE5LCAyNCwgMjksIDM2LCA0OSwgNjgsIDkwLCA4NiwgNzYsIDY0fSwKICAgICAgICAgICAgezE3LCAyMCwgMjQsIDMyLCA0MiwgNTIsIDYyLCA4MCwgMTA0LCAxMDAsIDg5LCA3NH0sCiAgICAgICAgICAgIHsyMSwgMjUsIDMxLCA0MiwgNTIsIDYyLCA3MSwgODcsIDEwNywgMTA3LCA5OCwgODN9LAogICAgICAgICAgICB7MjYsIDMyLCA0MiwgNTUsIDYyLCA2OSwgNzksIDkyLCAxMDYsIDExMSwgMTA2LCA5M30sCiAgICAgICAgICAgIHs0MCwgNDksIDU4LCA2OSwgNzYsIDgzLCA5MywgMTA1LCAxMTYsIDExOCwgMTExLCA5OH0sCiAgICAgICAgICAgIHs1NiwgNjYsIDc2LCA4MywgODgsIDkzLCAxMDMsIDEwOSwgMTEzLCAxMTMsIDEwOSwgMTAwfSwKICAgICAgICAgICAgezcyLCA4NCwgOTMsIDk1LCA5NywgMTAwLCAxMDksIDEwNiwgMTAwLCAxMDIsIDEwMiwgOTl9CiAgICAgICAgfTsKICAgICAgICBmb3IgKGkgPSAwOyBpIDwgMTI7IGkrKykKICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IDEyOyBqKyspCiAgICAgICAgICAgICAgICBxdWFudF9tYXRyaXhbaV1bal0gPSB0bXBbaV1bal07CiAgICB9IGVsc2UgaWYgKG4gPT0gMTQpIHsKICAgICAgICBpbnQgdG1wWzE0XVsxNF0gPSB7CiAgICAgICAgICAgIHsxNiwgMTMsIDExLCAxMCwgMTEsIDE0LCAxOCwgMjIsIDI4LCAzNywgNDQsIDUwLCA1NSwgNjF9LAogICAgICAgICAgICB7MTQsIDEyLCAxMiwgMTIsIDEzLCAxNiwgMTksIDIzLCAzMSwgNDQsIDUxLCA1NSwgNTcsIDU4fSwKICAgICAgICAgICAgezEyLCAxMiwgMTIsIDEzLCAxNSwgMTgsIDIxLCAyNSwgMzQsIDUxLCA1OSwgNjAsIDU4LCA1NX0sCiAgICAgICAgICAgIHsxMywgMTMsIDEzLCAxNCwgMTYsIDIwLCAyNCwgMzEsIDQwLCA1MywgNjAsIDY1LCA2MSwgNTZ9LAogICAgICAgICAgICB7MTQsIDE0LCAxNCwgMTUsIDE4LCAyMiwgMjgsIDM3LCA0NywgNTcsIDY0LCA3MCwgNjQsIDU3fSwKICAgICAgICAgICAgezE0LCAxNSwgMTYsIDE4LCAyMSwgMjUsIDMxLCA0MiwgNTUsIDcxLCA3NiwgNzYsIDY4LCA2MH0sCiAgICAgICAgICAgIHsxNSwgMTYsIDE4LCAyMiwgMjYsIDMxLCAzOCwgNDksIDY0LCA4NSwgODksIDg1LCA3NSwgNjV9LAogICAgICAgICAgICB7MTcsIDE5LCAyMSwgMjgsIDM1LCA0MywgNTEsIDYwLCA3NCwgOTYsIDEwMSwgOTgsIDg1LCA3M30sCiAgICAgICAgICAgIHsyMCwgMjMsIDI2LCAzNSwgNDQsIDUzLCA2MSwgNjgsIDgxLCAxMDEsIDEwNywgMTA2LCA5NCwgODF9LAogICAgICAgICAgICB7MjMsIDI4LCAzNCwgNDMsIDUzLCA1OSwgNjYsIDc1LCA4NiwgMTAwLCAxMDcsIDExMSwgMTAxLCA5MH0sCiAgICAgICAgICAgIHszMiwgMzgsIDQ1LCA1NSwgNjQsIDY5LCA3NiwgODUsIDk1LCAxMDcsIDExMiwgMTE1LCAxMDYsIDk1fSwKICAgICAgICAgICAgezQ2LCA1NCwgNjIsIDcwLCA3NywgODIsIDg4LCA5NywgMTA2LCAxMTcsIDEyMCwgMTE5LCAxMTAsIDEwMH0sCiAgICAgICAgICAgIHs1OSwgNjcsIDc2LCA4MiwgODYsIDkwLCA5NSwgMTAzLCAxMDgsIDExMCwgMTExLCAxMTIsIDEwNiwgMTAwfSwKICAgICAgICAgICAgezcyLCA4MiwgOTIsIDk0LCA5NSwgOTcsIDEwMSwgMTA5LCAxMDgsIDEwMiwgMTAxLCAxMDMsIDEwMSwgOTl9CiAgICAgICAgfTsKICAgICAgICBmb3IgKGkgPSAwOyBpIDwgMTQ7IGkrKykKICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IDE0OyBqKyspCiAgICAgICAgICAgICAgICBxdWFudF9tYXRyaXhbaV1bal0gPSB0bXBbaV1bal07CiAgICB9IGVsc2UgaWYgKG4gPT0gMTYpIHsKICAgICAgICBpbnQgdG1wWzE2XVsxNl0gPSB7CiAgICAgICAgICAgIHsxNiwgMTMsIDExLCAxMSwgMTAsIDEyLCAxNSwgMTgsIDIyLCAyNywgMzQsIDQxLCA0NiwgNTIsIDU2LCA2MX0sCiAgICAgICAgICAgIHsxNCwgMTMsIDEyLCAxMiwgMTIsIDEzLCAxNiwgMTksIDIzLCAyOCwgMzgsIDQ5LCA1MiwgNTUsIDU3LCA1OH0sCiAgICAgICAgICAgIHsxMiwgMTIsIDEyLCAxMywgMTMsIDE1LCAxOCwgMjAsIDI0LCAzMCwgNDQsIDU3LCA1OCwgNTksIDU3LCA1NX0sCiAgICAgICAgICAgIHsxMywgMTMsIDEyLCAxMywgMTQsIDE3LCAxOSwgMjMsIDI4LCAzNSwgNDcsIDU4LCA2MSwgNjMsIDU5LCA1NX0sCiAgICAgICAgICAgIHsxNCwgMTMsIDEzLCAxNCwgMTUsIDE4LCAyMiwgMjYsIDMzLCA0MSwgNTAsIDU4LCA2MywgNjcsIDYxLCA1Nn0sCiAgICAgICAgICAgIHsxNCwgMTQsIDE0LCAxNiwgMTcsIDIwLCAyNCwgMjksIDM4LCA0NywgNTcsIDY3LCA3MCwgNzEsIDY0LCA1OH0sCiAgICAgICAgICAgIHsxNCwgMTUsIDE2LCAxOCwgMjAsIDIzLCAyNiwgMzIsIDQyLCA1NCwgNjgsIDgwLCA3OSwgNzYsIDY4LCA2MX0sCiAgICAgICAgICAgIHsxNSwgMTYsIDE4LCAyMSwgMjQsIDI4LCAzMiwgMzksIDQ5LCA2MSwgNzgsIDkxLCA4OCwgODQsIDc0LCA2Nn0sCiAgICAgICAgICAgIHsxNywgMTgsIDIwLCAyNSwgMzAsIDM3LCA0NCwgNTEsIDU4LCA2OSwgODcsIDEwMiwgOTksIDk0LCA4MywgNzN9LAogICAgICAgICAgICB7MTksIDIxLCAyNCwgMzAsIDM3LCA0NSwgNTQsIDYxLCA2NywgNzcsIDk0LCAxMDgsIDEwNiwgMTAzLCA5MSwgODB9LAogICAgICAgICAgICB7MjIsIDI1LCAyOSwgMzYsIDQ1LCA1MiwgNTgsIDY1LCA3MiwgODIsIDk1LCAxMDYsIDEwOCwgMTA4LCA5NywgODd9LAogICAgICAgICAgICB7MjYsIDMxLCAzNywgNDUsIDU0LCA2MCwgNjUsIDcxLCA3OSwgODgsIDk4LCAxMDcsIDExMSwgMTEyLCAxMDIsIDkzfSwKICAgICAgICAgICAgezM3LCA0MywgNDksIDU3LCA2NSwgNzEsIDc1LCA4MSwgODksIDk3LCAxMDcsIDExNCwgMTE2LCAxMTYsIDEwNiwgOTd9LAogICAgICAgICAgICB7NTAsIDU3LCA2NCwgNzEsIDc3LCA4MiwgODYsIDkyLCA5OSwgMTA3LCAxMTQsIDExOSwgMTE5LCAxMTcsIDEwOSwgMTAxfSwKICAgICAgICAgICAgezYwLCA2OCwgNzYsIDgxLCA4NSwgODksIDkxLCA5NiwgMTAzLCAxMDgsIDEwOSwgMTA5LCAxMTAsIDExMCwgMTA1LCAxMDB9LAogICAgICAgICAgICB7NzIsIDgxLCA5MSwgOTMsIDk1LCA5NiwgOTcsIDEwMiwgMTA4LCAxMDksIDEwNCwgMTAwLCAxMDIsIDEwMywgMTAxLCA5OX0KICAgICAgICB9OwogICAgICAgIGZvciAoaSA9IDA7IGkgPCAxNjsgaSsrKQogICAgICAgICAgICBmb3IgKGogPSAwOyBqIDwgMTY7IGorKykKICAgICAgICAgICAgICAgIHF1YW50X21hdHJpeFtpXVtqXSA9IHRtcFtpXVtqXTsKICAgIH0KfQoKaW50IHJvdGF0aW9ucyhpbnQgYnBwKXsKCWlmKGJwcD4zICYgYnBwPDkpewoJCXJldHVybiAxNjsKCX0KCWVsc2UgaWYoYnBwPjkgJiBicHA8MTcpewoJCXJldHVybiAzMjsKCX0KCWVsc2V7CgkJcmV0dXJuIDU1OwoJfQp9CgpzdGF0aWMgY29uc3QgX191aW50MTI4X3QgYXRhbmhfZml4ZWQ1NVs1Nl0gPSB7CjAsIAoyMzE4MDg2MjI2NTg0Njc5MjE5MjAsIDEzNjg0NDYyMDUzODAwMzU3MDY4OCwgNzIzMDQ5MzkyMzU1MzIzMTY2NzIsIDM2NzAzMTE2MTM5MDY2NDgyNjg4LCA4NDIyNzgxMDE0MDk0ODYwMjg4LCAKOTIyMDM3MTM5NTA5NTU5ODA4MCwgNDYxMTMxMDc3MzQyNDQzNjczNiwgMjMwNTc5NjA5ODQzNTQ4NzQ4OCwgMTE1MjkxNTY0MDU5ODUxODY1NiwgNTc2NDYwMDE5Mjk3MzQ5Mzc2LCAKMjg4MjMwMjg0NTI1Nzk1MjAwLCAxNDQxMTUxNzY2MjI2MTEzOTIsIDcyMDU3NTkyNjA2MjcyMjI0LCAzNjAyODc5Njg0MDAwNzAwMCwgMTgwMTQzOTg0ODcxMTIzNjIsIAo5MDA3MTk5MjUxOTQ0Nzg5LCA0NTAzNTk5NjI3MDIwOTcwLCAyMjUxNzk5ODEzNjQxNTU3LCAxMTI1ODk5OTA2ODM3MTYzLCA1NjI5NDk5NTM0MjA2MjksIAoyODE0NzQ5NzY3MTA1NzEsIDE0MDczNzQ4ODM1NTMxNywgNzAzNjg3NDQxNzc2NjMsIDM1MTg0MzcyMDg4ODMyLCAxNzU5MjE4NjA0NDQxNiwgCjg3OTYwOTMwMjIyMDgsIDQzOTgwNDY1MTExMDQsIDIxOTkwMjMyNTU1NTIsIDEwOTk1MTE2Mjc3NzYsIDU0OTc1NTgxMzg4OCwgCjI3NDg3NzkwNjk0NCwgMTM3NDM4OTUzNDcyLCA2ODcxOTQ3NjczNiwgMzQzNTk3MzgzNjgsIDE3MTc5ODY5MTg0LCAKODU4OTkzNDU5MiwgNDI5NDk2NzI5NiwgMjE0NzQ4MzY0OCwgMTA3Mzc0MTgyNCwgNTM2ODcwOTEyLCAKMjY4NDM1NDU2LCAxMzQyMTc3MjgsIDY3MTA4ODY0LCAzMzU1NDQzMiwgMTY3NzcyMTYsIAo4Mzg4NjA4LCA0MTk0MzA0LCAyMDk3MTUyLCAxMDQ4NTc2LCA1MjQyODgsIAoyNjIxNDQsIDEzMTA3MiwgNjU1MzYsIDMyNzY4LCAxNjM4NAp9OwoKY29uc3QgdWludDY0X3QgayA9IDExMjAxODM5NDgwMTE2NTcyMDAwVUxMOwoKLy91aW50NjRfdCBLID0gayA+PiAoNjMgLSBUUF9XUl9XSURUSCAtIDEyKTsKCmludCBjbG9nMl9uMihpbnQgbikgewogICAgaW50IHYgPSBuKm4sIGNvdW50ID0gMDsKICAgIHdoaWxlICh2ID4gMSkgeyB2ID4+PSAxOyArK2NvdW50OyB9CiAgICByZXR1cm4gY291bnQgKyAxOwp9Cgp2b2lkIHByaW50X21hdHJpeChjb25zdCBjaGFyKiB0aXRsZSwgZmxvYXQqIG1hdCwgaW50IG4pIHsKICAgIHByaW50ZigiXG4lczpcbiIsIHRpdGxlKTsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbjsgaSsrKSB7CiAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBuOyBqKyspIHByaW50ZigiJTguNGYgIiwgbWF0W2kqbiArIGpdKTsKICAgICAgICBwcmludGYoIlxuIik7CiAgICB9Cn0KCnZvaWQgcHJpbnRfbWF0cml4X2RvdWJsZShjb25zdCBjaGFyKiB0aXRsZSwgZG91YmxlKiBtYXQsIGludCBuKSB7CiAgICBwcmludGYoIlxuJXMgKGRvdWJsZSk6XG4iLCB0aXRsZSk7CiAgICBmb3IgKGludCBpID0gMDsgaSA8IG47IGkrKykgewogICAgICAgIGZvciAoaW50IGogPSAwOyBqIDwgbjsgaisrKSBwcmludGYoIiUxMi40ZiAiLCBtYXRbaSpuICsgal0pOwogICAgICAgIHByaW50ZigiXG4iKTsKICAgIH0KfQoKdm9pZCBwcmludF9tYXRyaXhfaW50NjQoY29uc3QgY2hhciogdGl0bGUsIGludDY0X3QqIG1hdCwgaW50IG4pIHsKICAgIHByaW50ZigiXG4lcyAoaW50NjRfdCk6XG4iLCB0aXRsZSk7CiAgICBmb3IgKGludCBpID0gMDsgaSA8IG47IGkrKykgewogICAgICAgIGZvciAoaW50IGogPSAwOyBqIDwgbjsgaisrKQogICAgICAgICAgICBwcmludGYoIiUxMmxsZCAiLCAobG9uZyBsb25nKW1hdFtpKm4gKyBqXSk7CiAgICAgICAgcHJpbnRmKCJcbiIpOwogICAgfQp9Cgp2b2lkIHByaW50X3ppZ3phZ19pbnQ2NChjb25zdCBjaGFyKiB0aXRsZSwgaW50NjRfdCogYXJyLCBpbnQgbikgewogICAgaW50IHRvdGFsID0gbiAqIG47CiAgICBwcmludGYoIlxuJXMgKGxlbmd0aCAlZCk6XG4iLCB0aXRsZSwgdG90YWwpOwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCB0b3RhbDsgKytpKSB7CiAgICAgICAgcHJpbnRmKCJbJTNkXT0lNmxsZCAgIiwgaSwgKGxvbmcgbG9uZylhcnJbaV0pOwogICAgICAgIGlmICgoaSArIDEpICUgOCA9PSAwKSBwcmludGYoIlxuIik7CiAgICB9CiAgICBpZiAodG90YWwgJSA4ICE9IDApIHByaW50ZigiXG4iKTsKfQoKdm9pZCBjb3JkaWNfcm90YXRpb24odWludDY0X3QgdGhldGEsIGludCByb3QsIGludDY0X3QqIGMsIGludDY0X3QqIHMsIGludCBicHAsaW50IHRjX21vZGUsaW50IGlkY3RfbW9kZSkgewogICAgdWludDY0X3QgYXRhbmhfZml4ZWRbNTZdOwogICAgY29uc3QgdWludDY0X3QgbV9waSA9IDE0NDg4MDM4OTE2MTU0MjQ1MDAwTEw7CiAgICBpbnQgVFBfV1JfV0lEVEggPSBicHAvMiticHArMysoMS10Y19tb2RlKSooMS1pZGN0X21vZGUpOwogICAgdWludDY0X3QgSyA9IGsgPj4gKDY0IC0gVFBfV1JfV0lEVEggLSAxMik7CiAgICBmb3IgKGludCBpID0gMTsgaSA8PSA1NjsgaSsrKSB7CiAgICAgICAgYXRhbmhfZml4ZWRbaV0gPSAodWludDY0X3QpKGF0YW5oX2ZpeGVkNTVbaV0gPj4gKDYzIC0gVFBfV1JfV0lEVEggLSAxMikpOwogICAgfQogICAgd2hpbGUgKHRoZXRhIDwgLW1fcGkpIAoJdGhldGEgKz0gKG1fcGkgPDwgMSk7CiAgICB3aGlsZSAodGhldGEgPiBtX3BpKQoJdGhldGEgLT0gKG1fcGkgPDwgMSk7CiAgICBpbnQgc2lnbiA9IDE7CiAgICBpZih0aGV0YSA8IC0oMiptX3BpKSl7Cgl0aGV0YSArPSBtX3BpOwoJc2lnbiA9IC0xOwogICAgfQogICAgZWxzZSBpZih0aGV0YSA+ICgyKm1fcGkpKXsKCXRoZXRhIC09IG1fcGk7CglzaWduID0gLTE7CiAgICB9CiAgICB1aW50NjRfdCB4ID0gSywgeSA9IDAsIHogPSB0aGV0YTsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgcm90OyArK2kpewoJaW50NjRfdCBkaSA9ICh6ID49IDApID8gMSA6IC0xOwoJaW50NjRfdCB4X25ldyA9IHggLSBkaSAqICh5ID4+IGkpOwoJaW50NjRfdCB5X25ldyA9IHkgKyBkaSAqICh4ID4+IGkpOwoJaW50NjRfdCB6X25ldyA9IHogLSBkaSAqIGF0YW5oX2ZpeGVkW2ldOwoJeCA9IHhfbmV3OwoJeSA9IHlfbmV3OwoJeiA9IHpfbmV3OwogICAgfQogICAgKmMgPSBzaWduICogeDsKICAgICpzID0gc2lnbiAqIHk7Cn0KCnZvaWQgY29yZGljX2RjdF8xZChjb25zdCB1aW50NjRfdCogaW4sIHVpbnQ2NF90KiBvdXQsIGludCBuLCBpbnQgcm90LCBpbnQgYnBwLCBpbnQgdGNfbW9kZSwgaW50IGlkY3RfbW9kZSkgewogICAgc3RhdGljIGludDY0X3QgYWxwaGFbTl9NQVhdOwogICAgY29uc3QgdWludDY0X3QgbV9waSA9IDE0NDg4MDM4OTE2MTU0MjQ1MDAwTEw7CiAgICBzdGF0aWMgaW50IGluaXRlZCA9IDA7CiAgICBpZiAoIWluaXRlZCl7CglhbHBoYVswXSA9IHNxcnQoMSAvIG4pOwoJZm9yIChpbnQgayA9IDE7IGsgPCBuOyArK2spCgkgICAgYWxwaGFba10gPSBzcXJ0KDIgLyBuKTsKCWluaXRlZCA9IDE7CiAgICB9CiAgICBmb3IgKGludCBrID0gMDsgayA8IG47ICsraykgewoJaW50NjRfdCBhY2MgPSAwOwoJZm9yKGludCBtID0gMDsgbSA8IG47ICsrbSkgewoJICAgIGludDY0X3QgYW5nbGUgPSAobV9waSAqICgyTEwgKiBtICsgMUxMKSAqIGspIC8gKDJMTCAqIG4pOwoJICAgIGludDY0X3QgYywgczsKCSAgICBjb3JkaWNfcm90YXRpb24oYW5nbGUsIHJvdCwgJmMsICZzLCBicHAsIHRjX21vZGUsIGlkY3RfbW9kZSk7CgkgICAgYWNjICs9IGluW21dICogYzsKCX0KICAgIG91dFtrXSA9IGFscGhhW2tdICogYWNjOwogICAgfQp9CgovLyBxdWFudGl6ZSBmcm9tIGludDY0X3QgKHNpZ25lZCkgdG8gaW50NjRfdCAoc2lnbmVkKQp2b2lkIHF1YW50aXplX2ZpeGVkKGludDY0X3QqIGluLCBpbnQ2NF90KiBvdXQsIGludCBuLGludCBydF9tb2RlLCBpbnQgcXVhbnRfbWF0cml4W05fTUFYXVtOX01BWF0pIHsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbjsgaSsrKQogICAgICAgIGZvciAoaW50IGogPSAwOyBqIDwgbjsgaisrKSB7CiAgICAgICAgICAgIGludCBxID0gcXVhbnRfbWF0cml4W2ldW2pdOwogICAgICAgICAgICBpZiAocSA9PSAwKSBxID0gMTsgLy8gc2FmZXR5CiAgICAgICAgICAgIGlmKHJ0X21vZGU9PTApIHsKICAgICAgICAgICAgICAgIGRvdWJsZSB2ID0gKGRvdWJsZSlpbltpKm4gKyBqXSAvIChkb3VibGUpcTsKICAgICAgICAgICAgICAgIG91dFtpKm4gKyBqXSA9IChpbnQ2NF90KWxscm91bmQodik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZXsKICAgICAgICAgICAgICAgIG91dFtpKm4ral0gICA9IGluW2kqbitqXS9xOwogICAgICAgICAgICB9CiAgICAgICAgfQp9Cgp2b2lkIHppZ3phZ190cmF2ZXJzYWxfaW50NjQoaW50NjRfdCogbWF0LCBpbnQ2NF90KiBvdXQsIGludCBuKSB7CiAgICBpbnQgaSA9IDAsIGogPSAwLCBpbmRleCA9IDAsIHVwID0gMTsKICAgIGZvciAoaW50IGsgPSAwOyBrIDwgbiAqIG47IGsrKykgewogICAgICAgIG91dFtpbmRleCsrXSA9IG1hdFtpKm4gKyBqXTsKICAgICAgICBpZiAodXApIHsKICAgICAgICAgICAgaWYgKGogPT0gbiAtIDEpICAgICAgeyBpKys7IHVwID0gMDsgfQogICAgICAgICAgICBlbHNlIGlmIChpID09IDApICAgICB7IGorKzsgdXAgPSAwOyB9CiAgICAgICAgICAgIGVsc2UgICAgICAgICAgICAgICAgIHsgaS0tOyBqKys7IH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBpZiAoaSA9PSBuIC0gMSkgICAgICB7IGorKzsgdXAgPSAxOyB9CiAgICAgICAgICAgIGVsc2UgaWYgKGogPT0gMCkgICAgIHsgaSsrOyB1cCA9IDE7IH0KICAgICAgICAgICAgZWxzZSAgICAgICAgICAgICAgICAgeyBpKys7IGotLTsgfQogICAgICAgIH0KICAgIH0KfQoKc3RhdGljIGlubGluZSBpbnQ2NF90IGxpbWl0X2JpdHNfc2lnbmVkKGludDY0X3QgeCwgaW50IGJpdHMpIHsKICAgIGludDY0X3QgbWluLCBtYXg7CiAgICBpZiAoYml0cyA+PSA2MykgcmV0dXJuIHg7CiAgICBtaW4gPSAtKDFMTCA8PCAoYml0cyAtIDEpKTsKICAgIG1heCA9ICAoMUxMIDw8IChiaXRzIC0gMSkpIC0gMTsKICAgIGlmICh4IDwgbWluKSB4ID0gbWluOwogICAgZWxzZSBpZiAoeCA+IG1heCkgeCA9IG1heDsKICAgIHJldHVybiB4Owp9CgpzdGF0aWMgaW5saW5lIGludDY0X3QgaW52ZXJzZV9saW1pdF9iaXRzX3NpZ25lZChpbnQ2NF90IHgsIGludCBiaXRzKQp7CiAgICBpZiAoYml0cyA+PSA2MykgcmV0dXJuIHg7ICAgICAgICAgICAgICAgLy8gTm8gbGltaXQgbmVlZGVkCgogICAgaW50NjRfdCBtYXggPSAoMUxMIDw8IGJpdHMpIC0gMTsgICAgICAgIC8vIE1heCB1bnNpZ25lZCB2YWx1ZSB3aXRoIE4gYml0cwoKICAgIGlmICh4IDwgMCkKICAgICAgICByZXR1cm4gMDsgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOZWdhdGl2ZSDihpIgY2xhbXAgdG8gMAoKICAgIGlmICh4ID4gbWF4KQogICAgICAgIHJldHVybiBtYXg7ICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE92ZXJmbG93IOKGkiBjbGFtcCB0byBtYXgKCiAgICByZXR1cm4geDsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2l0aGluIHJhbmdlCn0KCi8vID09PSBNQUlOIEZVTkNUSU9OID09PQppbnQgbWFpbigpIHsKICAgIGludCBuID0gOCwgYnBwID0gODsKCiAgICBwcmludGYoIlNldCBtYXRyaXggc2l6ZSBuIChldmVuLCA04oCTMTYsIGRlZmF1bHQgOCk6ICIpOwogICAgaW50IHRtcG47CiAgICBpZiAoc2NhbmYoIiVkIiwgJnRtcG4pID09IDEgJiYgdG1wbiA+PSA0ICYmIHRtcG4gPD0gMTYgJiYgdG1wbiAlIDIgPT0gMCkKICAgICAgICBuID0gdG1wbjsKCiAgICBwcmludGYoIlNldCBiaXRzIHBlciBwaXhlbCBicHAgKDTigJMzMiwgZGVmYXVsdCA4KTogIik7CiAgICBpbnQgdG1wYjsKICAgIGlmIChzY2FuZigiJWQiLCAmdG1wYikgPT0gMSAmJiB0bXBiID49IDQgJiYgdG1wYiA8PSAzMikKICAgICAgICBicHAgPSB0bXBiOwoKICAgIGludCB0Y19tb2RlOwogICAgcHJpbnRmKCJlbnRlciB0aGUgdGNfbW9kZSAoMD1ub3JtYWwgc2lnbmVkLCAxPW5vcm1hbCBzaWduZWQg4oCTIGN1cnJlbnRseSBzYW1lKTogIik7CiAgICBzY2FuZigiJWQiLCAmdGNfbW9kZSk7ICAvLyBrZXB0IGZvciBpbnRlcmZhY2U7IG5vdCBjaGFuZ2luZyBiZWhhdmlvcgoKICAgIGludCBpZGN0X21vZGU7CiAgICBwcmludGYoImVudGVyIHRoZSBpZGN0X21vZGUgKDA9RENULCAxPUlEQ1QpOiAiKTsKICAgIHNjYW5mKCIlZCIsICZpZGN0X21vZGUpOwoKICAgIGludCBydF9tb2RlOwogICAgcHJpbnRmKCJlbnRlciB0aGUgcnRfbW9kZSAoMCA6cm91bmRlZCB1cCAxOnRydW5jYXRlKTogIik7CiAgICBzY2FuZigiJWQiLCAmcnRfbW9kZSk7CgogICAgaW50IGFkZHJfYml0cyA9IGNsb2cyX24yKG4pOwogICAgcHJpbnRmKCJGb3Igbj0lZCwgUkFNIGFkZHJlc3Mgd2lkdGg6ICVkIGJpdHNcbiIsIG4sIGFkZHJfYml0cyk7CgogICAgLy8gU2VsZWN0IHF1YW50aXphdGlvbiBtYXRyaXgKICAgIGludCBxdWFudF9tYXRyaXhbTl9NQVhdW05fTUFYXSwgcm90OwogICAgc2VsZWN0X3F1YW50X21hdHJpeChuLCBxdWFudF9tYXRyaXgpOwogICAgcm90ID0gcm90YXRpb25zKGJwcCk7CiAgICBwcmludGYoIlxuJWQ6XG4iLCByb3QpOwoKICAgIC8vIEVmZmVjdGl2ZSBpbnB1dCB3aWR0aCAoZm9yIHJhbmdlIGxpbWl0IG9ubHkpCiAgICAvLyBpbnQgaW5wdXRfYml0cyA9IChpZGN0X21vZGUgPT0gMCkgPyBicHAgOiAobi8yICsgYnBwKTsKICAgIC8vIHVuc2lnbmVkIGxvbmcgbG9uZyBtYXhfdmFsID0gKGlucHV0X2JpdHMgPj0gNjMpID8gKCgxVUxMIDw8IDYyKSAtIDFVTEwpCiAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6ICgoMVVMTCA8PCAoaW5wdXRfYml0cyAtIDEpKSAtIDFVTEwpOwoKICAgIC8vIEJ1ZmZlcnMKICAgIGludDY0X3QgIGRjdF9tZW1bTl9NQVgqTl9NQVhdOyAgICAgICAgLy8gZ2VuZXJpYyBmbG9hdCBidWZmZXIgKHNwYXRpYWwgb3IgZnJlcSkKICAgIGludDY0X3QgIHRwX21lbVtOX01BWCpOX01BWF07ICAgICAgICAgLy8gYWZ0ZXIgcm93IHRyYW5zZm9ybQogICAgaW50NjRfdCB0cF90cmFuc3Bvc2VkW05fTUFYKk5fTUFYXTsgIC8vIHRyYW5zcG9zZWQgaW50ZXJtZWRpYXRlCiAgICBpbnQ2NF90IGZpeGVkW05fTUFYKk5fTUFYXTsgICAgICAgICAvLyBpbnRlZ2VyLXJvdW5kZWQgdmFsdWVzCiAgICBpbnQ2NF90IHF1YW50aXplZFtOX01BWCpOX01BWF07ICAgICAvLyBxdWFudGl6ZWQgY29lZmZpY2llbnRzCiAgICBpbnQ2NF90IHppZ3phZ1tOX01BWCpOX01BWF07ICAgICAgICAvLyB6aWd6YWcgb3JkZXIKICAgIGludDY0X3QgemlnemFnX21hdHJpeFtOX01BWCpOX01BWF07IC8vIHppZ3phZyBhcnJheSByZXNoYXBlZCBhcyBtYXRyaXgKICAgIGludDY0X3QgaWRjdF9tYXRyaXhbTl9NQVgqTl9NQVhdOyAgIC8vIGRlLXppZ3phZ2dlZCBxdWFudGl6ZWQKICAgIGludDY0X3QgaWRjdF9tZW1bTl9NQVgqTl9NQVhdOyAgICAgIC8vIGRlcXVhbnRpemVkIGZyZXEtZG9tYWluIChpbnQ2NCkKCiAgICAKCiAgICBpZiAoaWRjdF9tb2RlID09IDApIHsKICAgICAgICBpbnQgZG9uZT0wOwogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09CiAgICAgICAgLy8gRm9yd2FyZCAyRCBEQ1QgKyBRdWFudCArIFppZ3phZwogICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09CiAgICAgICAgaW50IGlucHV0X2JpdHMgPSAoaWRjdF9tb2RlID09IDApID8gYnBwIDogKG4vMiArIGJwcCk7CiAgICAgICAgdW5zaWduZWQgbG9uZyBsb25nIG1heF92YWwgPSAoaW5wdXRfYml0cyA+PSA2NCkgPyB+MFVMTCA6ICgoMVVMTCA8PCBpbnB1dF9iaXRzKSAtIDFVTEwpOwogICAgICAgIHByaW50ZigiRW50ZXIgJWQgaW5wdXQgdmFsdWVzIChkZWNpbWFsLCAw4oCTJWxsdSk6XG4iLCBuICogbiwgbWF4X3ZhbCk7CiAgICAgICAgZm9yIChpbnQgYWRkciA9IDA7IGFkZHIgPCBuICogbjsgKythZGRyKSB7CiAgICAgICAgICAgIHVuc2lnbmVkIGxvbmcgbG9uZyB1dmFsOwogICAgICAgICAgICBpZiAoc2NhbmYoIiVsbHUiLCAmdXZhbCkgIT0gMSB8fCB1dmFsID4gbWF4X3ZhbCkgewogICAgICAgICAgICAgICAgZnByaW50ZihzdGRlcnIsICJJbnB1dCBvdXQgb2YgcmFuZ2UgKDDigJMlbGx1KVxuIiwgbWF4X3ZhbCk7CiAgICAgICAgICAgICAgICByZXR1cm4gMTsKICAgICAgICAgICAgfQogICAgCiAgICAgICAgICAgIC8vIEludGVycHJldCBhcyB1bnNpZ25lZCBvciBzaWduZWQgKHR3bydzIGNvbXBsZW1lbnQpIGRlcGVuZGluZyBvbiB0Y19tb2RlCiAgICAgICAgICAgIGlmICh0Y19tb2RlID09IDEpIHsKICAgICAgICAgICAgICAgIGRjdF9tZW1bYWRkcl0gPSAofnV2YWwrMSkgJiAoKCgodWludDY0X3QpMSA8PCBpbnB1dF9iaXRzKSAtIDEpKTs7CiAgICAgICAgICAgICAgICBwcmludGYoIldSIGRjdF9tZW1bJWRdID0gJS4wZlxuIiwgYWRkciwgZGN0X21lbVthZGRyXSk7CiAgICAgICAgICAgICAgICBkb25lPTE7CiAgICAgICAgICAgICAgICAvL2ludDY0X3Qgc3ZhbCA9IHRjX3RvX3NpZ25lZCh1dmFsLCBpbnB1dF9iaXRzKTsKICAgICAgICAgICAgICAgIC8vIGRjdF9tZW1bYWRkcl0gPSB0d29zX2NvbXBsZW1lbnRfdG9fc2lnbmVkKHV2YWwsIGlucHV0X2JpdHMpOwogICAgICAgICAgICAgICAgLy8gcHJpbnRmKCJXUiBkY3RfbWVtWyVkXSA9ICVsbGQgKGZyb20gMHglbGxYLCAlZC1iaXQgdHdvJ3MgY29tcGxlbWVudClcbiIsCiAgICAgICAgICAgICAgICAvLyAgICAgICBhZGRyLCAobG9uZyBsb25nKXN2YWwsIHV2YWwsIGlucHV0X2JpdHMpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBkY3RfbWVtW2FkZHJdID0gKGludDY0X3QpdXZhbDsKICAgICAgICAgICAgcHJpbnRmKCJXUiBkY3RfbWVtWyVkXSA9ICUuMGZcbiIsIGFkZHIsIGRjdF9tZW1bYWRkcl0pOwogICAgICAgICAgICBkb25lPTE7CiAgICAgICAgfQogICAgfQoKICAgICAgICAvLyBTdGVwIDE6IFJvdy13aXNlIERDVAogICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbjsgaSsrKSB7CiAgICAgICAgICAgIGludDY0X3QgaW5fcm93W05fTUFYXSwgb3V0X3Jvd1tOX01BWF07CiAgICAgICAgICAgIGZvciAoaW50IGogPSAwOyBqIDwgbjsgaisrKQogICAgICAgICAgICAgICAgaW5fcm93W2pdID0gZGN0X21lbVtpKm4gKyBqXTsKICAgICAgICAgICAgY29yZGljX2RjdF8xZChpbl9yb3csIG91dF9yb3csIG4sIHJvdCwgYnBwLCB0Y19tb2RlLCBpZGN0X21vZGUpOwogICAgICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IG47IGorKykKICAgICAgICAgICAgICAgIHRwX21lbVtpKm4gKyBqXSA9IChpbnQ2NF90KW91dF9yb3dbal07CiAgICAgICAgfQogICAgICAgIHByaW50X21hdHJpeF9pbnQ2NCgiMUQgRENUIChSb3dzKSBPdXRwdXQiLCB0cF9tZW0sIG4pOwoKICAgICAgICAvLyBTdGVwIDI6IFRyYW5zcG9zZSBhZnRlciByb3VuZGluZwogICAgICAgIC8vZmxvYXRfdG9faW50NjQodHBfbWVtLCBmaXhlZCwgbiwgcnRfbW9kZSk7CgogICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbjsgaSsrKQogICAgICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IG47IGorKykKICAgICAgICAgICAgICAgIHRwX3RyYW5zcG9zZWRbaSpuICsgal0gPSAoaW50NjRfdClmaXhlZFtqKm4gKyBpXTsKCiAgICAgICAgLy9wcmludF9tYXRyaXhfZG91YmxlKCJUcmFuc3Bvc2UgYWZ0ZXIgMUQgRENUIChkb3VibGUpIiwgdHBfdHJhbnNwb3NlZCwgbik7CgogICAgICAgIC8vIFN0ZXAgMzogQ29sdW1uLXdpc2UgRENUIG9uIHRyYW5zcG9zZWQKICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IG47IGkrKykgewogICAgICAgICAgICBpbnQ2NF90IGluX2NvbFtOX01BWF0sIG91dF9jb2xbTl9NQVhdOwogICAgICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IG47IGorKykKICAgICAgICAgICAgICAgIGluX2NvbFtqXSA9IHRwX3RyYW5zcG9zZWRbaSpuICsgal07CiAgICAgICAgICAgIGNvcmRpY19kY3RfMWQoaW5fY29sLCBvdXRfY29sLCBuLCByb3QsIGJwcCwgdGNfbW9kZSwgaWRjdF9tb2RlKTsKICAgICAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBuOyBqKyspCiAgICAgICAgICAgICAgICBkY3RfbWVtW2kqbiArIGpdID0gKGludDY0X3Qpb3V0X2NvbFtqXTsKICAgICAgICB9CiAgICAgICAgcHJpbnRfbWF0cml4X2ludDY0KCJGaW5hbCAyRCBEQ1QgUmVzdWx0IiwgZGN0X21lbSwgbik7CgogICAgICAgIC8vIFN0ZXAgNDogUXVhbnRpemF0aW9uICsgWmlnemFnCiAgICAgICAgLy9mbG9hdF90b19pbnQ2NChkY3RfbWVtLCBmaXhlZCwgbiwgcnRfbW9kZSk7CiAgICAgICAgcHJpbnRfbWF0cml4X2ludDY0KCJEQ1Qgcm91bmRlZCB0byBpbnQ2NCAoYmVmb3JlIHF1YW50KSIsIGZpeGVkLCBuKTsKCiAgICAgICAgcXVhbnRpemVfZml4ZWQoZml4ZWQsIHF1YW50aXplZCwgbixydF9tb2RlLCBxdWFudF9tYXRyaXgpOwogICAgICAgIGludCBkY3RfYml0cz0obi8yK2JwcCk7CiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuKm47ICsraSkKICAgICAgICAgICAgcXVhbnRpemVkW2ldID0gbGltaXRfYml0c19zaWduZWQocXVhbnRpemVkW2ldLCBkY3RfYml0cyk7CiAgICAgICAgcHJpbnRfbWF0cml4X2ludDY0KCJRdWFudGl6ZWQgTWF0cml4IChpbnQ2NCkiLCBxdWFudGl6ZWQsIG4pOwoKICAgICAgICB6aWd6YWdfdHJhdmVyc2FsX2ludDY0KHF1YW50aXplZCwgemlnemFnLCBuKTsKICAgICAgICBwcmludF96aWd6YWdfaW50NjQoIlppZy1aYWcgT3V0cHV0IEFycmF5IiwgemlnemFnLCBuKTsKCiAgICAgICAgLy8gQWxzbyByZXNoYXBlIHppZ3phZyBhcyBuIHggbiBtYXRyaXggKGZvciBlYXNpZXIgdmlzdWFsKQogICAgICAgIGZvciAoaW50IGlkeCA9IDA7IGlkeCA8IG4qbjsgaWR4KyspCiAgICAgICAgICAgIHppZ3phZ19tYXRyaXhbaWR4XSA9IHppZ3phZ1tpZHhdOwogICAgICAgIHByaW50X21hdHJpeF9pbnQ2NCgiWmlnLVphZyBPdXRwdXQgKGFzIG4geCBuIG1hdHJpeCkiLCB6aWd6YWdfbWF0cml4LCBuKTsKCiAgICB9ICAgICByZXR1cm4gMDsKfQ==