/*
プログラミングのお題スレ Part13
https://m...content-available-to-author-only...h.net/test/read.cgi/tech/1549160513/
831デフォルトの名無しさん2019/04/24(水) 20:52:14.50ID:NALZs80Z
お題: 簡易なテーブルを綺麗に整形する
余力があればカラムの左揃え、右揃えをオプションで選択できるようにする(出力は中央揃え)
入力:
a|aaaaa|bb
ccc|ddd|ee
出力:
**a***|*aaaaa*|***bb*
------+-------+------
*ccc**|**ddd**|***ee*
*/
#include <stdio.h>
#include <stdlib.h>
/* セル内の壁と文字列の間のスペース文字数 */
#define RDD_CHAR (' ')
#define RDD_CHAR_NUM 1
/* セル内の文字列が終わったときに使う、空の文字列 */
#define SPACE_CHAR ('*')
/* 配列で取得する最大サイズ */
typedef enum{
in_max_row = 16,
in_max_col = 1024,
table_max_row = 16,
table_max_col = 16,
out_max_row = in_max_row * 2 + 1, //input_max_row に依存
out_max_col = 2048
}max_size;
typedef struct{
char *ptr;
int size;
}tablestr_t;
/* 動作モード */
enum str_pos_id{
/* セル中の文字列の位置 */
LEFT, //左寄せ
MEDIUM, //中間
RIGHT //右寄せ
};
enum cell_width_id{
/* セルの幅 */
MAX_IN_TABLE, //すべてのセルを表の最大幅のセルに合わせる
MAX_IN_EACH_COL //各列のセルをその列の最大幅に合わせる
};
int tbl(char output[out_max_row][out_max_col],
char input[in_max_row][in_max_col],
enum str_pos_id mode_str_pos,
enum cell_width_id mode_cell_width){
/* セル内の壁と文字列の間のスペース文字数 */
int rdd_char_num = RDD_CHAR_NUM; //redundant space , 0以上の整数
char rdd_char = RDD_CHAR;
/* セル内の文字列が終わったときに使う、空の文字列 */
char space_char = SPACE_CHAR;
/* カウンタ */
int i, j;
/* セルの内容を記録する配列 */
tablestr_t table[table_max_row][table_max_col];
/* 表の区切りの水平線の文字列配列 */
char table_hori_line[out_max_col];
/* 各列のセルの幅を記録する配列 */
int col_cell_width[table_max_col];
/* 表の最も大きいセルの幅 */
int cell_max_width;
/* 各配列の行と列のサイズ */
int in_row, in_col;
int table_row, table_col;
int out_row, out_col;
/* 配列初期化 */
//table
for(i = 0; i < table_max_row; i++){
for(j = 0; j < table_max_col; j++){
table[i][j].ptr = NULL;
table[i][j].size = 0;
}
}
//col_cell_width
for(i = 0; i < table_max_col; i++){
col_cell_width[i] = 0;
}
//output
for(i = 0; i < out_max_row; i++){
for(j = 0; j < out_max_col; j++){
output[i][j] = '\0';
}
}
//table_hori_line
for(i = 0; i < in_max_col; i++){
table_hori_line[i] = '\0';
}
/* in_row, in_colを計算 */
for(i = 0; i < in_max_row; i++){
/* その行の最初の文字がnull文字なら、そこでデータの終点とする */
if(input[i][0] == '\0'){
in_row = i;
break;
}
}
/* in_col はin_max_colに設定 */
in_col = in_max_col;
/* table_row, table_colを計算 */
/* table_row がtable_max_rowに収まるサイズか確認 */
table_row = in_row;
if(table_row > table_max_row){
puts("ERROR: table_row > table_max_row");
return(1);
}
/* 各行のセルの数をカウントする */
//最終的に最大のセル数に合わせる
{ //一時変数隠蔽用ブロック
int temp;
char crr_char;
char prev_char;
table_col = 0;
for(i = 0; i < in_row; i++){
temp = 0;
prev_char = '\0';
for(j = 0; (j < in_col) && ( (crr_char = input[i][j]) != '\0'); j++){
if(crr_char == '|'){
temp++;
}
prev_char = crr_char;
}
if(prev_char != '|'){
temp++;
}
if(table_col < temp){
table_col = temp;
}
}
}
if(table_col > table_max_col){
puts("ERROR: table_col > table_max_col");
return(1);
}
/* tablelist の各セルに inputのポインタを登録 */
{ //一時変数隠蔽用ブロック
char *ptr; //inputの文字列開始位置
int size; //文字列数
int in_crr_col; //inputの文字列の解析位置
char crr_char;
for(i = 0; i < table_row; i++){
in_crr_col = 0;
for(j = 0; j < table_col; j++){
ptr = &input[i][in_crr_col];
size = 0;
while( ( (crr_char = input[i][in_crr_col]) != '|' ) && (crr_char != '\0') ){
in_crr_col++;
size++;
}
table[i][j].ptr = ptr;
table[i][j].size = size;
if(crr_char == '|'){
in_crr_col++;
}
else if(crr_char == '\0'){
break;
}
}
}
}
/* col_cell_width を計算 */
{
int temp = 0;
int cell_crr_col;
for(i = 0; i < in_row; i++){
cell_crr_col = 0;
temp = 0;
for(j = 0; j < in_col; j++){
/* '|'かnull文字を検索し、セルの最大幅を求める */
/* '|'だったら、tempを比較しリセット */
if(input[i][j] == '|'){
if(col_cell_width[cell_crr_col] < temp){
col_cell_width[cell_crr_col] = temp;
}
temp = 0;
cell_crr_col++;
}
/* null文字だったら、tempを比較しリセット、 ループ終了。次の行へ */
else if(input[i][j] == '\0'){
if(col_cell_width[cell_crr_col] < temp){
col_cell_width[cell_crr_col] = temp;
}
break;
}
/* どちらでもないなら +1 */
else{
temp++;
}
}
}
/* cell_max_widthを計算 */
cell_max_width = col_cell_width[0];
for(i = 1; i < table_col; i++){
if(cell_max_width < col_cell_width[i]){
cell_max_width = col_cell_width[i];
}
}
switch(mode_cell_width){
case MAX_IN_TABLE:
for(i = 0; i < table_col; i++){
col_cell_width[i] = cell_max_width;
}
break;
case MAX_IN_EACH_COL:
//特に何もしない
break;
default:
puts("'mode_cell_width' has invalid value");
return(1);
break;
}
}
/* out_row, out_col を計算 */
out_row = table_row * 2 + 1;
if(out_row > out_max_row){
puts("ERROR: out_row > out_max_row");
return(1);
}
out_col = (cell_max_width + rdd_char_num * 2 + 1) * table_col + 1;
if(out_col > out_max_col){
puts("ERROR: out_col > out_max_col");
return(1);
}
/* table_hori_line を作成 */
{ //一時変数隠蔽用ブロック
int hori_line_crr;
int temp;
int cell_width;
table_hori_line[0] = '+';
hori_line_crr = 1;
for(i = 0; i < table_col; i++){
temp = 0;
cell_width = col_cell_width[i] + rdd_char_num * 2;
while(temp < cell_width){
table_hori_line[hori_line_crr] = '-';
hori_line_crr++;
temp++;
}
table_hori_line[hori_line_crr] = '+';
hori_line_crr++;
}
}
/* output にtableを書き出し */
{ //一時変数隠蔽用ブロック
int out_crr_col;
int out_crr_row;
char *crr_cell_str_ptr;
int crr_cell_str_size;
int first_space_size;
int last_space_size;
int temp;
out_crr_col = 0;
out_crr_row = 0;
for(i = 0; i < table_row; i++){
if(i == 0){
for(out_crr_col = 0; out_crr_col < out_col; out_crr_col++){
output[out_crr_row][out_crr_col] = table_hori_line[out_crr_col];
}
out_crr_row++;
}
out_crr_col = 0;
output[out_crr_row][out_crr_col] = '|';
out_crr_col++;
for(j = 0; j < table_col; j++){
crr_cell_str_ptr = table[i][j].ptr;
crr_cell_str_size = table[i][j].size;
switch(mode_str_pos){
case MEDIUM:
//中央配置
if( (col_cell_width[j] + crr_cell_str_size) % 2 == 0){
first_space_size = (col_cell_width[j] - crr_cell_str_size) / 2;
last_space_size = (col_cell_width[j] - crr_cell_str_size) / 2;
}
else{
first_space_size = (col_cell_width[j] - crr_cell_str_size) / 2;
last_space_size = (col_cell_width[j] - crr_cell_str_size) / 2 + 1;
}
break;
case LEFT:
//左詰め
first_space_size = 0;
last_space_size = col_cell_width[j] - crr_cell_str_size;
break;
case RIGHT:
//右詰め
first_space_size = col_cell_width[j] - crr_cell_str_size;
last_space_size = 0;
break;
default:
puts("'mode_str_pos' has invalid value");
return(1);
break;
}
//冗長文字の書き込み
for(temp = 0; temp < rdd_char_num; temp++){
output[out_crr_row][out_crr_col] = rdd_char;
out_crr_col++;
}
//文字列の前の空白文字を書き込む
for(temp = 0; temp < first_space_size; temp++){
output[out_crr_row][out_crr_col] = space_char;
out_crr_col++;
}
//セルの文字列の書き込み
for(temp = 0; temp < crr_cell_str_size; temp++){
output[out_crr_row][out_crr_col] = crr_cell_str_ptr[temp];
out_crr_col++;
}
//文字列の後の空白文字を書き込む
for(temp = 0; temp < last_space_size; temp++){
output[out_crr_row][out_crr_col] = space_char;
out_crr_col++;
}
//冗長文字の書き込み
for(temp = 0; temp < rdd_char_num; temp++){
output[out_crr_row][out_crr_col] = rdd_char;
out_crr_col++;
}
//壁 '|'を書き込む
output[out_crr_row][out_crr_col] = '|';
out_crr_col++;
}
out_crr_row++;
for(out_crr_col = 0; out_crr_col < out_col; out_crr_col++){
output[out_crr_row][out_crr_col] = table_hori_line[out_crr_col];
}
out_crr_row++;
}
}
return(0);
}
void show_input(char input[][in_max_col]){
int i = 0;
while(i < in_max_row && input[i][0] != '\0'){
printf("%s\n", input[i]);
i++;
}
puts("");
}
void show_output(char output[][out_max_col]){
int i = 0;
while(i < out_max_row && output[i][0] != '\0'){
printf("%s\n", output[i]);
i++;
}
puts("");
}
int main(void){
char input[in_max_row][in_max_col] = { "a|eeeee||123456789|abcdefg|qwertyuiop|asdxfghjkl",
"bb|ffffff",
"ccc|ggggggg||0|1|2|3",
"dddd|hhhhhhhh||4|5|6|7|" };
char output[out_max_row][out_max_col];
puts("入力: ");
show_input(input);
puts("各列ごとに幅変更、中間配置");
if(tbl(output, input, MEDIUM, MAX_IN_EACH_COL) != 0){
exit(1);
}
show_output(output);
puts("各列ごとに幅変更、左詰め");
if(tbl(output, input, LEFT, MAX_IN_EACH_COL) != 0){
exit(1);
}
show_output(output);
puts("各列ごとに幅変更、右詰め");
if(tbl(output, input, RIGHT, MAX_IN_EACH_COL) != 0){
exit(1);
}
show_output(output);
puts("全セル等幅、中間配置");
if(tbl(output, input, MEDIUM, MAX_IN_TABLE) != 0){
exit(1);
}
show_output(output);
puts("全セル等幅、左詰め");
if(tbl(output, input, LEFT, MAX_IN_TABLE) != 0){
exit(1);
}
show_output(output);
puts("全セル等幅、右詰め");
if(tbl(output, input, RIGHT, MAX_IN_TABLE) != 0){
exit(1);
}
show_output(output);
return 0;
}
LyoK44OX44Ot44Kw44Op44Of44Oz44Kw44Gu44GK6aGM44K544OsIFBhcnQxMwpodHRwczovL20uLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmgubmV0L3Rlc3QvcmVhZC5jZ2kvdGVjaC8xNTQ5MTYwNTEzLwoKODMx44OH44OV44Kp44Or44OI44Gu5ZCN54Sh44GX44GV44KTMjAxOS8wNC8yNCjmsLQpIDIwOjUyOjE0LjUwSUQ6TkFMWnM4MFoK44GK6aGMOiDnsKHmmJPjgarjg4bjg7zjg5bjg6vjgpLntrrpupfjgavmlbTlvaLjgZnjgosgCuS9meWKm+OBjOOBguOCjOOBsOOCq+ODqeODoOOBruW3puaPg+OBiOOAgeWPs+aPg+OBiOOCkuOCquODl+OCt+ODp+ODs+OBp+mBuOaKnuOBp+OBjeOCi+OCiOOBhuOBq+OBmeOCi++8iOWHuuWKm+OBr+S4reWkruaPg+OBiO+8iSAKCuWFpeWKmzogCmF8YWFhYWF8YmIgCmNjY3xkZGR8ZWUgCgrlh7rlips6IAoKKiphKioqfCphYWFhYSp8KioqYmIqIAotLS0tLS0rLS0tLS0tLSstLS0tLS0gCipjY2MqKnwqKmRkZCoqfCoqKmVlKgoqLwoKI2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KCi8qIOOCu+ODq+WGheOBruWjgeOBqOaWh+Wtl+WIl+OBrumWk+OBruOCueODmuODvOOCueaWh+Wtl+aVsCAqLyAgCiNkZWZpbmUgUkREX0NIQVIgKCcgJykKI2RlZmluZSBSRERfQ0hBUl9OVU0gMQovKiDjgrvjg6vlhoXjga7mloflrZfliJfjgYzntYLjgo/jgaPjgZ/jgajjgY3jgavkvb/jgYbjgIHnqbrjga7mloflrZfliJcgKi8KI2RlZmluZSBTUEFDRV9DSEFSICgnKicpCgovKiDphY3liJfjgaflj5blvpfjgZnjgovmnIDlpKfjgrXjgqTjgrogKi8KdHlwZWRlZiBlbnVtewogIGluX21heF9yb3cgPSAxNiwKICBpbl9tYXhfY29sID0gMTAyNCwKICB0YWJsZV9tYXhfcm93ID0gMTYsCiAgdGFibGVfbWF4X2NvbCA9IDE2LAogIG91dF9tYXhfcm93ID0gaW5fbWF4X3JvdyAqIDIgKyAxLCAvL2lucHV0X21heF9yb3cg44Gr5L6d5a2YCiAgb3V0X21heF9jb2wgPSAyMDQ4Cn1tYXhfc2l6ZTsKCnR5cGVkZWYgc3RydWN0ewogIGNoYXIgKnB0cjsKICBpbnQgc2l6ZTsKfXRhYmxlc3RyX3Q7CgoKLyog5YuV5L2c44Oi44O844OJICovCgplbnVtIHN0cl9wb3NfaWR7CiAgLyog44K744Or5Lit44Gu5paH5a2X5YiX44Gu5L2N572uICovCiAgTEVGVCwgICAvL+W3puWvhOOBmwogIE1FRElVTSwgLy/kuK3plpMKICBSSUdIVCAgIC8v5Y+z5a+E44GbCn07CgplbnVtIGNlbGxfd2lkdGhfaWR7CiAgLyog44K744Or44Gu5bmFICovCiAgTUFYX0lOX1RBQkxFLCAgIC8v44GZ44G544Gm44Gu44K744Or44KS6KGo44Gu5pyA5aSn5bmF44Gu44K744Or44Gr5ZCI44KP44Gb44KLCiAgTUFYX0lOX0VBQ0hfQ09MIC8v5ZCE5YiX44Gu44K744Or44KS44Gd44Gu5YiX44Gu5pyA5aSn5bmF44Gr5ZCI44KP44Gb44KLIAp9OwoKaW50IHRibChjaGFyIG91dHB1dFtvdXRfbWF4X3Jvd11bb3V0X21heF9jb2xdLAoJY2hhciBpbnB1dFtpbl9tYXhfcm93XVtpbl9tYXhfY29sXSwKCWVudW0gc3RyX3Bvc19pZCBtb2RlX3N0cl9wb3MsCgllbnVtIGNlbGxfd2lkdGhfaWQgbW9kZV9jZWxsX3dpZHRoKXsKCiAgLyog44K744Or5YaF44Gu5aOB44Go5paH5a2X5YiX44Gu6ZaT44Gu44K544Oa44O844K55paH5a2X5pWwICovCiAgaW50IHJkZF9jaGFyX251bSA9IFJERF9DSEFSX05VTTsgLy9yZWR1bmRhbnQgc3BhY2UgLCAw5Lul5LiK44Gu5pW05pWwCiAgY2hhciByZGRfY2hhciA9IFJERF9DSEFSOyAKCiAgLyog44K744Or5YaF44Gu5paH5a2X5YiX44GM57WC44KP44Gj44Gf44Go44GN44Gr5L2/44GG44CB56m644Gu5paH5a2X5YiXICovCiAgY2hhciBzcGFjZV9jaGFyID0gU1BBQ0VfQ0hBUjsKICAKICAvKiDjgqvjgqbjg7Pjgr8gKi8KICBpbnQgaSwgajsKCiAgLyog44K744Or44Gu5YaF5a6544KS6KiY6Yyy44GZ44KL6YWN5YiXICovIAogIHRhYmxlc3RyX3QgdGFibGVbdGFibGVfbWF4X3Jvd11bdGFibGVfbWF4X2NvbF07CgogIC8qIOihqOOBruWMuuWIh+OCiuOBruawtOW5s+e3muOBruaWh+Wtl+WIl+mFjeWIlyAqLwogIGNoYXIgdGFibGVfaG9yaV9saW5lW291dF9tYXhfY29sXTsKCiAgLyog5ZCE5YiX44Gu44K744Or44Gu5bmF44KS6KiY6Yyy44GZ44KL6YWN5YiXICovCiAgaW50IGNvbF9jZWxsX3dpZHRoW3RhYmxlX21heF9jb2xdOwoKICAvKiDooajjga7mnIDjgoLlpKfjgY3jgYTjgrvjg6vjga7luYUgKi8KICBpbnQgY2VsbF9tYXhfd2lkdGg7CiAgCiAgLyog5ZCE6YWN5YiX44Gu6KGM44Go5YiX44Gu44K144Kk44K6ICovCiAgaW50IGluX3JvdywgaW5fY29sOwogIGludCB0YWJsZV9yb3csIHRhYmxlX2NvbDsKICBpbnQgb3V0X3Jvdywgb3V0X2NvbDsKCiAgCiAgLyog6YWN5YiX5Yid5pyf5YyWICovCiAgLy90YWJsZQogIGZvcihpID0gMDsgaSA8IHRhYmxlX21heF9yb3c7IGkrKyl7CiAgICBmb3IoaiA9IDA7IGogPCB0YWJsZV9tYXhfY29sOyBqKyspewogICAgICB0YWJsZVtpXVtqXS5wdHIgPSBOVUxMOwogICAgICB0YWJsZVtpXVtqXS5zaXplID0gMDsKICAgIH0KICB9CiAgLy9jb2xfY2VsbF93aWR0aAogIGZvcihpID0gMDsgaSA8IHRhYmxlX21heF9jb2w7IGkrKyl7CiAgICBjb2xfY2VsbF93aWR0aFtpXSA9IDA7CiAgfQogIC8vb3V0cHV0CiAgZm9yKGkgPSAwOyBpIDwgb3V0X21heF9yb3c7IGkrKyl7CiAgICBmb3IoaiA9IDA7IGogPCBvdXRfbWF4X2NvbDsgaisrKXsKICAgICAgb3V0cHV0W2ldW2pdID0gJ1wwJzsKICAgIH0KICB9CiAgLy90YWJsZV9ob3JpX2xpbmUKICBmb3IoaSA9IDA7IGkgPCBpbl9tYXhfY29sOyBpKyspewogICAgdGFibGVfaG9yaV9saW5lW2ldID0gJ1wwJzsKICB9CgogIAogIC8qIGluX3JvdywgaW5fY29s44KS6KiI566XICovCiAgZm9yKGkgPSAwOyBpIDwgaW5fbWF4X3JvdzsgaSsrKXsKICAgIC8qIOOBneOBruihjOOBruacgOWIneOBruaWh+Wtl+OBjG51bGzmloflrZfjgarjgonjgIHjgZ3jgZPjgafjg4fjg7zjgr/jga7ntYLngrnjgajjgZnjgosgKi8KICAgIGlmKGlucHV0W2ldWzBdID09ICdcMCcpewogICAgICBpbl9yb3cgPSBpOwogICAgICBicmVhazsKICAgIH0KICB9CiAgLyogaW5fY29sIOOBr2luX21heF9jb2zjgavoqK3lrpogKi8KICBpbl9jb2wgPSBpbl9tYXhfY29sOwoKICAKICAvKiB0YWJsZV9yb3csIHRhYmxlX2NvbOOCkuioiOeulyAqLwogIC8qIHRhYmxlX3JvdyDjgYx0YWJsZV9tYXhfcm9344Gr5Y+O44G+44KL44K144Kk44K644GL56K66KqNICovCiAgdGFibGVfcm93ID0gaW5fcm93OwogIGlmKHRhYmxlX3JvdyA+IHRhYmxlX21heF9yb3cpewogICAgcHV0cygiRVJST1I6IHRhYmxlX3JvdyA+IHRhYmxlX21heF9yb3ciKTsKICAgIHJldHVybigxKTsKICB9CiAgCiAgCiAgLyog5ZCE6KGM44Gu44K744Or44Gu5pWw44KS44Kr44Km44Oz44OI44GZ44KLICovCiAgLy/mnIDntYLnmoTjgavmnIDlpKfjga7jgrvjg6vmlbDjgavlkIjjgo/jgZvjgosKICB7IC8v5LiA5pmC5aSJ5pWw6Zqg6JS955So44OW44Ot44OD44KvCiAgICBpbnQgdGVtcDsKICAgIGNoYXIgY3JyX2NoYXI7CiAgICBjaGFyIHByZXZfY2hhcjsKICAgIAogICAgdGFibGVfY29sID0gMDsKICAgIGZvcihpID0gMDsgaSA8IGluX3JvdzsgaSsrKXsKICAgICAgdGVtcCA9IDA7CiAgICAgIHByZXZfY2hhciA9ICdcMCc7CiAgICAgIGZvcihqID0gMDsgKGogPCBpbl9jb2wpICYmICggKGNycl9jaGFyID0gaW5wdXRbaV1bal0pICE9ICdcMCcpOyBqKyspewoJaWYoY3JyX2NoYXIgPT0gJ3wnKXsKCSAgdGVtcCsrOwoJfQoJcHJldl9jaGFyID0gY3JyX2NoYXI7CiAgICAgIH0KICAgICAgaWYocHJldl9jaGFyICE9ICd8Jyl7Cgl0ZW1wKys7CiAgICAgIH0KICAgICAgCiAgICAgIGlmKHRhYmxlX2NvbCA8IHRlbXApewoJdGFibGVfY29sID0gdGVtcDsKICAgICAgfQogICAgfQogIH0KICBpZih0YWJsZV9jb2wgPiB0YWJsZV9tYXhfY29sKXsKICAgIHB1dHMoIkVSUk9SOiB0YWJsZV9jb2wgPiB0YWJsZV9tYXhfY29sIik7CiAgICByZXR1cm4oMSk7CiAgfQoKICAKICAvKiB0YWJsZWxpc3Qg44Gu5ZCE44K744Or44GrIGlucHV044Gu44Od44Kk44Oz44K/44KS55m76YyyICovCiAgeyAvL+S4gOaZguWkieaVsOmaoOiUveeUqOODluODreODg+OCrwogICAgY2hhciAqcHRyOyAvL2lucHV044Gu5paH5a2X5YiX6ZaL5aeL5L2N572uCiAgICBpbnQgc2l6ZTsgIC8v5paH5a2X5YiX5pWwCiAgICBpbnQgaW5fY3JyX2NvbDsgLy9pbnB1dOOBruaWh+Wtl+WIl+OBruino+aekOS9jee9rgogICAgY2hhciBjcnJfY2hhcjsKICAgIAogICAgZm9yKGkgPSAwOyBpIDwgdGFibGVfcm93OyBpKyspewogICAgICBpbl9jcnJfY29sID0gMDsKICAgICAgZm9yKGogPSAwOyBqIDwgdGFibGVfY29sOyBqKyspewoJcHRyID0gJmlucHV0W2ldW2luX2Nycl9jb2xdOwoJc2l6ZSA9IDA7Cgl3aGlsZSggKCAoY3JyX2NoYXIgPSBpbnB1dFtpXVtpbl9jcnJfY29sXSkgIT0gJ3wnICkgJiYgKGNycl9jaGFyICE9ICdcMCcpICl7CgkgIGluX2Nycl9jb2wrKzsKCSAgc2l6ZSsrOwoJfQoJCgl0YWJsZVtpXVtqXS5wdHIgPSBwdHI7Cgl0YWJsZVtpXVtqXS5zaXplID0gc2l6ZTsKCglpZihjcnJfY2hhciA9PSAnfCcpewoJICBpbl9jcnJfY29sKys7Cgl9CgllbHNlIGlmKGNycl9jaGFyID09ICdcMCcpewoJICBicmVhazsKCX0KICAgICAgfQogICAgfQogIH0KCiAgCiAgLyogY29sX2NlbGxfd2lkdGgg44KS6KiI566XICovCiAgewogICAgaW50IHRlbXAgPSAwOwogICAgaW50IGNlbGxfY3JyX2NvbDsKCiAgICBmb3IoaSA9IDA7IGkgPCBpbl9yb3c7IGkrKyl7CiAgICAgIGNlbGxfY3JyX2NvbCA9IDA7CiAgICAgIHRlbXAgPSAwOwogICAgICBmb3IoaiA9IDA7IGogPCBpbl9jb2w7IGorKyl7CgkvKiAnfCfjgYtudWxs5paH5a2X44KS5qSc57Si44GX44CB44K744Or44Gu5pyA5aSn5bmF44KS5rGC44KB44KLICovCgkvKiAnfCfjgaDjgaPjgZ/jgonjgIF0ZW1w44KS5q+U6LyD44GX44Oq44K744OD44OIICovCglpZihpbnB1dFtpXVtqXSA9PSAnfCcpewoJICBpZihjb2xfY2VsbF93aWR0aFtjZWxsX2Nycl9jb2xdIDwgdGVtcCl7CgkgICAgY29sX2NlbGxfd2lkdGhbY2VsbF9jcnJfY29sXSA9IHRlbXA7CgkgIH0KCSAgdGVtcCA9IDA7CgkgIGNlbGxfY3JyX2NvbCsrOwoJfQoJLyogbnVsbOaWh+Wtl+OBoOOBo+OBn+OCieOAgXRlbXDjgpLmr5TovIPjgZfjg6rjgrvjg4Pjg4jjgIEg44Or44O844OX57WC5LqG44CC5qyh44Gu6KGM44G4ICovCgllbHNlIGlmKGlucHV0W2ldW2pdID09ICdcMCcpewoJICBpZihjb2xfY2VsbF93aWR0aFtjZWxsX2Nycl9jb2xdIDwgdGVtcCl7CgkgICAgY29sX2NlbGxfd2lkdGhbY2VsbF9jcnJfY29sXSA9IHRlbXA7CgkgIH0KCSAgYnJlYWs7Cgl9CgkvKiDjganjgaHjgonjgafjgoLjgarjgYTjgarjgokgKzEgKi8KCWVsc2V7CgkgIHRlbXArKzsKCX0KICAgICAgfQogICAgfQoKICAgIC8qIGNlbGxfbWF4X3dpZHRo44KS6KiI566XICovCiAgICBjZWxsX21heF93aWR0aCA9ICBjb2xfY2VsbF93aWR0aFswXTsKICAgIGZvcihpID0gMTsgaSA8IHRhYmxlX2NvbDsgaSsrKXsKICAgICAgaWYoY2VsbF9tYXhfd2lkdGggPCBjb2xfY2VsbF93aWR0aFtpXSl7CgljZWxsX21heF93aWR0aCA9IGNvbF9jZWxsX3dpZHRoW2ldOwogICAgICB9CiAgICB9CiAgICAKICAgIHN3aXRjaChtb2RlX2NlbGxfd2lkdGgpewogICAgY2FzZSBNQVhfSU5fVEFCTEU6CiAgICAgIGZvcihpID0gMDsgaSA8IHRhYmxlX2NvbDsgaSsrKXsKCWNvbF9jZWxsX3dpZHRoW2ldID0gY2VsbF9tYXhfd2lkdGg7CiAgICAgIH0KICAgICAgYnJlYWs7CgogICAgY2FzZSBNQVhfSU5fRUFDSF9DT0w6CiAgICAgIC8v54m544Gr5L2V44KC44GX44Gq44GECiAgICAgIGJyZWFrOwoKICAgIGRlZmF1bHQ6CiAgICAgIHB1dHMoIidtb2RlX2NlbGxfd2lkdGgnIGhhcyBpbnZhbGlkIHZhbHVlIik7CiAgICAgIHJldHVybigxKTsKICAgICAgYnJlYWs7CiAgICB9ICAgCiAgfQoKICAKICAvKiBvdXRfcm93LCBvdXRfY29sIOOCkuioiOeulyAqLwogIG91dF9yb3cgPSB0YWJsZV9yb3cgKiAyICsgMTsKICBpZihvdXRfcm93ID4gb3V0X21heF9yb3cpewogICAgcHV0cygiRVJST1I6IG91dF9yb3cgPiBvdXRfbWF4X3JvdyIpOwogICAgcmV0dXJuKDEpOwogIH0KICBvdXRfY29sID0gKGNlbGxfbWF4X3dpZHRoICsgcmRkX2NoYXJfbnVtICogMiArIDEpICogdGFibGVfY29sICsgMTsKICBpZihvdXRfY29sID4gb3V0X21heF9jb2wpewogICAgcHV0cygiRVJST1I6IG91dF9jb2wgPiBvdXRfbWF4X2NvbCIpOwogICAgcmV0dXJuKDEpOwogIH0KCiAgCiAgLyogdGFibGVfaG9yaV9saW5lIOOCkuS9nOaIkCAqLwogIHsgLy/kuIDmmYLlpInmlbDpmqDolL3nlKjjg5bjg63jg4Pjgq8KICAgIGludCBob3JpX2xpbmVfY3JyOwogICAgaW50IHRlbXA7CiAgICBpbnQgY2VsbF93aWR0aDsKICAgIAogICAgdGFibGVfaG9yaV9saW5lWzBdID0gJysnOwogICAgaG9yaV9saW5lX2NyciA9IDE7CiAgICBmb3IoaSA9IDA7IGkgPCB0YWJsZV9jb2w7IGkrKyl7CiAgICAgIHRlbXAgPSAwOwogICAgICBjZWxsX3dpZHRoID0gY29sX2NlbGxfd2lkdGhbaV0gKyByZGRfY2hhcl9udW0gKiAyOwogICAgICB3aGlsZSh0ZW1wIDwgY2VsbF93aWR0aCl7Cgl0YWJsZV9ob3JpX2xpbmVbaG9yaV9saW5lX2Nycl0gPSAnLSc7Cglob3JpX2xpbmVfY3JyKys7Cgl0ZW1wKys7CiAgICAgIH0KICAgICAgdGFibGVfaG9yaV9saW5lW2hvcmlfbGluZV9jcnJdID0gJysnOwogICAgICBob3JpX2xpbmVfY3JyKys7CiAgICB9CiAgfQoKCiAgLyogb3V0cHV0IOOBq3RhYmxl44KS5pu444GN5Ye644GXICovCiAgeyAvL+S4gOaZguWkieaVsOmaoOiUveeUqOODluODreODg+OCrwogICAgaW50IG91dF9jcnJfY29sOwogICAgaW50IG91dF9jcnJfcm93OwogICAgY2hhciAqY3JyX2NlbGxfc3RyX3B0cjsKICAgIGludCBjcnJfY2VsbF9zdHJfc2l6ZTsKICAgIGludCBmaXJzdF9zcGFjZV9zaXplOwogICAgaW50IGxhc3Rfc3BhY2Vfc2l6ZTsKICAgIGludCB0ZW1wOwogICAgCiAgICBvdXRfY3JyX2NvbCA9IDA7CiAgICBvdXRfY3JyX3JvdyA9IDA7CiAgICBmb3IoaSA9IDA7IGkgPCB0YWJsZV9yb3c7IGkrKyl7CiAgICAgIGlmKGkgPT0gMCl7Cglmb3Iob3V0X2Nycl9jb2wgPSAwOyBvdXRfY3JyX2NvbCA8IG91dF9jb2w7IG91dF9jcnJfY29sKyspewoJICBvdXRwdXRbb3V0X2Nycl9yb3ddW291dF9jcnJfY29sXSA9IHRhYmxlX2hvcmlfbGluZVtvdXRfY3JyX2NvbF07Cgl9CglvdXRfY3JyX3JvdysrOwogICAgICB9CiAgICAgIAogICAgICBvdXRfY3JyX2NvbCA9IDA7CiAgICAgIAogICAgICBvdXRwdXRbb3V0X2Nycl9yb3ddW291dF9jcnJfY29sXSA9ICd8JzsKICAgICAgb3V0X2Nycl9jb2wrKzsKICAgICAgCiAgICAgIGZvcihqID0gMDsgaiA8IHRhYmxlX2NvbDsgaisrKXsJCgljcnJfY2VsbF9zdHJfcHRyID0gdGFibGVbaV1bal0ucHRyOwoJY3JyX2NlbGxfc3RyX3NpemUgPSB0YWJsZVtpXVtqXS5zaXplOwoKCXN3aXRjaChtb2RlX3N0cl9wb3MpewoJY2FzZSBNRURJVU06CgkgIC8v5Lit5aSu6YWN572uCgkgIGlmKCAoY29sX2NlbGxfd2lkdGhbal0gKyBjcnJfY2VsbF9zdHJfc2l6ZSkgJSAyID09IDApewoJICAgIGZpcnN0X3NwYWNlX3NpemUgPSAoY29sX2NlbGxfd2lkdGhbal0gLSBjcnJfY2VsbF9zdHJfc2l6ZSkgLyAyOwoJICAgIGxhc3Rfc3BhY2Vfc2l6ZSA9IChjb2xfY2VsbF93aWR0aFtqXSAtIGNycl9jZWxsX3N0cl9zaXplKSAvIDI7CgkgIH0KCSAgZWxzZXsKCSAgICBmaXJzdF9zcGFjZV9zaXplID0gKGNvbF9jZWxsX3dpZHRoW2pdIC0gY3JyX2NlbGxfc3RyX3NpemUpIC8gMjsKCSAgICBsYXN0X3NwYWNlX3NpemUgPSAoY29sX2NlbGxfd2lkdGhbal0gLSBjcnJfY2VsbF9zdHJfc2l6ZSkgLyAyICsgMTsKCSAgfQoJICBicmVhazsKCSAgCgljYXNlIExFRlQ6CgkgIC8v5bem6Kmw44KBCgkgIGZpcnN0X3NwYWNlX3NpemUgPSAwOwoJICBsYXN0X3NwYWNlX3NpemUgPSBjb2xfY2VsbF93aWR0aFtqXSAtIGNycl9jZWxsX3N0cl9zaXplOwoJICBicmVhazsKCSAgICAKCWNhc2UgUklHSFQ6CgkgIC8v5Y+z6Kmw44KBCgkgIGZpcnN0X3NwYWNlX3NpemUgPSBjb2xfY2VsbF93aWR0aFtqXSAtIGNycl9jZWxsX3N0cl9zaXplOwoJICBsYXN0X3NwYWNlX3NpemUgPSAwOwoJICBicmVhazsKCglkZWZhdWx0OgoJICBwdXRzKCInbW9kZV9zdHJfcG9zJyBoYXMgaW52YWxpZCB2YWx1ZSIpOwoJICByZXR1cm4oMSk7CgkgIGJyZWFrOwoJfQoKCS8v5YaX6ZW35paH5a2X44Gu5pu444GN6L6844G/Cglmb3IodGVtcCA9IDA7IHRlbXAgPCByZGRfY2hhcl9udW07IHRlbXArKyl7CgkgIG91dHB1dFtvdXRfY3JyX3Jvd11bb3V0X2Nycl9jb2xdID0gcmRkX2NoYXI7CgkgIG91dF9jcnJfY29sKys7Cgl9CgoJLy/mloflrZfliJfjga7liY3jga7nqbrnmb3mloflrZfjgpLmm7jjgY3ovrzjgoAKCWZvcih0ZW1wID0gMDsgdGVtcCA8IGZpcnN0X3NwYWNlX3NpemU7IHRlbXArKyl7CgkgIG91dHB1dFtvdXRfY3JyX3Jvd11bb3V0X2Nycl9jb2xdID0gc3BhY2VfY2hhcjsKCSAgb3V0X2Nycl9jb2wrKzsKCX0KCQoJLy/jgrvjg6vjga7mloflrZfliJfjga7mm7jjgY3ovrzjgb8KCWZvcih0ZW1wID0gMDsgdGVtcCA8IGNycl9jZWxsX3N0cl9zaXplOyB0ZW1wKyspewoJICBvdXRwdXRbb3V0X2Nycl9yb3ddW291dF9jcnJfY29sXSA9IGNycl9jZWxsX3N0cl9wdHJbdGVtcF07CgkgIG91dF9jcnJfY29sKys7Cgl9CgoJLy/mloflrZfliJfjga7lvozjga7nqbrnmb3mloflrZfjgpLmm7jjgY3ovrzjgoAKCWZvcih0ZW1wID0gMDsgdGVtcCA8IGxhc3Rfc3BhY2Vfc2l6ZTsgdGVtcCsrKXsKCSAgb3V0cHV0W291dF9jcnJfcm93XVtvdXRfY3JyX2NvbF0gPSBzcGFjZV9jaGFyOwoJICBvdXRfY3JyX2NvbCsrOwoJfQoJCgkvL+WGl+mVt+aWh+Wtl+OBruabuOOBjei+vOOBvwoJZm9yKHRlbXAgPSAwOyB0ZW1wIDwgcmRkX2NoYXJfbnVtOyB0ZW1wKyspewoJICBvdXRwdXRbb3V0X2Nycl9yb3ddW291dF9jcnJfY29sXSA9IHJkZF9jaGFyOwoJICBvdXRfY3JyX2NvbCsrOwoJfQoJCgkvL+WjgSAnfCfjgpLmm7jjgY3ovrzjgoAKCW91dHB1dFtvdXRfY3JyX3Jvd11bb3V0X2Nycl9jb2xdID0gJ3wnOwoJb3V0X2Nycl9jb2wrKzsKICAgICAgfQogICAgICBvdXRfY3JyX3JvdysrOwogICAgICAKICAgICAgZm9yKG91dF9jcnJfY29sID0gMDsgb3V0X2Nycl9jb2wgPCBvdXRfY29sOyBvdXRfY3JyX2NvbCsrKXsKCW91dHB1dFtvdXRfY3JyX3Jvd11bb3V0X2Nycl9jb2xdID0gdGFibGVfaG9yaV9saW5lW291dF9jcnJfY29sXTsKICAgICAgfQogICAgICBvdXRfY3JyX3JvdysrOwogICAgfQogIH0KICAKICByZXR1cm4oMCk7Cn0KCnZvaWQgc2hvd19pbnB1dChjaGFyIGlucHV0W11baW5fbWF4X2NvbF0pewogIGludCBpID0gMDsKICB3aGlsZShpIDwgaW5fbWF4X3JvdyAmJiBpbnB1dFtpXVswXSAhPSAnXDAnKXsKICAgIHByaW50ZigiJXNcbiIsIGlucHV0W2ldKTsKICAgIGkrKzsKICB9CiAgcHV0cygiIik7Cn0KCnZvaWQgc2hvd19vdXRwdXQoY2hhciBvdXRwdXRbXVtvdXRfbWF4X2NvbF0pewogIGludCBpID0gMDsKICB3aGlsZShpIDwgb3V0X21heF9yb3cgJiYgb3V0cHV0W2ldWzBdICE9ICdcMCcpewogICAgcHJpbnRmKCIlc1xuIiwgb3V0cHV0W2ldKTsKICAgIGkrKzsKICB9CiAgcHV0cygiIik7Cn0KCmludCBtYWluKHZvaWQpewogIGNoYXIgaW5wdXRbaW5fbWF4X3Jvd11baW5fbWF4X2NvbF0gPSB7ICJhfGVlZWVlfHwxMjM0NTY3ODl8YWJjZGVmZ3xxd2VydHl1aW9wfGFzZHhmZ2hqa2wiLAoJCQkJCSAiYmJ8ZmZmZmZmIiwKCQkJCQkgImNjY3xnZ2dnZ2dnfHwwfDF8MnwzIiwKCQkJCQkgImRkZGR8aGhoaGhoaGh8fDR8NXw2fDd8IiB9OwogIGNoYXIgb3V0cHV0W291dF9tYXhfcm93XVtvdXRfbWF4X2NvbF07CgogIHB1dHMoIuWFpeWKmzogIik7CiAgc2hvd19pbnB1dChpbnB1dCk7CiAgCiAgcHV0cygi5ZCE5YiX44GU44Go44Gr5bmF5aSJ5pu044CB5Lit6ZaT6YWN572uIik7CiAgaWYodGJsKG91dHB1dCwgaW5wdXQsIE1FRElVTSwgTUFYX0lOX0VBQ0hfQ09MKSAhPSAwKXsKICAgIGV4aXQoMSk7CiAgfQogIHNob3dfb3V0cHV0KG91dHB1dCk7CgogIHB1dHMoIuWQhOWIl+OBlOOBqOOBq+W5heWkieabtOOAgeW3puipsOOCgSIpOwogIGlmKHRibChvdXRwdXQsIGlucHV0LCBMRUZULCBNQVhfSU5fRUFDSF9DT0wpICE9IDApewogICAgZXhpdCgxKTsKICB9CiAgc2hvd19vdXRwdXQob3V0cHV0KTsKCiAgcHV0cygi5ZCE5YiX44GU44Go44Gr5bmF5aSJ5pu044CB5Y+z6Kmw44KBIik7CiAgaWYodGJsKG91dHB1dCwgaW5wdXQsIFJJR0hULCBNQVhfSU5fRUFDSF9DT0wpICE9IDApewogICAgZXhpdCgxKTsKICB9CiAgc2hvd19vdXRwdXQob3V0cHV0KTsKCiAgcHV0cygi5YWo44K744Or562J5bmF44CB5Lit6ZaT6YWN572uIik7CiAgaWYodGJsKG91dHB1dCwgaW5wdXQsIE1FRElVTSwgTUFYX0lOX1RBQkxFKSAhPSAwKXsKICAgIGV4aXQoMSk7CiAgfQogIHNob3dfb3V0cHV0KG91dHB1dCk7CiAgCiAgcHV0cygi5YWo44K744Or562J5bmF44CB5bem6Kmw44KBIik7CiAgaWYodGJsKG91dHB1dCwgaW5wdXQsIExFRlQsIE1BWF9JTl9UQUJMRSkgIT0gMCl7CiAgICBleGl0KDEpOwogIH0KICBzaG93X291dHB1dChvdXRwdXQpOwoKICBwdXRzKCLlhajjgrvjg6vnrYnluYXjgIHlj7PoqbDjgoEiKTsKICBpZih0Ymwob3V0cHV0LCBpbnB1dCwgUklHSFQsIE1BWF9JTl9UQUJMRSkgIT0gMCl7CiAgICBleGl0KDEpOwogIH0KICBzaG93X291dHB1dChvdXRwdXQpOwogIAogIHJldHVybiAwOwp9