// ルーレットが完成
/* pin assign
* Digital_0 DATA (NJU3711)
* Digital_1 CK (NJU3711)
* Digital_2 SW(interrputing)
* Digital_3 NC
* Digital_4 STR (NJU3711)
* Digital_5 NC
* Digital_6 Kathode_1 (Tr)
* Digital_7 Kathode_2 (Tr)
* Digital_8 Kathode_3 (Tr)
* Digital_9 Kathode_4 (Tr)
* Digital_10 Kathode_5 (Tr)
* Digital_11 Kathode_6 (Tr)
* Digital_12 Kathode_7 (Tr)
* Digital_13 Kathode_8 (Tr)
*/
/**************************************************
* 端子、定数の定義 と ヘッダのインクルード *
***************************************************/
#include <math.h> // sin, cos
#define DATA 0 // シフトレジスタの制御ピンを定義
#define CK 1 //
#define STR 4 //
#define WIDTH_ 8 // マトリクスLEDのドット数
#define HIGH_ 8 //
#define Y0 6 // Y軸0~7列目に対応するピンを定義
#define Y1 7 //
#define Y2 8 //
#define Y3 9 //
#define Y4 10 //
#define Y5 11 //
#define Y6 12 //
#define Y7 13 //
#define UPBUTTON 14
#define DOWNBUTTON 15
#define LEFTBUTTON 16
#define RIGHTBUTTON 17
#define MODENUM 3 // 登録モードの数
#define MENU 0 // メニュー
#define ROULETTE 1 // ルーレット(ツール)
#define HAYAOSHI 2 // 早押し(ゲーム)
//#define M_PI 3.14159265358979323846
#define SIN(x) sin(x * (M_PI/180))
#define COS(x) cos(x * (M_PI/180))
/**************************************************
* グローバル変数 *
***************************************************/
const char zero[ HIGH_] [ WIDTH_] = { // 0
{ 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 }
} ;
const char one[ HIGH_] [ WIDTH_] = { // 1
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }
} ;
const char two[ HIGH_] [ WIDTH_] = { // 2
{ 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 }
} ;
const char three[ HIGH_] [ WIDTH_] = { // 3
{ 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 }
} ;
const char yajirusi[ HIGH_] [ WIDTH_] = { // 矢印
{ 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 } ,
{ 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 } ,
{ 0 , 1 , 0 , 1 , 1 , 0 , 1 , 0 } ,
{ 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 } ,
{ 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 }
} ;
char ground[ HIGH_] [ WIDTH_] = { // グラウンド
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }
} ;
int i = 0 ;
int num = 0 , flag = 0 ;
unsigned long time = 0 ; // 起動後の時間を記録する変数 int state; // メニューの選択画面の状態を記憶
int mode = 0 ; // 実行中のモードを記憶(メニュー、ルーレット…)
int i_hayaosi = 0 ; // 早押:何個目の表示かを記憶する
int muki[ 10 ] ; // 早押:ランダムな矢印の向きを記憶
int content_haya = 0 ; // 早押:状態を記憶(クリア・ミス入力)
// 0:初期値, 1:クリア, 2:ミス
/**************************************************
* GPIO等の初期設定 *
***************************************************/
void setup( )
{
pinMode( DATA, OUTPUT) ; // DATA
pinMode( CK, OUTPUT) ; // CK
pinMode( STR, OUTPUT) ; // STR
pinMode( 2 , INPUT) ; // 変化割り込み 左右スイッチの論理和
pinMode( Y0, OUTPUT) ; // LEDアノード側制御ピン
pinMode( Y1, OUTPUT) ; //
pinMode( Y2, OUTPUT) ; //
pinMode( Y3, OUTPUT) ; //
pinMode( Y4, OUTPUT) ; //
pinMode( Y5, OUTPUT) ; //
pinMode( Y6, OUTPUT) ; //
pinMode( Y7, OUTPUT) ; //
pinMode( 14 , INPUT) ; // スイッチ(上)
pinMode( 15 , INPUT) ; // スイッチ(下)
pinMode( 16 , INPUT) ; // スイッチ(左)
pinMode( 17 , INPUT) ; // スイッチ(右)
pinMode( 18 , INPUT) ; // ランダム関数の種
//-- 変化割り込みの初期設定
attachInterrupt( 0 , interrupt, RISING) ; // 2番ピンを割り込みで使用
//--
//-- シフトレジスタの初期設定
digitalWrite( STR, HIGH) ; // シフトレジスタを出力しない
digitalWrite( DATA, LOW) ; // シフトレジスタ データを0クリア
digitalWrite( STR, LOW) ; // シフトレジスタを出力する
//--
time = millis
( ) ; // プログラム開始時間を記録 roll( ground, zero, 0 ) ; // 起動直後のメニューは0を表示
state = 0 ; // 表示が0であることを記憶
}
/**************************************************
* loop関数 *
***************************************************/
void loop( )
{
switch ( state) {
case MENU:
menu( ) ; //メニューを実行
break ;
case ROULETTE:
roulette( ) ; // ルーレットを実行
break ;
case HAYAOSHI:
hayaoshi( ) ; // 早押しゲームを実行
break ;
default :
break ;
}
}
/**************************************************
* ユーザー定義関数 *
***************************************************/
//================= メ ニ ュ ー ===================
void menu( )
{
static int state1 = 0 ; // 初期状態は'0'を表示しているので0を代入
while ( flag == 0 ) { // メニューが選択されない限りループ
if ( state1 != state) { // 現在の表示データと異なる場合
switch ( state) {
case 0 : // メニュー0ならば
state1 = 0 ; // 現在の数字を '0' に変更
roll( ground, zero, 0 ) ; // 表示データを '0' に変更
break ;
case 1 :
state1 = 1 ; // 現在の数字を '1' に変更
roll( ground, one, 0 ) ; // 表示データを '1' に変更
break ;
case 2 :
state1 = 2 ; // 現在の数字を '2' に変更
roll( ground, two, 0 ) ; // 表示データを '2' に変更
break ;
}
}
draw_ground( ) ; // 選択中の番号を表示する
}
return ;
}
//=============== ル ー レ ッ ト の 処 理 ===================
void roulette( )
{
int angle;
randomSeed( analogRead( 18 ) ) ; // ランダム関数の種まき
angle = 90 * random( 0 , 4 ) ; // 停止角度を決める(90~360)
roll( ground, yajirusi, 0 ) ;
while ( millis
( ) - time < 2000 ) { // 2秒間めちゃくちゃな表示 roll( ground, yajirusi, 90 * random( 0 , 4 ) ) ;
draw_ground( ) ;
}
roll( ground, yajirusi, angle) ;
for ( i = 0 ; i < 100 ; i++ ) { // 決定した状態をしばらく表示
draw_ground( ) ;
}
flag = 0 ; // メニュー画面をループするようフラグを立てる
state = MENU; // メニュー画面へ移行
return ;
}
//=============== 早 押 し ゲ ー ム の 処 理 ===================
void hayaoshi( )
{
randomSeed( analogRead( 18 ) ) ; // ランダム関数の種まき
//-- 矢印を決めるパラメータを10個得る
for ( i = 0 ; i < 10 ; i++ ) {
muki[ i] = random( 0 , 4 ) ; // 0~3の値を得る
}
//-- 開始までのカウント処理
time = millis
( ) ; // 現在の時間を記録 while ( 1 ) {
content
= millis
( ) - time ; // 経過時間を得る(ms) if ( content > 3000 ) { // 3秒以上経過
break ; // ゲームへ移行
} else if ( content > 2000 ) { // 2秒以上経過(1を表示)
roll( ground, one, 0 ) ;
} else if ( content > 1000 ) { // 1秒以上経過(2を表示)
roll( ground, two, 0 ) ; // 表示データに2をセット
} else { // 0秒以上経過(3を表示)
roll( ground, three, 0 ) ; // 表示データに3をセット
}
draw_ground( ) ; //
}
//-- ゲーム開始
// time = millis(); // ゲーム開始の時間を得る
muki[ 0 ] = 0 ; //デバッグ用に必ず上向きで出るよう設定
roll( ground, yajirusi, muki[ i_hayaosi] * 90 ) ; // 最初の矢印を表示
while ( 1 ) { // このループ内でゲームを処理する
if ( content_haya == 1 ) { // ゲームクリアの場合
//gameclear(); // クリアした時間を出力 引数はタイム
break ;
} else if ( content_haya == 2 ) { // ゲーム失敗の場合
//gameretired(); // 失敗の表示
break ;
}
draw_ground( ) ;
}
//-- 後処理
flag = 0 ; // メニュー画面をループするようフラグを立てる
state = MENU; // メニュー画面へ移行
i_hayaosi = 0 ; // ゲームのプレイ情報を初期化
content_haya = 0 ;
}
//=================== スイッチ 割 り 込 み 処 理 ===================
void interrupt( )
{
static int angle = 0 ;
unsigned long time2 = millis( ) ; // チャタリング防止の処理
if ( time2
- time < 50 ) return ; //
if ( digitalRead( UPBUTTON) ) { //-----上ボタンが押されたならば-----
// メニュー表示中の処理
if ( flag != 1 && state != 0 ) { // メニュー画面以外のゲームが終了していれば実行
// 選択中のメニューを決定する
flag = 1 ; // メニュー画面を抜けるフラグを立てる
return ;
} else if ( state == HAYAOSHI) { // ○早押しゲームでの処理
if ( muki[ i_hayaosi] == 0 ) {
i_hayaosi += 1 ; // 次の矢印のパラメータへ加算
roll( ground, yajirusi, muki[ i_hayaosi] * 90 ) ; //矢印を次の矢印に更新
if ( i_hayaosi == 10 ) content_haya = 1 ; // ゲームクリアを教える
} else {
content_haya = 2 ; // ゲーム失敗を教える
}
}
} else if ( digitalRead( DOWNBUTTON) ) { //-----下ボタンが押されたならば-----
if ( flag == 0 ) return ; // メニュー画面上での入力は無効
if ( state == HAYAOSHI) { // ○早押しゲームでの処理
if ( muki[ i_hayaosi] == 2 ) {
i_hayaosi ++; // 次の矢印のパラメータへ加算
roll( ground, yajirusi, muki[ i_hayaosi] * 90 ) ; //矢印を次の矢印に更新
if ( i_hayaosi == 10 ) content_haya = 1 ; // ゲームクリアを教える
} else {
content_haya = 2 ; // ゲーム失敗を教える
}
}
} else if ( digitalRead( LEFTBUTTON) ) { //-----左ボタンが押されたならば-----
if ( flag != 1 && state > 0 ) { // メニュー表示中の処理
state --; // メニューを-1する
} else if ( state == HAYAOSHI) { // ○早押しゲームでの処理
if ( muki[ i_hayaosi] == 3 ) {
i_hayaosi ++; // 次の矢印のパラメータへ加算
roll( ground, yajirusi, muki[ i_hayaosi] * 90 ) ; //矢印を次の矢印に更新
if ( i_hayaosi == 10 ) content_haya = 1 ; // ゲームクリアを教える
} else {
content_haya = 2 ; // ゲーム失敗を教える
}
}
} else if ( digitalRead( RIGHTBUTTON) ) { //-----右ボタンが押されたならば-----
if ( flag != 1 && state < MODENUM- 1 ) { // メニュー表示中の処理
state ++; // メニューを+1する
} else if ( state == HAYAOSHI) { // ○早押しゲームでの処理
if ( muki[ i_hayaosi] == 1 ) {
i_hayaosi ++; // 次の矢印のパラメータへ加算
roll( ground, yajirusi, muki[ i_hayaosi] * 90 ) ; //矢印を次の矢印に更新
if ( i_hayaosi == 10 ) content_haya = 1 ; // ゲームクリアを教える
} else {
content_haya = 2 ; // ゲーム失敗を教える
}
}
}
}
//===================ground配列をマトリクスLEDに描画===================
void draw_ground( )
{
for ( int i = 0 ; i < 8 ; i++ ) { // 8列分列アノード側をシフトさせる。
if ( i== 0 ) { // 1列目が参照されていたならば
digitalWrite( DATA, HIGH) ; // HIGHをセットしてシフト
} else { // 2列目以降が参照されていたならば
digitalWrite( DATA, LOW) ; // 順次LOWをセットしてシフト
}
digitalWrite( Y0, ( ground[ 0 ] [ i] == 1 ) ? HIGH: LOW) ;
digitalWrite( Y1, ( ground[ 1 ] [ i] == 1 ) ? HIGH: LOW) ;
digitalWrite( Y2, ( ground[ 2 ] [ i] == 1 ) ? HIGH: LOW) ;
digitalWrite( Y3, ( ground[ 3 ] [ i] == 1 ) ? HIGH: LOW) ;
digitalWrite( Y4, ( ground[ 4 ] [ i] == 1 ) ? HIGH: LOW) ;
digitalWrite( Y5, ( ground[ 5 ] [ i] == 1 ) ? HIGH: LOW) ;
digitalWrite( Y6, ( ground[ 6 ] [ i] == 1 ) ? HIGH: LOW) ;
digitalWrite( Y7, ( ground[ 7 ] [ i] == 1 ) ? HIGH: LOW) ;
delay( 2 ) ;
wipe_out_shadow( ) ; // 列を切り替える前に表示を消すことで残像処理
}
}
//===================シフトレジスタへのクロック処理===================
{
digitalWrite( CK, LOW) ;
delayMicroseconds( 5 ) ;
digitalWrite( CK, HIGH) ;
delayMicroseconds( 5 ) ;
digitalWrite( CK, LOW) ;
}
//===================ドットマトリクスLEDの残像処理===================
void wipe_out_shadow( )
{
digitalWrite( Y0, LOW) ;
digitalWrite( Y1, LOW) ;
digitalWrite( Y2, LOW) ;
digitalWrite( Y3, LOW) ;
digitalWrite( Y4, LOW) ;
digitalWrite( Y5, LOW) ;
digitalWrite( Y6, LOW) ;
digitalWrite( Y7, LOW) ;
}
//======引数の表示データを任意の角度に回転してground配列にセット=====
void roll( char to[ ] [ 8 ] , const char from[ ] [ 8 ] , int angle)
{
int x, y;
double x1 = 0.0 , y1 = 0.0 ;
if ( angle == 0 ) { // 回転角度が0なら回転処理は行わない
for ( y = 0 ; y < 8 ; y++ ) {
for ( x = 0 ; x < 8 ; x++ ) {
to[ y] [ x] = from[ y] [ x] ;
}
}
} else { // 回転処理
for ( y = 0 ; y < 8 ; y++ ) {
for ( x = 0 ; x < 8 ; x++ ) {
x1 = ( ( x - 3.5 ) * COS( angle) - ( y - 3.5 ) * SIN( angle) ) ;
y1 = ( ( x - 3.5 ) * SIN( angle) + ( y - 3.5 ) * COS( angle) ) ;
x1 = x1 + 3.5 ; // ずらした座標を修正
y1 = y1 + 3.5 ; //
if ( from[ y] [ x] == 1 ) {
if ( ( int ) ( x1 + 0.5 ) < WIDTH_ && ( int ) ( y1 + 0.5 ) < HIGH_) to[ ( int ) ( y1 + 0.5 ) ] [ ( int ) ( x1 + 0.5 ) ] = 1 ;
} else {
if ( ( int ) ( x1 + 0.5 ) < WIDTH_ && ( int ) ( y1 + 0.5 ) < HIGH_) to[ ( int ) ( y1 + 0.5 ) ] [ ( int ) ( x1 + 0.5 ) ] = 0 ;
}
}
}
}
}
Ly8g44Or44O844Os44OD44OI44GM5a6M5oiQCgovKiAgICAgIHBpbiBhc3NpZ24KKiBEaWdpdGFsXzAgICAgREFUQSAoTkpVMzcxMSkKKiBEaWdpdGFsXzEgICAgQ0sgICAoTkpVMzcxMSkKKiBEaWdpdGFsXzIgICAgU1coaW50ZXJycHV0aW5nKQoqIERpZ2l0YWxfMyAgICBOQwoqIERpZ2l0YWxfNCAgICBTVFIgIChOSlUzNzExKQoqIERpZ2l0YWxfNSAgICBOQwoqIERpZ2l0YWxfNiAgICBLYXRob2RlXzEgKFRyKQoqIERpZ2l0YWxfNyAgICBLYXRob2RlXzIgKFRyKQoqIERpZ2l0YWxfOCAgICBLYXRob2RlXzMgKFRyKQoqIERpZ2l0YWxfOSAgICBLYXRob2RlXzQgKFRyKQoqIERpZ2l0YWxfMTAgICBLYXRob2RlXzUgKFRyKQoqIERpZ2l0YWxfMTEgICBLYXRob2RlXzYgKFRyKQoqIERpZ2l0YWxfMTIgICBLYXRob2RlXzcgKFRyKQoqIERpZ2l0YWxfMTMgICBLYXRob2RlXzggKFRyKQoqLwogCiAKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCirjgIDjgIAg56uv5a2Q44CB5a6a5pWw44Gu5a6a576p44CA44Go44CA44OY44OD44OA44Gu44Kk44Oz44Kv44Or44O844OJICAqCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KI2luY2x1ZGUgPG1hdGguaD4gICAgIC8vIHNpbiwgY29zCgojZGVmaW5lIERBVEEgMCAgICAgIC8vIOOCt+ODleODiOODrOOCuOOCueOCv+OBruWItuW+oeODlOODs+OCkuWumue+qQojZGVmaW5lIENLICAgMSAgICAgIC8vCiNkZWZpbmUgU1RSICA0ICAgICAgLy8KI2RlZmluZSBXSURUSF8gICA4ICAvLyDjg57jg4jjg6rjgq/jgrlMRUTjga7jg4njg4Pjg4jmlbAKI2RlZmluZSBISUdIXyAgICA4ICAvLwojZGVmaW5lIFkwICAgNiAgICAgIC8vIFnou7jvvJDvvZ7vvJfliJfnm67jgavlr77lv5zjgZnjgovjg5Tjg7PjgpLlrprnvqkKI2RlZmluZSBZMSAgIDcgICAgICAvLwojZGVmaW5lIFkyICAgOCAgICAgIC8vCiNkZWZpbmUgWTMgICA5ICAgICAgLy8KI2RlZmluZSBZNCAgIDEwICAgICAvLwojZGVmaW5lIFk1ICAgMTEgICAgIC8vCiNkZWZpbmUgWTYgICAxMiAgICAgLy8KI2RlZmluZSBZNyAgIDEzICAgICAvLwoKI2RlZmluZSBVUEJVVFRPTiAgICAxNAojZGVmaW5lIERPV05CVVRUT04gIDE1CiNkZWZpbmUgTEVGVEJVVFRPTiAgMTYKI2RlZmluZSBSSUdIVEJVVFRPTiAxNwoKI2RlZmluZSBNT0RFTlVNICAgMyAgICAgLy8g55m76Yyy44Oi44O844OJ44Gu5pWwCgojZGVmaW5lIE1FTlUgICAgICAwICAgICAvLyDjg6Hjg4vjg6Xjg7wKI2RlZmluZSBST1VMRVRURSAgMSAgICAgLy8g44Or44O844Os44OD44OIKOODhOODvOODqykKI2RlZmluZSBIQVlBT1NISSAgMiAgICAgLy8g5pep5oq844GXKOOCsuODvOODoCkKCi8vI2RlZmluZSBNX1BJICAgIDMuMTQxNTkyNjUzNTg5NzkzMjM4NDYKI2RlZmluZSBTSU4oeCkgIHNpbih4ICogKE1fUEkvMTgwKSkKI2RlZmluZSBDT1MoeCkJY29zKHggKiAoTV9QSS8xODApKQoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCirjgIDjgIDjgIDjgIAgICDjgIAgIOOCsOODreODvOODkOODq+WkieaVsCAgICAgICAgICAgICAgICAgICAgKgoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCmNvbnN0IGNoYXIgemVyb1tISUdIX11bV0lEVEhfXSA9IHsgLy8g77yQCiAgICAgICAgICAgIHswLDAsMSwxLDEsMSwwLDB9LAogICAgICAgICAgICB7MCwxLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMSwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDEsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwxLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMSwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDEsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDEsMSwxLDEsMCwwfQp9Owpjb25zdCBjaGFyIG9uZVtISUdIX11bV0lEVEhfXSA9IHsgLy8g77yRCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMCwwfQp9Owpjb25zdCBjaGFyIHR3b1tISUdIX11bV0lEVEhfXSA9IHsgLy8g77ySCiAgICAgICAgICAgIHswLDAsMSwxLDEsMSwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDEsMSwxLDEsMCwwfSwKICAgICAgICAgICAgezAsMSwwLDAsMCwwLDAsMH0sCiAgICAgICAgICAgIHswLDEsMCwwLDAsMCwwLDB9LAogICAgICAgICAgICB7MCwwLDEsMSwxLDEsMCwwfQp9Owpjb25zdCBjaGFyIHRocmVlW0hJR0hfXVtXSURUSF9dID0geyAvLyDvvJMKICAgICAgICAgICAgezAsMCwxLDEsMSwxLDAsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMSwxLDEsMSwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMSwxLDEsMSwwLDB9Cn07Cgpjb25zdCBjaGFyIHlhamlydXNpW0hJR0hfXVtXSURUSF9dID0geyAgIC8vIOefouWNsAogICAgICAgICAgICB7MCwwLDAsMSwxLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwxLDEsMSwxLDAsMH0sCiAgICAgICAgICAgIHswLDEsMCwxLDEsMCwxLDB9LAogICAgICAgICAgICB7MSwwLDAsMSwxLDAsMCwxfSwKICAgICAgICAgICAgezAsMCwwLDEsMSwwLDAsMH0sCiAgICAgICAgICAgIHswLDAsMCwxLDEsMCwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMSwxLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDEsMSwwLDAsMH0KICAgICAgICAgIH07CgpjaGFyIGdyb3VuZFtISUdIX11bV0lEVEhfXSA9IHsgICAvLyDjgrDjg6njgqbjg7Pjg4kKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDAsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDAsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDAsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwwLDB9CiAgICAgICAgICB9OwogCmludCBpID0gMDsKaW50IG51bSA9IDAsIGZsYWcgPSAwOwp1bnNpZ25lZCBsb25nIHRpbWUgPSAwOy8vIOi1t+WLleW+jOOBruaZgumWk+OCkuiomOmMsuOBmeOCi+WkieaVsAppbnQgc3RhdGU7ICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOOBrumBuOaKnueUu+mdouOBrueKtuaFi+OCkuiomOaGtiAKaW50IG1vZGUgPSAwOyAgICAgICAgICAvLyDlrp/ooYzkuK3jga7jg6Ljg7zjg4njgpLoqJjmhrbvvIjjg6Hjg4vjg6Xjg7zjgIHjg6vjg7zjg6zjg4Pjg4jigKYpCmludCBpX2hheWFvc2kgPSAwOyAgICAgLy8g5pep5oq877ya5L2V5YCL55uu44Gu6KGo56S644GL44KS6KiY5oa244GZ44KLCmludCBtdWtpWzEwXTsgICAgICAgICAgLy8g5pep5oq877ya44Op44Oz44OA44Og44Gq55+i5Y2w44Gu5ZCR44GN44KS6KiY5oa2CmludCBjb250ZW50X2hheWEgPSAwOyAgLy8g5pep5oq877ya54q25oWL44KS6KiY5oa277yI44Kv44Oq44Ki44O744Of44K55YWl5Yqb77yJCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMDrliJ3mnJ/lgKQsIDE644Kv44Oq44KiLCAyOuODn+OCuQogCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgoq44CA44CA44CA44CAICAgICAgR1BJT+etieOBruWIneacn+ioreWumiAgICAgICAgICAgICAgICAgICAqCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8Kdm9pZCBzZXR1cCgpIAp7CiAgcGluTW9kZShEQVRBLCBPVVRQVVQpOyAgLy8gREFUQQogIHBpbk1vZGUoQ0ssIE9VVFBVVCk7ICAgIC8vIENLCiAgcGluTW9kZShTVFIsIE9VVFBVVCk7ICAgLy8gU1RSCiAgcGluTW9kZSgyLCBJTlBVVCk7ICAgICAgLy8g5aSJ5YyW5Ymy44KK6L6844G/IOW3puWPs+OCueOCpOODg+ODgeOBruirlueQhuWSjAogIAogIHBpbk1vZGUoWTAsIE9VVFBVVCk7ICAgIC8vIExFROOCouODjuODvOODieWBtOWItuW+oeODlOODswogIHBpbk1vZGUoWTEsIE9VVFBVVCk7ICAgIC8vCiAgcGluTW9kZShZMiwgT1VUUFVUKTsgICAgLy8KICBwaW5Nb2RlKFkzLCBPVVRQVVQpOyAgICAvLwogIHBpbk1vZGUoWTQsIE9VVFBVVCk7ICAgIC8vCiAgcGluTW9kZShZNSwgT1VUUFVUKTsgICAgLy8KICBwaW5Nb2RlKFk2LCBPVVRQVVQpOyAgICAvLwogIHBpbk1vZGUoWTcsIE9VVFBVVCk7ICAgIC8vCiAgCiAgcGluTW9kZSgxNCwgSU5QVVQpOyAgICAgLy8g44K544Kk44OD44OBKOS4iikKICBwaW5Nb2RlKDE1LCBJTlBVVCk7ICAgICAvLyDjgrnjgqTjg4Pjg4Eo5LiLKQogIHBpbk1vZGUoMTYsIElOUFVUKTsgICAgIC8vIOOCueOCpOODg+ODgSjlt6YpCiAgcGluTW9kZSgxNywgSU5QVVQpOyAgICAgLy8g44K544Kk44OD44OBKOWPsykKICBwaW5Nb2RlKDE4LCBJTlBVVCk7ICAgICAvLyDjg6njg7Pjg4Djg6DplqLmlbDjga7nqK4KIAogIC8vLS0g5aSJ5YyW5Ymy44KK6L6844G/44Gu5Yid5pyf6Kit5a6aCiAgYXR0YWNoSW50ZXJydXB0KDAsIGludGVycnVwdCwgUklTSU5HKTsgIC8vIDLnlarjg5Tjg7PjgpLlibLjgorovrzjgb/jgafkvb/nlKgKICAvLy0tCiAKICAvLy0tIOOCt+ODleODiOODrOOCuOOCueOCv+OBruWIneacn+ioreWumgogIGRpZ2l0YWxXcml0ZShTVFIsIEhJR0gpOyAgICAgICAgICAgLy8g44K344OV44OI44Os44K444K544K/44KS5Ye65Yqb44GX44Gq44GECiAgZGlnaXRhbFdyaXRlKERBVEEsIExPVyk7ICAgICAgICAgICAvLyDjgrfjg5Xjg4jjg6zjgrjjgrnjgr8g44OH44O844K/44KS77yQ44Kv44Oq44KiCiAgY2xvY2soKTsgY2xvY2soKTsgY2xvY2soKTsgY2xvY2soKTsvLwogIGNsb2NrKCk7IGNsb2NrKCk7IGNsb2NrKCk7IGNsb2NrKCk7Ly8KICBkaWdpdGFsV3JpdGUoU1RSLCBMT1cpOyAgICAgICAgICAgIC8vIOOCt+ODleODiOODrOOCuOOCueOCv+OCkuWHuuWKm+OBmeOCiwogIC8vLS0KICB0aW1lID0gbWlsbGlzKCk7ICAgICAgICAgICAgICAgICAgIC8vIOODl+ODreOCsOODqeODoOmWi+Wni+aZgumWk+OCkuiomOmMsgogIHJvbGwoZ3JvdW5kLCB6ZXJvLCAwKTsgICAgICAgICAgICAgLy8g6LW35YuV55u05b6M44Gu44Oh44OL44Ol44O844Gv77yQ44KS6KGo56S6CiAgc3RhdGUgPSAwOyAgICAgICAgICAgICAgICAgICAgICAgICAvLyDooajnpLrjgYzvvJDjgafjgYLjgovjgZPjgajjgpLoqJjmhrYKfQoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCirjgIDjgIDjgIDjgIAgICDjgIAgICAgbG9vcOmWouaVsCAgICAgICAgICAgICAgICAgICAgICAgICoKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwp2b2lkIGxvb3AoKSAKeyAKICBzd2l0Y2goc3RhdGUpewogICAgY2FzZSBNRU5VOgogICAgICBtZW51KCk7ICAgICAgLy/jg6Hjg4vjg6Xjg7zjgpLlrp/ooYwKICAgICAgYnJlYWs7CiAgICBjYXNlIFJPVUxFVFRFOgogICAgICByb3VsZXR0ZSgpOyAgLy8g44Or44O844Os44OD44OI44KS5a6f6KGMCiAgICAgIGJyZWFrOwogICAgY2FzZSBIQVlBT1NISToKICAgICAgaGF5YW9zaGkoKTsgIC8vIOaXqeaKvOOBl+OCsuODvOODoOOCkuWun+ihjAogICAgICBicmVhazsKICAgIGRlZmF1bHQ6CiAgICAgIGJyZWFrOwogIH0KfQoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCirjgIDjgIDjgIDjgIAgICDjgIAgIOODpuODvOOCtuODvOWumue+qemWouaVsCAgICAgICAgICAgICAgICAgICoKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwoKLy89PT09PT09PT09PT09PT09PSDjg6Eg44OLIOODpSAg44O8ID09PT09PT09PT09PT09PT09PT0Kdm9pZCBtZW51KCkKewogIHN0YXRpYyBpbnQgc3RhdGUxID0gMDsgICAgICAgIC8vIOWIneacn+eKtuaFi+OBryfvvJAn44KS6KGo56S644GX44Gm44GE44KL44Gu44Gn77yQ44KS5Luj5YWlCiAgd2hpbGUoZmxhZyA9PSAwKXsgICAgICAgICAgICAgLy8g44Oh44OL44Ol44O844GM6YG45oqe44GV44KM44Gq44GE6ZmQ44KK44Or44O844OXCiAgICBpZihzdGF0ZTEgIT0gc3RhdGUpeyAgICAgICAgLy8g54++5Zyo44Gu6KGo56S644OH44O844K/44Go55Ww44Gq44KL5aC05ZCICiAgICAgIHN3aXRjaChzdGF0ZSl7CiAgICAgICAgY2FzZSAwOiAgICAgICAgICAgICAgICAgLy8g44Oh44OL44Ol44O877yQ44Gq44KJ44GwCiAgICAgICAgICBzdGF0ZTEgPSAwOyAgICAgICAgICAgLy8g54++5Zyo44Gu5pWw5a2X44KSICfvvJAnIOOBq+WkieabtAogICAgICAgICAgcm9sbChncm91bmQsIHplcm8sIDApOy8vIOihqOekuuODh+ODvOOCv+OCkiAn77yQJyDjgavlpInmm7QKICAgICAgICAgIGJyZWFrOwogICAgICAgIGNhc2UgMToKICAgICAgICAgIHN0YXRlMSA9IDE7ICAgICAgICAgICAvLyDnj77lnKjjga7mlbDlrZfjgpIgJ++8kScg44Gr5aSJ5pu0CiAgICAgICAgICByb2xsKGdyb3VuZCwgb25lLCAwKTsgLy8g6KGo56S644OH44O844K/44KSICfvvJEnIOOBq+WkieabtAogICAgICAgICAgYnJlYWs7CiAgICAgICAgY2FzZSAyOgogICAgICAgICAgc3RhdGUxID0gMjsgICAgICAgICAgIC8vIOePvuWcqOOBruaVsOWtl+OCkiAn77ySJyDjgavlpInmm7QKICAgICAgICAgIHJvbGwoZ3JvdW5kLCB0d28sIDApOyAvLyDooajnpLrjg4fjg7zjgr/jgpIgJ++8kicg44Gr5aSJ5pu0CiAgICAgICAgICBicmVhazsKICAgICAgfQogICAgfQogICAgZHJhd19ncm91bmQoKTsgICAgICAgICAgICAgIC8vIOmBuOaKnuS4reOBrueVquWPt+OCkuihqOekuuOBmeOCiwogIH0KICAKICByZXR1cm47Cn0KCi8vPT09PT09PT09PT09PT09IOODqyDjg7wg44OsIOODgyDjg4gg44GuIOWHpiDnkIYgPT09PT09PT09PT09PT09PT09PQp2b2lkIHJvdWxldHRlKCkKewogIGludCBhbmdsZTsKICBpbnQgaSwgdGltZTsKICAKICByYW5kb21TZWVkKGFuYWxvZ1JlYWQoMTgpKTsgICAgIC8vIOODqeODs+ODgOODoOmWouaVsOOBrueoruOBvuOBjQogIGFuZ2xlID0gOTAgKiByYW5kb20oMCwgNCk7ICAgICAgLy8g5YGc5q2i6KeS5bqm44KS5rG644KB44KLKDkwfjM2MCkKICB0aW1lID0gbWlsbGlzKCk7CiAgcm9sbChncm91bmQsIHlhamlydXNpLCAwKTsKICB3aGlsZShtaWxsaXMoKSAtIHRpbWUgPCAyMDAwKXsgIC8vIO+8kuenkumWk+OCgeOBoeOCg+OBj+OBoeOCg+OBquihqOekugogICAgcm9sbChncm91bmQsIHlhamlydXNpLCA5MCAqIHJhbmRvbSgwLDQpKTsKICAgIGRyYXdfZ3JvdW5kKCk7CiAgfQogIHJvbGwoZ3JvdW5kLCB5YWppcnVzaSwgYW5nbGUpOwogIAogIGZvcihpID0gMDsgaSA8IDEwMDsgaSsrKXsgICAgICAgLy8g5rG65a6a44GX44Gf54q25oWL44KS44GX44Gw44KJ44GP6KGo56S6CiAgICBkcmF3X2dyb3VuZCgpOwogIH0KICBmbGFnID0gMDsgICAgICAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOeUu+mdouOCkuODq+ODvOODl+OBmeOCi+OCiOOBhuODleODqeOCsOOCkueri+OBpuOCiwogIHN0YXRlID0gTUVOVTsgICAgICAgICAgICAgICAgICAgLy8g44Oh44OL44Ol44O855S76Z2i44G456e76KGMCiAgcmV0dXJuOwp9CgovLz09PT09PT09PT09PT09PSDml6kg5oq8IOOBlyDjgrIg44O8IOODoCDjga4g5YemIOeQhiA9PT09PT09PT09PT09PT09PT09CnZvaWQgaGF5YW9zaGkoKQp7CiAgaW50IHRpbWUsIGNvbnRlbnQsIGk7CiAgcmFuZG9tU2VlZChhbmFsb2dSZWFkKDE4KSk7ICAgLy8g44Op44Oz44OA44Og6Zai5pWw44Gu56iu44G+44GNCiAgLy8tLSAgICDnn6LljbDjgpLmsbrjgoHjgovjg5Hjg6njg6Hjg7zjgr/jgpLvvJHvvJDlgIvlvpfjgosKICBmb3IoaSA9IDA7IGkgPCAxMDsgaSsrKXsKICAgIG11a2lbaV0gPSByYW5kb20oMCwgNCk7ICAgICAgIC8vIO+8kO+9nu+8k+OBruWApOOCkuW+l+OCiwogIH0KCiAgLy8tLSAgICDplovlp4vjgb7jgafjga7jgqvjgqbjg7Pjg4jlh6bnkIYgCiAgdGltZSA9IG1pbGxpcygpOyAgICAgICAgICAgICAgICAvLyDnj77lnKjjga7mmYLplpPjgpLoqJjpjLIKICB3aGlsZSgxKXsKICAgIGNvbnRlbnQgPSBtaWxsaXMoKSAtIHRpbWU7ICAgIC8vIOe1jOmBjuaZgumWk+OCkuW+l+OCiyhtcykKICAgIGlmKGNvbnRlbnQgPiAzMDAwKXsgICAgICAgICAgIC8vIO+8k+enkuS7peS4iue1jOmBjgogICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAgLy8g44Ky44O844Og44G456e76KGMCiAgICB9ZWxzZSBpZihjb250ZW50ID4gMjAwMCl7ICAgICAvLyDvvJLnp5Lku6XkuIrntYzpgY4o77yR44KS6KGo56S6KQogICAgICByb2xsKGdyb3VuZCwgb25lLCAwKTsKICAgIH1lbHNlIGlmKGNvbnRlbnQgPiAxMDAwKXsgICAgIC8vIO+8keenkuS7peS4iue1jOmBjijvvJLjgpLooajnpLopCiAgICAgIHJvbGwoZ3JvdW5kLCB0d28sIDApOyAgICAgICAvLyDooajnpLrjg4fjg7zjgr/jgavvvJLjgpLjgrvjg4Pjg4gKICAgIH1lbHNleyAgICAgICAgICAgICAgICAgICAgICAgIC8vIO+8kOenkuS7peS4iue1jOmBjijvvJPjgpLooajnpLopCiAgICAgIHJvbGwoZ3JvdW5kLCB0aHJlZSwgMCk7ICAgICAvLyDooajnpLrjg4fjg7zjgr/jgavvvJPjgpLjgrvjg4Pjg4gKICAgIH0KICAgIGRyYXdfZ3JvdW5kKCk7ICAgICAgICAgICAgICAgIC8vCiAgfQogIAogIC8vLS0gICAg44Ky44O844Og6ZaL5aeLCiAvLyB0aW1lID0gbWlsbGlzKCk7ICAgICAgICAgICAgICAgIC8vIOOCsuODvOODoOmWi+Wni+OBruaZgumWk+OCkuW+l+OCiwogIG11a2lbMF0gPSAwOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy/jg4fjg5Djg4PjgrDnlKjjgavlv4XjgZrkuIrlkJHjgY3jgaflh7rjgovjgojjgYboqK3lrpoKICByb2xsKGdyb3VuZCwgeWFqaXJ1c2ksIG11a2lbaV9oYXlhb3NpXSAqIDkwKTsgIC8vIOacgOWIneOBruefouWNsOOCkuihqOekugogIAogIHdoaWxlKDEpeyAgICAgICAgICAgICAgICAgICAgICAgLy8g44GT44Gu44Or44O844OX5YaF44Gn44Ky44O844Og44KS5Yem55CG44GZ44KLCiAgICBpZihjb250ZW50X2hheWEgPT0gMSl7ICAgICAgICAvLyDjgrLjg7zjg6Djgq/jg6rjgqLjga7loLTlkIgKICAgICAgLy9nYW1lY2xlYXIoKTsgICAgICAgICAgICAgIC8vIOOCr+ODquOCouOBl+OBn+aZgumWk+OCkuWHuuWKmyDlvJXmlbDjga/jgr/jgqTjg6AKICAgICAgYnJlYWs7CiAgICB9ZWxzZSBpZihjb250ZW50X2hheWEgPT0gMil7ICAvLyDjgrLjg7zjg6DlpLHmlZfjga7loLTlkIgKICAgICAgLy9nYW1lcmV0aXJlZCgpOyAgICAgICAgICAgIC8vIOWkseaVl+OBruihqOekugogICAgICBicmVhazsKICAgIH0KICAgIGRyYXdfZ3JvdW5kKCk7CiAgfQogIAogIC8vLS0gICAg5b6M5Yem55CGCiAgZmxhZyA9IDA7ICAgICAgICAgICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7znlLvpnaLjgpLjg6vjg7zjg5fjgZnjgovjgojjgYbjg5Xjg6njgrDjgpLnq4vjgabjgosKICBzdGF0ZSA9IE1FTlU7ICAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOeUu+mdouOBuOenu+ihjAogIGlfaGF5YW9zaSA9IDA7ICAgICAgICAgICAgICAgICAgLy8g44Ky44O844Og44Gu44OX44Os44Kk5oOF5aCx44KS5Yid5pyf5YyWCiAgY29udGVudF9oYXlhID0gMDsKfQoKLy89PT09PT09PT09PT09PT09PT09IOOCueOCpOODg+ODgSDlibIg44KKIOi+vCDjgb8g5YemIOeQhiA9PT09PT09PT09PT09PT09PT09CnZvaWQgaW50ZXJydXB0KCkKewogIHN0YXRpYyBpbnQgYW5nbGUgPSAwOwogIHVuc2lnbmVkIGxvbmcgdGltZTIgPSBtaWxsaXMoKTsgICAgICAgICAgICAgICAgICAgICAgICAgLy8g44OB44Oj44K/44Oq44Oz44Kw6Ziy5q2i44Gu5Yem55CGCiAgaWYodGltZTIgLSB0aW1lIDwgNTApIHJldHVybjsgICAgICAgICAgICAgICAgICAgICAgICAgICAvLwogIAogIGlmKGRpZ2l0YWxSZWFkKFVQQlVUVE9OKSl7ICAgICAgICAgIC8vLS0tLS3kuIrjg5zjgr/jg7PjgYzmirzjgZXjgozjgZ/jgarjgonjgbAtLS0tLQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g44Oh44OL44Ol44O86KGo56S65Lit44Gu5Yem55CGCiAgICAgaWYoZmxhZyAhPSAxICYmIHN0YXRlICE9IDApeyAgICAgICAgICAgICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7znlLvpnaLku6XlpJbjga7jgrLjg7zjg6DjgYzntYLkuobjgZfjgabjgYTjgozjgbDlrp/ooYwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOmBuOaKnuS4reOBruODoeODi+ODpeODvOOCkuaxuuWumuOBmeOCiwogICAgICAgZmxhZyA9IDE7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g44Oh44OL44Ol44O855S76Z2i44KS5oqc44GR44KL44OV44Op44Kw44KS56uL44Gm44KLCiAgICAgICByZXR1cm47CiAgICAgfWVsc2UgaWYoc3RhdGUgPT0gSEFZQU9TSEkpeyAgICAgICAgICAgICAgICAgICAgICAgICAvLyDil4vml6nmirzjgZfjgrLjg7zjg6Djgafjga7lh6bnkIYKICAgICAgIGlmKG11a2lbaV9oYXlhb3NpXSA9PSAwKXsKICAgICAgICAgaV9oYXlhb3NpICs9IDE7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOasoeOBruefouWNsOOBruODkeODqeODoeODvOOCv+OBuOWKoOeulwogICAgICAgICByb2xsKGdyb3VuZCwgeWFqaXJ1c2ksIG11a2lbaV9oYXlhb3NpXSAqIDkwKTsgICAgLy/nn6LljbDjgpLmrKHjga7nn6LljbDjgavmm7TmlrAKICAgICAgICAgaWYoaV9oYXlhb3NpID09IDEwKSBjb250ZW50X2hheWEgPSAxOyAgICAgICAgICAgIC8vIOOCsuODvOODoOOCr+ODquOCouOCkuaVmeOBiOOCiwogICAgICAgfWVsc2V7CiAgICAgICAgIGNvbnRlbnRfaGF5YSA9IDI7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDjgrLjg7zjg6DlpLHmlZfjgpLmlZnjgYjjgosKICAgICAgIH0KICAgICB9IAogIH1lbHNlIGlmKGRpZ2l0YWxSZWFkKERPV05CVVRUT04pKXsgICAvLy0tLS0t5LiL44Oc44K/44Oz44GM5oq844GV44KM44Gf44Gq44KJ44GwLS0tLS0KICAgIGlmKCBmbGFnID09IDAgKSByZXR1cm47ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOeUu+mdouS4iuOBp+OBruWFpeWKm+OBr+eEoeWKuQogICAgCiAgICBpZiggc3RhdGUgPT0gSEFZQU9TSEkpeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDil4vml6nmirzjgZfjgrLjg7zjg6Djgafjga7lh6bnkIYKICAgICAgIGlmKG11a2lbaV9oYXlhb3NpXSA9PSAyKXsKICAgICAgICAgaV9oYXlhb3NpICsrOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOasoeOBruefouWNsOOBruODkeODqeODoeODvOOCv+OBuOWKoOeulwogICAgICAgICByb2xsKGdyb3VuZCwgeWFqaXJ1c2ksIG11a2lbaV9oYXlhb3NpXSAqIDkwKTsgICAgLy/nn6LljbDjgpLmrKHjga7nn6LljbDjgavmm7TmlrAKICAgICAgICAgaWYoaV9oYXlhb3NpID09IDEwKSBjb250ZW50X2hheWEgPSAxOyAgICAgICAgICAgIC8vIOOCsuODvOODoOOCr+ODquOCouOCkuaVmeOBiOOCiwogICAgICAgfWVsc2V7CiAgICAgICAgIGNvbnRlbnRfaGF5YSA9IDI7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDjgrLjg7zjg6DlpLHmlZfjgpLmlZnjgYjjgosKICAgICAgIH0KICAgICB9IAogIH1lbHNlIGlmKGRpZ2l0YWxSZWFkKExFRlRCVVRUT04pKXsgICAgLy8tLS0tLeW3puODnOOCv+ODs+OBjOaKvOOBleOCjOOBn+OBquOCieOBsC0tLS0tCiAgICAgaWYoZmxhZyAhPSAxICYmIHN0YXRlID4gMCl7ICAgICAgICAgICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7zooajnpLrkuK3jga7lh6bnkIYKICAgICAgIHN0YXRlIC0tOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOOCku+8je+8keOBmeOCiwogICAgIH1lbHNlIGlmKHN0YXRlID09IEhBWUFPU0hJKXsgICAgICAgICAgICAgICAgICAgICAgICAgLy8g4peL5pep5oq844GX44Ky44O844Og44Gn44Gu5Yem55CGCiAgICAgICBpZihtdWtpW2lfaGF5YW9zaV0gPT0gMyl7CiAgICAgICAgIGlfaGF5YW9zaSArKzsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDmrKHjga7nn6LljbDjga7jg5Hjg6njg6Hjg7zjgr/jgbjliqDnrpcKICAgICAgICAgcm9sbChncm91bmQsIHlhamlydXNpLCBtdWtpW2lfaGF5YW9zaV0gKiA5MCk7ICAgIC8v55+i5Y2w44KS5qyh44Gu55+i5Y2w44Gr5pu05pawCiAgICAgICAgIGlmKGlfaGF5YW9zaSA9PSAxMCkgY29udGVudF9oYXlhID0gMTsgICAgICAgICAgICAvLyDjgrLjg7zjg6Djgq/jg6rjgqLjgpLmlZnjgYjjgosKICAgICAgIH1lbHNlewogICAgICAgICBjb250ZW50X2hheWEgPSAyOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g44Ky44O844Og5aSx5pWX44KS5pWZ44GI44KLCiAgICAgICB9CiAgICAgfQogIH1lbHNlIGlmKGRpZ2l0YWxSZWFkKFJJR0hUQlVUVE9OKSl7Ly8tLS0tLeWPs+ODnOOCv+ODs+OBjOaKvOOBleOCjOOBn+OBquOCieOBsC0tLS0tCiAgICAgaWYoZmxhZyAhPSAxICYmIHN0YXRlIDwgTU9ERU5VTS0xKXsgICAgICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7zooajnpLrkuK3jga7lh6bnkIYKICAgICAgIHN0YXRlICsrOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOOCku+8i++8keOBmeOCiwogICAgIH1lbHNlIGlmKHN0YXRlID09IEhBWUFPU0hJKXsgICAgICAgICAgICAgICAgICAgICAgICAgLy8g4peL5pep5oq844GX44Ky44O844Og44Gn44Gu5Yem55CGCiAgICAgICBpZihtdWtpW2lfaGF5YW9zaV0gPT0gMSl7CiAgICAgICAgIGlfaGF5YW9zaSArKzsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDmrKHjga7nn6LljbDjga7jg5Hjg6njg6Hjg7zjgr/jgbjliqDnrpcKICAgICAgICAgcm9sbChncm91bmQsIHlhamlydXNpLCBtdWtpW2lfaGF5YW9zaV0gKiA5MCk7ICAgIC8v55+i5Y2w44KS5qyh44Gu55+i5Y2w44Gr5pu05pawCiAgICAgICAgIGlmKGlfaGF5YW9zaSA9PSAxMCkgY29udGVudF9oYXlhID0gMTsgICAgICAgICAgICAvLyDjgrLjg7zjg6Djgq/jg6rjgqLjgpLmlZnjgYjjgosKICAgICAgIH1lbHNlewogICAgICAgICBjb250ZW50X2hheWEgPSAyOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOOCsuODvOODoOWkseaVl+OCkuaVmeOBiOOCiwogICAgICAgfQogICAgIH0KICB9CiAgdGltZSA9IHRpbWUyOwp9IAoKLy89PT09PT09PT09PT09PT09PT09Z3JvdW5k6YWN5YiX44KS44Oe44OI44Oq44Kv44K5TEVE44Gr5o+P55S7PT09PT09PT09PT09PT09PT09PQp2b2lkIGRyYXdfZ3JvdW5kKCkKewogIGZvcihpbnQgaSA9IDA7IGkgPCA4OyBpKyspeyAgICAgIC8vIO+8mOWIl+WIhuWIl+OCouODjuODvOODieWBtOOCkuOCt+ODleODiOOBleOBm+OCi+OAggogICAgaWYoaT09MCl7ICAgICAgICAgICAgICAgICAgICAgIC8vIO+8keWIl+ebruOBjOWPgueFp+OBleOCjOOBpuOBhOOBn+OBquOCieOBsAogICAgICBkaWdpdGFsV3JpdGUoREFUQSwgSElHSCk7ICAgIC8vIEhJR0jjgpLjgrvjg4Pjg4jjgZfjgabjgrfjg5Xjg4gKICAgICAgY2xvY2soKTsKICAgIH1lbHNleyAgICAgICAgICAgICAgICAgICAgICAgICAvLyDvvJLliJfnm67ku6XpmY3jgYzlj4LnhafjgZXjgozjgabjgYTjgZ/jgarjgonjgbAKICAgICAgZGlnaXRhbFdyaXRlKERBVEEsIExPVyk7ICAgICAvLyDpoIbmrKFMT1fjgpLjgrvjg4Pjg4jjgZfjgabjgrfjg5Xjg4gKICAgICAgY2xvY2soKTsKICAgIH0KICAgIGRpZ2l0YWxXcml0ZShZMCwgKGdyb3VuZFswXVtpXT09MSk/SElHSDpMT1cpOwogICAgZGlnaXRhbFdyaXRlKFkxLCAoZ3JvdW5kWzFdW2ldPT0xKT9ISUdIOkxPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTIsIChncm91bmRbMl1baV09PTEpP0hJR0g6TE9XKTsKICAgIGRpZ2l0YWxXcml0ZShZMywgKGdyb3VuZFszXVtpXT09MSk/SElHSDpMT1cpOwogICAgZGlnaXRhbFdyaXRlKFk0LCAoZ3JvdW5kWzRdW2ldPT0xKT9ISUdIOkxPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTUsIChncm91bmRbNV1baV09PTEpP0hJR0g6TE9XKTsKICAgIGRpZ2l0YWxXcml0ZShZNiwgKGdyb3VuZFs2XVtpXT09MSk/SElHSDpMT1cpOwogICAgZGlnaXRhbFdyaXRlKFk3LCAoZ3JvdW5kWzddW2ldPT0xKT9ISUdIOkxPVyk7CiAgICBkZWxheSgyKTsKICAgIHdpcGVfb3V0X3NoYWRvdygpOyAgICAgICAgICAgICAgLy8g5YiX44KS5YiH44KK5pu/44GI44KL5YmN44Gr6KGo56S644KS5raI44GZ44GT44Go44Gn5q6L5YOP5Yem55CGCiAgfQp9CgovLz09PT09PT09PT09PT09PT09PT3jgrfjg5Xjg4jjg6zjgrjjgrnjgr/jgbjjga7jgq/jg63jg4Pjgq/lh6bnkIY9PT09PT09PT09PT09PT09PT09CnZvaWQgY2xvY2soKQp7CiAgZGlnaXRhbFdyaXRlKENLLCBMT1cpOwogIGRlbGF5TWljcm9zZWNvbmRzKDUpOwogIGRpZ2l0YWxXcml0ZShDSywgSElHSCk7CiAgZGVsYXlNaWNyb3NlY29uZHMoNSk7CiAgZGlnaXRhbFdyaXRlKENLLCBMT1cpOwp9CgovLz09PT09PT09PT09PT09PT09PT3jg4njg4Pjg4jjg57jg4jjg6rjgq/jgrlMRUTjga7mrovlg4/lh6bnkIY9PT09PT09PT09PT09PT09PT09CnZvaWQgd2lwZV9vdXRfc2hhZG93KCkKewogICAgZGlnaXRhbFdyaXRlKFkwLCBMT1cpOwogICAgZGlnaXRhbFdyaXRlKFkxLCBMT1cpOwogICAgZGlnaXRhbFdyaXRlKFkyLCBMT1cpOwogICAgZGlnaXRhbFdyaXRlKFkzLCBMT1cpOwogICAgZGlnaXRhbFdyaXRlKFk0LCBMT1cpOwogICAgZGlnaXRhbFdyaXRlKFk1LCBMT1cpOwogICAgZGlnaXRhbFdyaXRlKFk2LCBMT1cpOwogICAgZGlnaXRhbFdyaXRlKFk3LCBMT1cpOwp9CgovLz09PT09PeW8leaVsOOBruihqOekuuODh+ODvOOCv+OCkuS7u+aEj+OBruinkuW6puOBq+Wbnui7ouOBl+OBpmdyb3VuZOmFjeWIl+OBq+OCu+ODg+ODiD09PT09CnZvaWQgcm9sbChjaGFyIHRvW11bOF0sIGNvbnN0IGNoYXIgZnJvbVtdWzhdLCBpbnQgYW5nbGUpCnsKICBpbnQgeCwgeTsKICBkb3VibGUgeDEgPSAwLjAsIHkxID0gMC4wOwogIGlmKGFuZ2xlID09IDApeyAgICAgICAvLyDlm57ou6Lop5LluqbjgYzvvJDjgarjgonlm57ou6Llh6bnkIbjga/ooYzjgo/jgarjgYQKICAgIGZvciAoeSA9IDA7IHkgPCA4OyB5KyspewogICAgICBmb3IgKHggPSAwOyB4IDwgODsgeCsrKXsKICAgICAgICB0b1t5XVt4XSA9IGZyb21beV1beF07CiAgICAgIH0KICAgIH0KICB9ZWxzZXsgICAgICAgICAgICAgICAgLy8g5Zue6Lui5Yem55CGCiAgICBmb3IgKHkgPSAwOyB5IDwgODsgeSsrKXsKICAgICAgZm9yICh4ID0gMDsgeCA8IDg7IHgrKyl7CiAgICAgICAgeDEgPSAoKHggLSAzLjUpICogQ09TKGFuZ2xlKSAtICh5IC0gMy41KSAqIFNJTihhbmdsZSkpOwogICAgICAgIHkxID0gKCh4IC0gMy41KSAqIFNJTihhbmdsZSkgKyAoeSAtIDMuNSkgKiBDT1MoYW5nbGUpKTsKICAgICAgICB4MSA9IHgxICsgMy41OwkvLyDjgZrjgonjgZfjgZ/luqfmqJnjgpLkv67mraMKICAgICAgICB5MSA9IHkxICsgMy41OwkvLwogICAgICAgIAogICAgICAgIGlmIChmcm9tW3ldW3hdID09IDEpewogICAgICAgICAgaWYgKChpbnQpKHgxICsgMC41KSA8IFdJRFRIXyAmJiAoaW50KSh5MSArIDAuNSkgPCBISUdIXykgdG9bKGludCkoeTEgKyAwLjUpXVsoaW50KSh4MSArIDAuNSldID0gMTsKICAgICAgICB9ZWxzZXsKICAgICAgICAgIGlmICgoaW50KSh4MSArIDAuNSkgPCBXSURUSF8gJiYgKGludCkoeTEgKyAwLjUpIDwgSElHSF8pIHRvWyhpbnQpKHkxICsgMC41KV1bKGludCkoeDEgKyAwLjUpXSA9IDA7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfQp9