// ルーレットが完成
/* pin assign
* Digital_0 serial.begin で使用?(RX)
* Digital_1 serial.begin で使用?(TX)
* Digital_2 SW(interrputing)
* Digital_3 DATA (NJU3711)
* Digital_4 STR (NJU3711)
* Digital_5 CK (NJU3711)
* 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 3
#define STR 4 //
#define CK 5
#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 }
} ;
const char A[ HIGH_] [ WIDTH_] = { // A
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 } ,
{ 0 , 1 , 1 , 1 , 1 , 1 , 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 }
} ;
const char M[ HIGH_] [ WIDTH_] = { // M
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 } ,
{ 0 , 1 , 0 , 1 , 1 , 0 , 1 , 0 } ,
{ 0 , 1 , 0 , 1 , 1 , 0 , 1 , 0 } ,
{ 0 , 1 , 0 , 1 , 1 , 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 }
} ;
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 }
} ;
volatile int flag = 0 ; // メニュートップ画面?で使用したような
volatile int permission_sw = 0 ; // スイッチの入力の禁止と許可を制御(1:許可)
volatile unsigned long time = 0 ; // 起動後の時間を記録する変数 volatile int state; // メニューの選択画面の状態を記憶
volatile int i_hayaosi = 0 ; // 早押:何個目の表示かを記憶する
volatile int content_haya = 0 ; // 早押:状態を記憶(クリア・ミス入力)
// 0:初期値, 1:クリア, 2:ミス
int muki[ 10 ] ; // 早押:ランダムな矢印の向きを記憶
/**************************************************
* GPIO等の初期設定 *
***************************************************/
void setup( )
{
pinMode( DATA, OUTPUT) ; // DATA
pinMode( CK, OUTPUT) ; // CK
pinMode( STR, OUTPUT) ; // STR
pinMode( 0 , INPUT) ; // RX
pinMode( 1 , OUTPUT) ; // TX
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番ピンを割り込みで使用
permission_sw = 1 ; // 割り込みを許可
//--
//-- シフトレジスタの初期設定
digitalWrite( STR, HIGH) ; // シフトレジスタを出力しない
digitalWrite( DATA, LOW) ; // シフトレジスタ データを0クリア
digitalWrite( STR, LOW) ; // シフトレジスタを出力する
//--
//time = millis(); // プログラム開始時間を記録
Serial.begin ( 9600 ) ;
startup( ) ; // 起動時にAMAと図々しく表示
roll( ground, zero, 0 ) ; // 起動直後のメニューは0を表示
state = 0 ; // 表示が0であることを記憶
}
/**************************************************
* loop関数 *
***************************************************/
void loop( )
{
switch ( state) {
case MENU:
menu( ) ; //メニューを実行
break ;
case ROULETTE:
roulette( ) ; // ルーレットを実行
break ;
case HAYAOSHI:
hayaoshi( ) ; // 早押しゲームを実行
flag = 0 ; // メニュー画面をループするようフラグを立てる
state = MENU; // メニュー画面へ移行
i_hayaosi = 0 ; // ゲームのプレイ情報を初期化
content_haya = 0 ;
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 startup( )
{
int angle = 0 ;
unsigned long time , margin
;
for ( angle = 0 ; angle <= 360 ; angle+= 10 ) {
roll( ground, A, angle) ;
draw_ground( ) ;
}
while ( 1 ) {
margin
= millis
( ) - time ; if ( margin > 500 ) break ;
draw_ground( ) ;
}
for ( angle = 0 ; angle <= 360 ; angle+= 10 ) {
roll( ground, M, angle) ;
draw_ground( ) ;
}
while ( 1 ) {
margin
= millis
( ) - time ; if ( margin > 500 ) break ;
draw_ground( ) ;
}
for ( angle = 0 ; angle <= 360 ; angle+= 10 ) {
roll( ground, A, angle) ;
draw_ground( ) ;
}
while ( 1 ) {
margin
= millis
( ) - time ; if ( margin > 500 ) break ;
draw_ground( ) ;
}
}
//=============== ル ー レ ッ ト の 処 理 ===================
void roulette( )
{
int angle;
int i, time_r;
int margin;
permission_sw = 0 ; // スイッチ入力を禁止
randomSeed( analogRead( 18 ) ) ; // ランダム関数の種まき
angle = 90 * random( 0 , 4 ) ; // 停止角度を決める(90~360)
time_r = millis( ) ;
roll( ground, yajirusi, 0 ) ;
time_r = millis( ) ;
while ( 1 ) { // 2秒間めちゃくちゃな表示
margin = millis( ) - time_r;
if ( margin > 2000 ) break ; // 2秒以上経過で結果表示へ移行
delayMicroseconds( 10 ) ;
roll( ground, yajirusi, 90 * random( 0 , 4 ) ) ;
draw_ground( ) ;
}
roll( ground, yajirusi, angle) ;
for ( i = 0 ; i < 100 ; i++ ) { // 決定した状態をしばらく表示
delayMicroseconds( 100 ) ;
draw_ground( ) ;
}
flag = 0 ; // メニュー画面をループするようフラグを立てる
state = MENU; // メニュー画面へ移行
permission_sw = 1 ; // スイッチ入力を許可
return ;
}
//=============== 早 押 し ゲ ー ム の 処 理 ===================
void hayaoshi( )
{
int i;
unsigned long time_haya, margin;
permission_sw = 0 ; // スイッチ入力を禁止
randomSeed( analogRead( 18 ) ) ; // ランダム関数の種まき
//-- 矢印を決めるパラメータを10個得る
for ( i = 0 ; i < 5 ; i++ ) {
muki[ i] = random( 0 , 4 ) ; // 0~3の値を得る
}
//-- 開始までのカウント処理
time_haya = millis( ) ; // 現在の時間を記録
while ( 1 ) {
margin = millis( ) - time_haya; // 経過時間を得る(ms)
if ( margin > 3000 ) { // 3秒以上経過
break ; // ゲームへ移行
} else if ( margin > 2000 ) { // 2秒以上経過(1を表示)
roll( ground, one, 0 ) ;
} else if ( margin > 1000 ) { // 1秒以上経過(2を表示)
roll( ground, two, 0 ) ; // 表示データに2をセット
} else { // 0秒以上経過(3を表示)
roll( ground, three, 0 ) ; // 表示データに3をセット
}
draw_ground( ) ; //
}
permission_sw = 1 ; // スイッチ入力を許可
//-- ゲーム開始
time_haya = millis( ) ; // ゲーム開始の時間を得る
roll( ground, yajirusi, muki[ i_hayaosi] * 90 ) ; // 最初の矢印を表示
while ( 1 ) { // このループ内でゲームを処理する
draw_ground( ) ;
if ( content_haya == 1 ) { // ゲームクリアの場合
//gameclear(); // クリアした時間を出力 引数はタイム
margin = millis( ) - time_haya; //クリアまでの経過時間を算出
Serial.println ( margin) ;
break ;
}
else if ( content_haya == 2 ) { // ゲーム失敗の場合
//gameretired(); // 失敗の表示
break ;
}
}
}
//=================== スイッチ 割 り 込 み 処 理 ===================
void interrupt( )
{
static int angle = 0 ;
unsigned long time2 = millis( ) ;
if ( permission_sw == 0 ) return ; // スイッチ入力が許可されていなければリターン
if ( time2
- time < 200 ) return ; // 前回の割り込み時間から100ms以上経過しているか
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 == 5 ) 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 == 5 ) content_haya = 1 ; // ゲームクリアを教える
} else {
content_haya = 2 ; // ゲーム失敗を教える
}
}
} else if ( digitalRead( LEFTBUTTON) ) { //-----左ボタンが押されたならば-----
if ( state > 0 && flag == 0 ) { // メニュー表示中の処理
state --; // メニューを-1する
} else if ( state == HAYAOSHI && flag == 1 ) { // ○早押しゲームでの処理
if ( muki[ i_hayaosi] == 3 ) {
i_hayaosi ++; // 次の矢印のパラメータへ加算
roll( ground, yajirusi, muki[ i_hayaosi] * 90 ) ; //矢印を次の矢印に更新
if ( i_hayaosi == 5 ) content_haya = 1 ; // ゲームクリアを教える
} else {
content_haya = 2 ; // ゲーム失敗を教える
}
}
} else if ( digitalRead( RIGHTBUTTON) ) { //-----右ボタンが押されたならば-----
if ( state < MODENUM- 1 && flag == 0 ) { // メニュー表示中の処理
state ++; // メニューを+1する
} else if ( state == HAYAOSHI && flag == 1 ) { // ○早押しゲームでの処理
if ( muki[ i_hayaosi] == 1 ) {
i_hayaosi ++; // 次の矢印のパラメータへ加算
roll( ground, yajirusi, muki[ i_hayaosi] * 90 ) ; //矢印を次の矢印に更新
if ( i_hayaosi == 5 ) 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 ;
}
}
}
}
}
Ly8g44Or44O844Os44OD44OI44GM5a6M5oiQCgovKiAgICAgIHBpbiBhc3NpZ24KKiBEaWdpdGFsXzAgICAgc2VyaWFsLmJlZ2luIOOBp+S9v+eUqO+8nyhSWCkKKiBEaWdpdGFsXzEgICAgc2VyaWFsLmJlZ2luIOOBp+S9v+eUqO+8nyhUWCkKKiBEaWdpdGFsXzIgICAgU1coaW50ZXJycHV0aW5nKQoqIERpZ2l0YWxfMyAgICBEQVRBIChOSlUzNzExKQoqIERpZ2l0YWxfNCAgICBTVFIgIChOSlUzNzExKQoqIERpZ2l0YWxfNSAgICBDSyAgIChOSlUzNzExKQoqIERpZ2l0YWxfNiAgICBLYXRob2RlXzEgKFRyKQoqIERpZ2l0YWxfNyAgICBLYXRob2RlXzIgKFRyKQoqIERpZ2l0YWxfOCAgICBLYXRob2RlXzMgKFRyKQoqIERpZ2l0YWxfOSAgICBLYXRob2RlXzQgKFRyKQoqIERpZ2l0YWxfMTAgICBLYXRob2RlXzUgKFRyKQoqIERpZ2l0YWxfMTEgICBLYXRob2RlXzYgKFRyKQoqIERpZ2l0YWxfMTIgICBLYXRob2RlXzcgKFRyKQoqIERpZ2l0YWxfMTMgICBLYXRob2RlXzggKFRyKQoqLwoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCirjgIDjgIAg56uv5a2Q44CB5a6a5pWw44Gu5a6a576p44CA44Go44CA44OY44OD44OA44Gu44Kk44Oz44Kv44Or44O844OJICAqCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KI2luY2x1ZGUgPG1hdGguaD4gICAgIC8vIHNpbiwgY29zCgojZGVmaW5lIERBVEEgMwojZGVmaW5lIFNUUiAgNCAgICAgIC8vCiNkZWZpbmUgQ0sgICA1CiNkZWZpbmUgV0lEVEhfICAgOCAgLy8g44Oe44OI44Oq44Kv44K5TEVE44Gu44OJ44OD44OI5pWwCiNkZWZpbmUgSElHSF8gICAgOCAgLy8KI2RlZmluZSBZMCAgIDYgICAgICAvLyBZ6Lu477yQ772e77yX5YiX55uu44Gr5a++5b+c44GZ44KL44OU44Oz44KS5a6a576pCiNkZWZpbmUgWTEgICA3ICAgICAgLy8KI2RlZmluZSBZMiAgIDggICAgICAvLwojZGVmaW5lIFkzICAgOSAgICAgIC8vCiNkZWZpbmUgWTQgICAxMCAgICAgLy8KI2RlZmluZSBZNSAgIDExICAgICAvLwojZGVmaW5lIFk2ICAgMTIgICAgIC8vCiNkZWZpbmUgWTcgICAxMyAgICAgLy8KCiNkZWZpbmUgVVBCVVRUT04gICAgMTQKI2RlZmluZSBET1dOQlVUVE9OICAxNQojZGVmaW5lIExFRlRCVVRUT04gIDE2CiNkZWZpbmUgUklHSFRCVVRUT04gMTcKCiNkZWZpbmUgTU9ERU5VTSAgIDMgICAgIC8vIOeZu+mMsuODouODvOODieOBruaVsAoKI2RlZmluZSBNRU5VICAgICAgMCAgICAgLy8g44Oh44OL44Ol44O8CiNkZWZpbmUgUk9VTEVUVEUgIDEgICAgIC8vIOODq+ODvOODrOODg+ODiCjjg4Tjg7zjg6spCiNkZWZpbmUgSEFZQU9TSEkgIDIgICAgIC8vIOaXqeaKvOOBlyjjgrLjg7zjg6ApCgovLyNkZWZpbmUgTV9QSSAgICAzLjE0MTU5MjY1MzU4OTc5MzIzODQ2CiNkZWZpbmUgU0lOKHgpICBzaW4oeCAqIChNX1BJLzE4MCkpCiNkZWZpbmUgQ09TKHgpCWNvcyh4ICogKE1fUEkvMTgwKSkKCi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgoq44CA44CA44CA44CAICAg44CAICDjgrDjg63jg7zjg5Djg6vlpInmlbAgICAgICAgICAgICAgICAgICAgICoKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwpjb25zdCBjaGFyIHplcm9bSElHSF9dW1dJRFRIX10gPSB7IC8vIO+8kAogICAgICAgICAgICB7MCwwLDEsMSwxLDEsMCwwfSwKICAgICAgICAgICAgezAsMSwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDEsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwxLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMSwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDEsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwxLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwxLDEsMSwxLDAsMH0KfTsKY29uc3QgY2hhciBvbmVbSElHSF9dW1dJRFRIX10gPSB7IC8vIO+8kQogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDAsMH0KfTsKY29uc3QgY2hhciB0d29bSElHSF9dW1dJRFRIX10gPSB7IC8vIO+8kgogICAgICAgICAgICB7MCwwLDEsMSwxLDEsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwxLDEsMSwxLDAsMH0sCiAgICAgICAgICAgIHswLDEsMCwwLDAsMCwwLDB9LAogICAgICAgICAgICB7MCwxLDAsMCwwLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwxLDEsMSwxLDAsMH0KfTsKY29uc3QgY2hhciB0aHJlZVtISUdIX11bV0lEVEhfXSA9IHsgLy8g77yTCiAgICAgICAgICAgIHswLDAsMSwxLDEsMSwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDEsMSwxLDEsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwwLDEsMSwxLDEsMCwwfQp9OwoKY29uc3QgY2hhciB5YWppcnVzaVtISUdIX11bV0lEVEhfXSA9IHsgICAvLyDnn6LljbAKICAgICAgICAgICAgezAsMCwwLDEsMSwwLDAsMH0sCiAgICAgICAgICAgIHswLDAsMSwxLDEsMSwwLDB9LAogICAgICAgICAgICB7MCwxLDAsMSwxLDAsMSwwfSwKICAgICAgICAgICAgezEsMCwwLDEsMSwwLDAsMX0sCiAgICAgICAgICAgIHswLDAsMCwxLDEsMCwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMSwxLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDEsMSwwLDAsMH0sCiAgICAgICAgICAgIHswLDAsMCwxLDEsMCwwLDB9CiAgICAgICAgICB9OwogICAgICAgICAgCmNvbnN0IGNoYXIgQVtISUdIX11bV0lEVEhfXSA9IHsgICAgICAgICAgLy8gQQogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMCwwfSwKICAgICAgICAgICAgezAsMSwxLDEsMSwxLDEsMH0sCiAgICAgICAgICAgIHswLDEsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwxLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMSwxLDEsMSwxLDEsMH0sCiAgICAgICAgICAgIHswLDEsMCwwLDAsMCwxLDB9LAogICAgICAgICAgICB7MCwxLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMSwwLDAsMCwwLDEsMH0KICAgICAgICAgIH07CiAgICAgICAgICAKY29uc3QgY2hhciBNW0hJR0hfXVtXSURUSF9dID0geyAgICAgIC8vIE0KICAgICAgICAgICAgezAsMCwwLDAsMCwwLDAsMH0sCiAgICAgICAgICAgIHswLDEsMSwwLDAsMSwxLDB9LAogICAgICAgICAgICB7MCwxLDAsMSwxLDAsMSwwfSwKICAgICAgICAgICAgezAsMSwwLDEsMSwwLDEsMH0sCiAgICAgICAgICAgIHswLDEsMCwxLDEsMCwxLDB9LAogICAgICAgICAgICB7MCwxLDAsMCwwLDAsMSwwfSwKICAgICAgICAgICAgezAsMSwwLDAsMCwwLDEsMH0sCiAgICAgICAgICAgIHswLDEsMCwwLDAsMCwxLDB9CiAgICAgICAgICB9OwoKY2hhciBncm91bmRbSElHSF9dW1dJRFRIX10gPSB7ICAgICAgIC8vIOOCsOODqeOCpuODs+ODiQogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDAsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDAsMH0sCiAgICAgICAgICAgIHswLDAsMCwwLDAsMCwwLDB9LAogICAgICAgICAgICB7MCwwLDAsMCwwLDAsMCwwfSwKICAgICAgICAgICAgezAsMCwwLDAsMCwwLDAsMH0KICAgICAgICAgIH07CiAKdm9sYXRpbGUgaW50IGZsYWcgPSAwOyAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOODiOODg+ODl+eUu+mdou+8n+OBp+S9v+eUqOOBl+OBn+OCiOOBhuOBqgp2b2xhdGlsZSBpbnQgcGVybWlzc2lvbl9zdyA9IDA7ICAgICAgLy8g44K544Kk44OD44OB44Gu5YWl5Yqb44Gu56aB5q2i44Go6Kix5Y+v44KS5Yi25b6hKDE66Kix5Y+vKQp2b2xhdGlsZSB1bnNpZ25lZCBsb25nIHRpbWUgPSAwOyAgICAgLy8g6LW35YuV5b6M44Gu5pmC6ZaT44KS6KiY6Yyy44GZ44KL5aSJ5pWwCnZvbGF0aWxlIGludCBzdGF0ZTsgICAgICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7zjga7pgbjmip7nlLvpnaLjga7nirbmhYvjgpLoqJjmhrYgCnZvbGF0aWxlIGludCBpX2hheWFvc2kgPSAwOyAgICAgICAgICAvLyDml6nmirzvvJrkvZXlgIvnm67jga7ooajnpLrjgYvjgpLoqJjmhrbjgZnjgosKdm9sYXRpbGUgaW50IGNvbnRlbnRfaGF5YSA9IDA7ICAgICAgIC8vIOaXqeaKvO+8mueKtuaFi+OCkuiomOaGtu+8iOOCr+ODquOCouODu+ODn+OCueWFpeWKm++8iQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMDrliJ3mnJ/lgKQsIDE644Kv44Oq44KiLCAyOuODn+OCuQppbnQgbXVraVsxMF07ICAgICAgICAgICAgICAgICAgICAgICAgLy8g5pep5oq877ya44Op44Oz44OA44Og44Gq55+i5Y2w44Gu5ZCR44GN44KS6KiY5oa2CiAKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCirjgIDjgIDjgIDjgIAgICAgICBHUElP562J44Gu5Yid5pyf6Kit5a6aICAgICAgICAgICAgICAgICAgICoKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwp2b2lkIHNldHVwKCkgCnsKICBwaW5Nb2RlKERBVEEsIE9VVFBVVCk7ICAvLyBEQVRBCiAgcGluTW9kZShDSywgT1VUUFVUKTsgICAgLy8gQ0sKICBwaW5Nb2RlKFNUUiwgT1VUUFVUKTsgICAvLyBTVFIKICBwaW5Nb2RlKDAsIElOUFVUKTsgICAgICAvLyBSWAogIHBpbk1vZGUoMSwgT1VUUFVUKTsgICAgIC8vIFRYCiAgcGluTW9kZSgyLCBJTlBVVCk7ICAgICAgLy8g5aSJ5YyW5Ymy44KK6L6844G/IOW3puWPs+OCueOCpOODg+ODgeOBruirlueQhuWSjAogIAogIHBpbk1vZGUoWTAsIE9VVFBVVCk7ICAgIC8vIExFROOCouODjuODvOODieWBtOWItuW+oeODlOODswogIHBpbk1vZGUoWTEsIE9VVFBVVCk7ICAgIC8vCiAgcGluTW9kZShZMiwgT1VUUFVUKTsgICAgLy8KICBwaW5Nb2RlKFkzLCBPVVRQVVQpOyAgICAvLwogIHBpbk1vZGUoWTQsIE9VVFBVVCk7ICAgIC8vCiAgcGluTW9kZShZNSwgT1VUUFVUKTsgICAgLy8KICBwaW5Nb2RlKFk2LCBPVVRQVVQpOyAgICAvLwogIHBpbk1vZGUoWTcsIE9VVFBVVCk7ICAgIC8vCiAgCiAgcGluTW9kZSgxNCwgSU5QVVQpOyAgICAgLy8g44K544Kk44OD44OBKOS4iikKICBwaW5Nb2RlKDE1LCBJTlBVVCk7ICAgICAvLyDjgrnjgqTjg4Pjg4Eo5LiLKQogIHBpbk1vZGUoMTYsIElOUFVUKTsgICAgIC8vIOOCueOCpOODg+ODgSjlt6YpCiAgcGluTW9kZSgxNywgSU5QVVQpOyAgICAgLy8g44K544Kk44OD44OBKOWPsykKICBwaW5Nb2RlKDE4LCBJTlBVVCk7ICAgICAvLyDjg6njg7Pjg4Djg6DplqLmlbDjga7nqK4KIAogIC8vLS0g5aSJ5YyW5Ymy44KK6L6844G/44Gu5Yid5pyf6Kit5a6aCiAgYXR0YWNoSW50ZXJydXB0KDAsIGludGVycnVwdCwgUklTSU5HKTsgIC8vIDLnlarjg5Tjg7PjgpLlibLjgorovrzjgb/jgafkvb/nlKgKICBwZXJtaXNzaW9uX3N3ID0gMTsgICAgICAgICAgICAgICAgICAgICAgLy8g5Ymy44KK6L6844G/44KS6Kix5Y+vCiAgLy8tLQogCiAgLy8tLSDjgrfjg5Xjg4jjg6zjgrjjgrnjgr/jga7liJ3mnJ/oqK3lrpoKICBkaWdpdGFsV3JpdGUoU1RSLCBISUdIKTsgICAgICAgICAgIC8vIOOCt+ODleODiOODrOOCuOOCueOCv+OCkuWHuuWKm+OBl+OBquOBhAogIGRpZ2l0YWxXcml0ZShEQVRBLCBMT1cpOyAgICAgICAgICAgLy8g44K344OV44OI44Os44K444K544K/IOODh+ODvOOCv+OCku+8kOOCr+ODquOCogogIGNsb2NrKCk7IGNsb2NrKCk7IGNsb2NrKCk7IGNsb2NrKCk7Ly8KICBjbG9jaygpOyBjbG9jaygpOyBjbG9jaygpOyBjbG9jaygpOy8vCiAgZGlnaXRhbFdyaXRlKFNUUiwgTE9XKTsgICAgICAgICAgICAvLyDjgrfjg5Xjg4jjg6zjgrjjgrnjgr/jgpLlh7rlipvjgZnjgosKICAvLy0tCiAgLy90aW1lID0gbWlsbGlzKCk7ICAgICAgICAgICAgICAgICAgIC8vIOODl+ODreOCsOODqeODoOmWi+Wni+aZgumWk+OCkuiomOmMsgogIFNlcmlhbC5iZWdpbig5NjAwKTsKICAKICBzdGFydHVwKCk7ICAgICAgIC8vIOi1t+WLleaZguOBq0FNQeOBqOWbs+OAheOBl+OBj+ihqOekugogIHJvbGwoZ3JvdW5kLCB6ZXJvLCAwKTsgICAgICAgICAgICAgLy8g6LW35YuV55u05b6M44Gu44Oh44OL44Ol44O844Gv77yQ44KS6KGo56S6CiAgc3RhdGUgPSAwOyAgICAgICAgICAgICAgICAgICAgICAgICAvLyDooajnpLrjgYzvvJDjgafjgYLjgovjgZPjgajjgpLoqJjmhrYKfQoKLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCirjgIDjgIDjgIDjgIAgICDjgIAgICAgbG9vcOmWouaVsCAgICAgICAgICAgICAgICAgICAgICAgICoKKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLwp2b2lkIGxvb3AoKSAKeyAKICBzd2l0Y2goc3RhdGUpewogICAgY2FzZSBNRU5VOgogICAgICBtZW51KCk7ICAgICAgLy/jg6Hjg4vjg6Xjg7zjgpLlrp/ooYwKICAgICAgYnJlYWs7CiAgICBjYXNlIFJPVUxFVFRFOgogICAgICByb3VsZXR0ZSgpOyAgLy8g44Or44O844Os44OD44OI44KS5a6f6KGMCiAgICAgIGJyZWFrOwogICAgY2FzZSBIQVlBT1NISToKICAgICAgaGF5YW9zaGkoKTsgICAgICAgICAgICAgICAgLy8g5pep5oq844GX44Ky44O844Og44KS5a6f6KGMCiAgICAgIGZsYWcgPSAwOyAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOeUu+mdouOCkuODq+ODvOODl+OBmeOCi+OCiOOBhuODleODqeOCsOOCkueri+OBpuOCiwogICAgICBzdGF0ZSA9IE1FTlU7ICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7znlLvpnaLjgbjnp7vooYwKICAgICAgaV9oYXlhb3NpID0gMDsgICAgICAgICAgICAgLy8g44Ky44O844Og44Gu44OX44Os44Kk5oOF5aCx44KS5Yid5pyf5YyWCiAgICAgIGNvbnRlbnRfaGF5YSA9IDA7CiAgICAgIGJyZWFrOwogICAgZGVmYXVsdDoKICAgICAgYnJlYWs7CiAgfQp9CgovKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKKuOAgOOAgOOAgOOAgCAgIOOAgCAg44Om44O844K244O85a6a576p6Zai5pWwICAgICAgICAgICAgICAgICAgKgoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovCgovLz09PT09PT09PT09PT09PT09IOODoSDjg4sg44OlICDjg7wgPT09PT09PT09PT09PT09PT09PQp2b2lkIG1lbnUoKQp7CiAgc3RhdGljIGludCBzdGF0ZTEgPSAwOyAgICAgICAgLy8g5Yid5pyf54q25oWL44GvJ++8kCfjgpLooajnpLrjgZfjgabjgYTjgovjga7jgafvvJDjgpLku6PlhaUKICB3aGlsZShmbGFnID09IDApeyAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7zjgYzpgbjmip7jgZXjgozjgarjgYTpmZDjgorjg6vjg7zjg5cKICAgIGlmKHN0YXRlMSAhPSBzdGF0ZSl7ICAgICAgICAvLyDnj77lnKjjga7ooajnpLrjg4fjg7zjgr/jgajnlbDjgarjgovloLTlkIgKICAgICAgc3dpdGNoKHN0YXRlKXsKICAgICAgICBjYXNlIDA6ICAgICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7zvvJDjgarjgonjgbAKICAgICAgICAgIHN0YXRlMSA9IDA7ICAgICAgICAgICAvLyDnj77lnKjjga7mlbDlrZfjgpIgJ++8kCcg44Gr5aSJ5pu0CiAgICAgICAgICByb2xsKGdyb3VuZCwgemVybywgMCk7Ly8g6KGo56S644OH44O844K/44KSICfvvJAnIOOBq+WkieabtAogICAgICAgICAgYnJlYWs7CiAgICAgICAgY2FzZSAxOgogICAgICAgICAgc3RhdGUxID0gMTsgICAgICAgICAgIC8vIOePvuWcqOOBruaVsOWtl+OCkiAn77yRJyDjgavlpInmm7QKICAgICAgICAgIHJvbGwoZ3JvdW5kLCBvbmUsIDApOyAvLyDooajnpLrjg4fjg7zjgr/jgpIgJ++8kScg44Gr5aSJ5pu0CiAgICAgICAgICBicmVhazsKICAgICAgICBjYXNlIDI6CiAgICAgICAgICBzdGF0ZTEgPSAyOyAgICAgICAgICAgLy8g54++5Zyo44Gu5pWw5a2X44KSICfvvJInIOOBq+WkieabtAogICAgICAgICAgcm9sbChncm91bmQsIHR3bywgMCk7IC8vIOihqOekuuODh+ODvOOCv+OCkiAn77ySJyDjgavlpInmm7QKICAgICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgICBkcmF3X2dyb3VuZCgpOyAgICAgICAgICAgICAgLy8g6YG45oqe5Lit44Gu55Wq5Y+344KS6KGo56S644GZ44KLCiAgfQogIAogIHJldHVybjsKfQoKLy89PT09PT09PT09PT09PT09PSDotbcg5YuVIOaZgiDjga4g44KoIOODlSDjgqcg44KvIOODiCA9PT09PT09PT09PT09PT09PT09Cgp2b2lkIHN0YXJ0dXAoKQp7CiAgaW50IGFuZ2xlID0gMDsKICB1bnNpZ25lZCBsb25nIHRpbWUsIG1hcmdpbjsKICAKICBmb3IoYW5nbGUgPSAwOyBhbmdsZSA8PSAzNjA7IGFuZ2xlKz0xMCl7CiAgICAgcm9sbChncm91bmQsIEEsIGFuZ2xlKTsKICAgICBkcmF3X2dyb3VuZCgpOwogIH0KICAKICB0aW1lID0gbWlsbGlzKCk7CiAgIHdoaWxlKDEpewogICAgIG1hcmdpbiA9IG1pbGxpcygpIC0gdGltZTsKICAgICBpZihtYXJnaW4gPiA1MDApIGJyZWFrOwogICAgIGRyYXdfZ3JvdW5kKCk7CiAgIH0KICAKICBmb3IoYW5nbGUgPSAwOyBhbmdsZSA8PSAzNjA7IGFuZ2xlKz0xMCl7CiAgICAgcm9sbChncm91bmQsIE0sIGFuZ2xlKTsKICAgICBkcmF3X2dyb3VuZCgpOwogIH0KICAKICAgdGltZSA9IG1pbGxpcygpOwogICB3aGlsZSgxKXsKICAgICBtYXJnaW4gPSBtaWxsaXMoKSAtIHRpbWU7CiAgICAgaWYobWFyZ2luID4gNTAwKSBicmVhazsKICAgICBkcmF3X2dyb3VuZCgpOwogICB9CiAgCiAgZm9yKGFuZ2xlID0gMDsgYW5nbGUgPD0gMzYwOyBhbmdsZSs9MTApewogICAgIHJvbGwoZ3JvdW5kLCBBLCBhbmdsZSk7CiAgICAgZHJhd19ncm91bmQoKTsKICB9CiAgCiAgdGltZSA9IG1pbGxpcygpOwogICB3aGlsZSgxKXsKICAgICBtYXJnaW4gPSBtaWxsaXMoKSAtIHRpbWU7CiAgICAgaWYobWFyZ2luID4gNTAwKSBicmVhazsKICAgICBkcmF3X2dyb3VuZCgpOwogICB9Cn0KCi8vPT09PT09PT09PT09PT09IOODqyDjg7wg44OsIOODgyDjg4gg44GuIOWHpiDnkIYgPT09PT09PT09PT09PT09PT09PQp2b2lkIHJvdWxldHRlKCkKewogIGludCBhbmdsZTsKICBpbnQgaSwgdGltZV9yOwogIGludCBtYXJnaW47CiAgCiAgcGVybWlzc2lvbl9zdyA9IDA7ICAgICAgICAgICAgICAvLyDjgrnjgqTjg4Pjg4HlhaXlipvjgpLnpoHmraIKICByYW5kb21TZWVkKGFuYWxvZ1JlYWQoMTgpKTsgICAgIC8vIOODqeODs+ODgOODoOmWouaVsOOBrueoruOBvuOBjQogIGFuZ2xlID0gOTAgKiByYW5kb20oMCwgNCk7ICAgICAgLy8g5YGc5q2i6KeS5bqm44KS5rG644KB44KLKDkwfjM2MCkKICB0aW1lX3IgPSBtaWxsaXMoKTsKICByb2xsKGdyb3VuZCwgeWFqaXJ1c2ksIDApOwogIHRpbWVfciA9IG1pbGxpcygpOwogIAogIHdoaWxlKDEpeyAgLy8g77yS56eS6ZaT44KB44Gh44KD44GP44Gh44KD44Gq6KGo56S6CiAgICBtYXJnaW4gPSBtaWxsaXMoKSAtIHRpbWVfcjsKICAgIGlmKG1hcmdpbiA+IDIwMDApIGJyZWFrOyAgICAgLy8g77yS56eS5Lul5LiK57WM6YGO44Gn57WQ5p6c6KGo56S644G456e76KGMCiAgICBkZWxheU1pY3Jvc2Vjb25kcygxMCk7CiAgICByb2xsKGdyb3VuZCwgeWFqaXJ1c2ksIDkwICogcmFuZG9tKDAsNCkpOwogICAgZHJhd19ncm91bmQoKTsKICB9CiAgcm9sbChncm91bmQsIHlhamlydXNpLCBhbmdsZSk7CiAgCiAgZm9yKGkgPSAwOyBpIDwgMTAwOyBpKyspeyAgICAgICAvLyDmsbrlrprjgZfjgZ/nirbmhYvjgpLjgZfjgbDjgonjgY/ooajnpLoKICAgIGRlbGF5TWljcm9zZWNvbmRzKDEwMCk7CiAgICBkcmF3X2dyb3VuZCgpOwogIH0KICBmbGFnID0gMDsgICAgICAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOeUu+mdouOCkuODq+ODvOODl+OBmeOCi+OCiOOBhuODleODqeOCsOOCkueri+OBpuOCiwogIHN0YXRlID0gTUVOVTsgICAgICAgICAgICAgICAgICAgLy8g44Oh44OL44Ol44O855S76Z2i44G456e76KGMCiAgcGVybWlzc2lvbl9zdyA9IDE7ICAgICAgICAgICAgICAvLyDjgrnjgqTjg4Pjg4HlhaXlipvjgpLoqLHlj68KICByZXR1cm47Cn0KCi8vPT09PT09PT09PT09PT09IOaXqSDmirwg44GXIOOCsiDjg7wg44OgIOOBriDlh6Yg55CGID09PT09PT09PT09PT09PT09PT0Kdm9pZCBoYXlhb3NoaSgpCnsKICBpbnQgaTsKICB1bnNpZ25lZCBsb25nIHRpbWVfaGF5YSwgbWFyZ2luOwogIHBlcm1pc3Npb25fc3cgPSAwOyAgICAgICAgICAgICAgLy8g44K544Kk44OD44OB5YWl5Yqb44KS56aB5q2iCiAgcmFuZG9tU2VlZChhbmFsb2dSZWFkKDE4KSk7ICAgICAvLyDjg6njg7Pjg4Djg6DplqLmlbDjga7nqK7jgb7jgY0KICAvLy0tICAgIOefouWNsOOCkuaxuuOCgeOCi+ODkeODqeODoeODvOOCv+OCku+8ke+8kOWAi+W+l+OCiwogIGZvcihpID0gMDsgaSA8IDU7IGkrKyl7CiAgICBtdWtpW2ldID0gcmFuZG9tKDAsIDQpOyAgICAgICAvLyDvvJDvvZ7vvJPjga7lgKTjgpLlvpfjgosKICB9CgogIC8vLS0gICAg6ZaL5aeL44G+44Gn44Gu44Kr44Km44Oz44OI5Yem55CGIAogIHRpbWVfaGF5YSA9IG1pbGxpcygpOyAgICAgICAgICAgICAgICAvLyDnj77lnKjjga7mmYLplpPjgpLoqJjpjLIKICB3aGlsZSgxKXsKICAgIG1hcmdpbiA9IG1pbGxpcygpIC0gdGltZV9oYXlhOyAgICAvLyDntYzpgY7mmYLplpPjgpLlvpfjgosobXMpCiAgICBpZihtYXJnaW4gPiAzMDAwKXsgICAgICAgICAgIC8vIO+8k+enkuS7peS4iue1jOmBjgogICAgICBicmVhazsgICAgICAgICAgICAgICAgICAgICAgLy8g44Ky44O844Og44G456e76KGMCiAgICB9ZWxzZSBpZihtYXJnaW4gPiAyMDAwKXsgICAgIC8vIO+8kuenkuS7peS4iue1jOmBjijvvJHjgpLooajnpLopCiAgICAgIHJvbGwoZ3JvdW5kLCBvbmUsIDApOwogICAgfWVsc2UgaWYobWFyZ2luID4gMTAwMCl7ICAgICAvLyDvvJHnp5Lku6XkuIrntYzpgY4o77yS44KS6KGo56S6KQogICAgICByb2xsKGdyb3VuZCwgdHdvLCAwKTsgICAgICAgLy8g6KGo56S644OH44O844K/44Gr77yS44KS44K744OD44OICiAgICB9ZWxzZXsgICAgICAgICAgICAgICAgICAgICAgICAvLyDvvJDnp5Lku6XkuIrntYzpgY4o77yT44KS6KGo56S6KQogICAgICByb2xsKGdyb3VuZCwgdGhyZWUsIDApOyAgICAgLy8g6KGo56S644OH44O844K/44Gr77yT44KS44K744OD44OICiAgICB9CiAgICBkcmF3X2dyb3VuZCgpOyAgICAgICAgICAgICAgICAvLwogIH0KICBwZXJtaXNzaW9uX3N3ID0gMTsgICAgICAgICAgICAgIC8vIOOCueOCpOODg+ODgeWFpeWKm+OCkuioseWPrwogIAogIC8vLS0gICAg44Ky44O844Og6ZaL5aeLCiAgdGltZV9oYXlhID0gbWlsbGlzKCk7ICAgICAgICAgICAgICAgIC8vIOOCsuODvOODoOmWi+Wni+OBruaZgumWk+OCkuW+l+OCiwogIHJvbGwoZ3JvdW5kLCB5YWppcnVzaSwgbXVraVtpX2hheWFvc2ldICogOTApOyAgLy8g5pyA5Yid44Gu55+i5Y2w44KS6KGo56S6CiAgCiAgd2hpbGUoMSl7ICAgICAgICAgICAgICAgICAgICAgICAvLyDjgZPjga7jg6vjg7zjg5flhoXjgafjgrLjg7zjg6DjgpLlh6bnkIbjgZnjgosKICAgIGRyYXdfZ3JvdW5kKCk7CiAgICAKICAgIGlmKGNvbnRlbnRfaGF5YSA9PSAxKXsgICAgICAgIC8vIOOCsuODvOODoOOCr+ODquOCouOBruWgtOWQiAogICAgICAvL2dhbWVjbGVhcigpOyAgICAgICAgICAgICAgLy8g44Kv44Oq44Ki44GX44Gf5pmC6ZaT44KS5Ye65YqbIOW8leaVsOOBr+OCv+OCpOODoAogICAgICBtYXJnaW4gPSBtaWxsaXMoKSAtIHRpbWVfaGF5YTsgIC8v44Kv44Oq44Ki44G+44Gn44Gu57WM6YGO5pmC6ZaT44KS566X5Ye6CiAgICAgIFNlcmlhbC5wcmludGxuKG1hcmdpbik7CiAgICAgIGJyZWFrOwogICAgfQogICAgZWxzZSBpZihjb250ZW50X2hheWEgPT0gMil7ICAvLyDjgrLjg7zjg6DlpLHmlZfjga7loLTlkIgKICAgICAgLy9nYW1lcmV0aXJlZCgpOyAgICAgICAgICAgIC8vIOWkseaVl+OBruihqOekugogICAgICBicmVhazsKICAgIH0KICB9Cn0KCi8vPT09PT09PT09PT09PT09PT09PSDjgrnjgqTjg4Pjg4Eg5YmyIOOCiiDovrwg44G/IOWHpiDnkIYgPT09PT09PT09PT09PT09PT09PQp2b2lkIGludGVycnVwdCgpCnsKICBzdGF0aWMgaW50IGFuZ2xlID0gMDsKICB1bnNpZ25lZCBsb25nIHRpbWUyID0gbWlsbGlzKCk7CiAgaWYocGVybWlzc2lvbl9zdyA9PSAwKSAgcmV0dXJuOyAgICAgICAgICAgICAgICAgICAgICAgICAvLyDjgrnjgqTjg4Pjg4HlhaXlipvjgYzoqLHlj6/jgZXjgozjgabjgYTjgarjgZHjgozjgbDjg6rjgr/jg7zjg7MKICBpZih0aW1lMiAtIHRpbWUgPCAyMDApIHJldHVybjsgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOWJjeWbnuOBruWJsuOCiui+vOOBv+aZgumWk+OBi+OCiTEwMG1z5Lul5LiK57WM6YGO44GX44Gm44GE44KL44GLCiAgCiAgaWYoZGlnaXRhbFJlYWQoVVBCVVRUT04pKXsgICAgICAgICAgLy8tLS0tLeS4iuODnOOCv+ODs+OBjOaKvOOBleOCjOOBn+OBquOCieOBsC0tLS0tCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7zooajnpLrkuK3jga7lh6bnkIYKICAgICBpZihmbGFnICE9IDEgJiYgc3RhdGUgIT0gMCl7ICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOeUu+mdouS7peWkluOBruOCsuODvOODoOOBjOe1guS6huOBl+OBpuOBhOOCjOOBsOWun+ihjAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g6YG45oqe5Lit44Gu44Oh44OL44Ol44O844KS5rG65a6a44GZ44KLCiAgICAgICBmbGFnID0gMTsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7znlLvpnaLjgpLmipzjgZHjgovjg5Xjg6njgrDjgpLnq4vjgabjgosKICAgICAgIHJldHVybjsKICAgICB9ZWxzZSBpZihzdGF0ZSA9PSBIQVlBT1NISSl7ICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOKXi+aXqeaKvOOBl+OCsuODvOODoOOBp+OBruWHpueQhgogICAgICAgaWYobXVraVtpX2hheWFvc2ldID09IDApewogICAgICAgICBpX2hheWFvc2kgKz0gMTsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g5qyh44Gu55+i5Y2w44Gu44OR44Op44Oh44O844K/44G45Yqg566XCiAgICAgICAgIHJvbGwoZ3JvdW5kLCB5YWppcnVzaSwgbXVraVtpX2hheWFvc2ldICogOTApOyAgICAvL+efouWNsOOCkuasoeOBruefouWNsOOBq+abtOaWsAogICAgICAgICBpZihpX2hheWFvc2kgPT0gNSkgY29udGVudF9oYXlhID0gMTsgICAgICAgICAgICAgLy8g44Ky44O844Og44Kv44Oq44Ki44KS5pWZ44GI44KLCiAgICAgICB9ZWxzZXsKICAgICAgICAgY29udGVudF9oYXlhID0gMjsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOOCsuODvOODoOWkseaVl+OCkuaVmeOBiOOCiwogICAgICAgfQogICAgIH0gCiAgfWVsc2UgaWYoZGlnaXRhbFJlYWQoRE9XTkJVVFRPTikpeyAgIC8vLS0tLS3kuIvjg5zjgr/jg7PjgYzmirzjgZXjgozjgZ/jgarjgonjgbAtLS0tLQogICAgaWYoIGZsYWcgPT0gMCApIHJldHVybjsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g44Oh44OL44Ol44O855S76Z2i5LiK44Gn44Gu5YWl5Yqb44Gv54Sh5Yq5CiAgICAKICAgIGlmKCBzdGF0ZSA9PSBIQVlBT1NISSl7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOKXi+aXqeaKvOOBl+OCsuODvOODoOOBp+OBruWHpueQhgogICAgICAgaWYobXVraVtpX2hheWFvc2ldID09IDIpewogICAgICAgICBpX2hheWFvc2kgKys7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g5qyh44Gu55+i5Y2w44Gu44OR44Op44Oh44O844K/44G45Yqg566XCiAgICAgICAgIHJvbGwoZ3JvdW5kLCB5YWppcnVzaSwgbXVraVtpX2hheWFvc2ldICogOTApOyAgICAvL+efouWNsOOCkuasoeOBruefouWNsOOBq+abtOaWsAogICAgICAgICBpZihpX2hheWFvc2kgPT0gNSkgY29udGVudF9oYXlhID0gMTsgICAgICAgICAgICAgLy8g44Ky44O844Og44Kv44Oq44Ki44KS5pWZ44GI44KLCiAgICAgICB9ZWxzZXsKICAgICAgICAgY29udGVudF9oYXlhID0gMjsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOOCsuODvOODoOWkseaVl+OCkuaVmeOBiOOCiwogICAgICAgfQogICAgIH0gCiAgfWVsc2UgaWYoZGlnaXRhbFJlYWQoTEVGVEJVVFRPTikpeyAgICAvLy0tLS0t5bem44Oc44K/44Oz44GM5oq844GV44KM44Gf44Gq44KJ44GwLS0tLS0KICAgICBpZihzdGF0ZSA+IDAgJiYgZmxhZyA9PSAwKXsgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOihqOekuuS4reOBruWHpueQhgogICAgICAgc3RhdGUgLS07ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g44Oh44OL44Ol44O844KS77yN77yR44GZ44KLCiAgICAgfWVsc2UgaWYoc3RhdGUgPT0gSEFZQU9TSEkgJiYgZmxhZyA9PSAxKXsgICAgICAgICAgICAvLyDil4vml6nmirzjgZfjgrLjg7zjg6Djgafjga7lh6bnkIYKICAgICAgIGlmKG11a2lbaV9oYXlhb3NpXSA9PSAzKXsKICAgICAgICAgaV9oYXlhb3NpICsrOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOasoeOBruefouWNsOOBruODkeODqeODoeODvOOCv+OBuOWKoOeulwogICAgICAgICByb2xsKGdyb3VuZCwgeWFqaXJ1c2ksIG11a2lbaV9oYXlhb3NpXSAqIDkwKTsgICAgLy/nn6LljbDjgpLmrKHjga7nn6LljbDjgavmm7TmlrAKICAgICAgICAgaWYoaV9oYXlhb3NpID09IDUpIGNvbnRlbnRfaGF5YSA9IDE7ICAgICAgICAgICAgIC8vIOOCsuODvOODoOOCr+ODquOCouOCkuaVmeOBiOOCiwogICAgICAgfWVsc2V7CiAgICAgICAgIGNvbnRlbnRfaGF5YSA9IDI7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDjgrLjg7zjg6DlpLHmlZfjgpLmlZnjgYjjgosKICAgICAgIH0KICAgICB9CiAgfWVsc2UgaWYoZGlnaXRhbFJlYWQoUklHSFRCVVRUT04pKXsgICAgLy8tLS0tLeWPs+ODnOOCv+ODs+OBjOaKvOOBleOCjOOBn+OBquOCieOBsC0tLS0tCiAgICAgaWYoc3RhdGUgPCBNT0RFTlVNLTEgJiYgZmxhZyA9PSAwKXsgICAgICAgICAgICAgICAgICAvLyDjg6Hjg4vjg6Xjg7zooajnpLrkuK3jga7lh6bnkIYKICAgICAgIHN0YXRlICsrOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIOODoeODi+ODpeODvOOCku+8i++8keOBmeOCiwogICAgIH1lbHNlIGlmKHN0YXRlID09IEhBWUFPU0hJICYmIGZsYWcgPT0gMSl7ICAgICAgICAgICAgLy8g4peL5pep5oq844GX44Ky44O844Og44Gn44Gu5Yem55CGCiAgICAgICBpZihtdWtpW2lfaGF5YW9zaV0gPT0gMSl7CiAgICAgICAgIGlfaGF5YW9zaSArKzsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDmrKHjga7nn6LljbDjga7jg5Hjg6njg6Hjg7zjgr/jgbjliqDnrpcKICAgICAgICAgcm9sbChncm91bmQsIHlhamlydXNpLCBtdWtpW2lfaGF5YW9zaV0gKiA5MCk7ICAgIC8v55+i5Y2w44KS5qyh44Gu55+i5Y2w44Gr5pu05pawCiAgICAgICAgIGlmKGlfaGF5YW9zaSA9PSA1KSBjb250ZW50X2hheWEgPSAxOyAgICAgICAgICAgICAvLyDjgrLjg7zjg6Djgq/jg6rjgqLjgpLmlZnjgYjjgosKICAgICAgIH1lbHNlewogICAgICAgICBjb250ZW50X2hheWEgPSAyOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g44Ky44O844Og5aSx5pWX44KS5pWZ44GI44KLCiAgICAgICB9CiAgICAgfQogIH0KICB0aW1lID0gdGltZTI7Cn0gCgovLz09PT09PT09PT09PT09PT09PT1ncm91bmTphY3liJfjgpLjg57jg4jjg6rjgq/jgrlMRUTjgavmj4/nlLs9PT09PT09PT09PT09PT09PT09CnZvaWQgZHJhd19ncm91bmQoKQp7CiAgZm9yKGludCBpID0gMDsgaSA8IDg7IGkrKyl7ICAgICAgLy8g77yY5YiX5YiG5YiX44Ki44OO44O844OJ5YG044KS44K344OV44OI44GV44Gb44KL44CCCiAgICBpZihpPT0wKXsgICAgICAgICAgICAgICAgICAgICAgLy8g77yR5YiX55uu44GM5Y+C54Wn44GV44KM44Gm44GE44Gf44Gq44KJ44GwCiAgICAgIGRpZ2l0YWxXcml0ZShEQVRBLCBISUdIKTsgICAgLy8gSElHSOOCkuOCu+ODg+ODiOOBl+OBpuOCt+ODleODiAogICAgICBjbG9jaygpOwogICAgfWVsc2V7ICAgICAgICAgICAgICAgICAgICAgICAgIC8vIO+8kuWIl+ebruS7pemZjeOBjOWPgueFp+OBleOCjOOBpuOBhOOBn+OBquOCieOBsAogICAgICBkaWdpdGFsV3JpdGUoREFUQSwgTE9XKTsgICAgIC8vIOmghuasoUxPV+OCkuOCu+ODg+ODiOOBl+OBpuOCt+ODleODiAogICAgICBjbG9jaygpOwogICAgfQogICAgZGlnaXRhbFdyaXRlKFkwLCAoZ3JvdW5kWzBdW2ldPT0xKT9ISUdIOkxPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTEsIChncm91bmRbMV1baV09PTEpP0hJR0g6TE9XKTsKICAgIGRpZ2l0YWxXcml0ZShZMiwgKGdyb3VuZFsyXVtpXT09MSk/SElHSDpMT1cpOwogICAgZGlnaXRhbFdyaXRlKFkzLCAoZ3JvdW5kWzNdW2ldPT0xKT9ISUdIOkxPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTQsIChncm91bmRbNF1baV09PTEpP0hJR0g6TE9XKTsKICAgIGRpZ2l0YWxXcml0ZShZNSwgKGdyb3VuZFs1XVtpXT09MSk/SElHSDpMT1cpOwogICAgZGlnaXRhbFdyaXRlKFk2LCAoZ3JvdW5kWzZdW2ldPT0xKT9ISUdIOkxPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTcsIChncm91bmRbN11baV09PTEpP0hJR0g6TE9XKTsKICAgIGRlbGF5KDIpOwogICAgd2lwZV9vdXRfc2hhZG93KCk7ICAgICAgICAgICAgICAvLyDliJfjgpLliIfjgormm7/jgYjjgovliY3jgavooajnpLrjgpLmtojjgZnjgZPjgajjgafmrovlg4/lh6bnkIYKICB9Cn0KCi8vPT09PT09PT09PT09PT09PT09PeOCt+ODleODiOODrOOCuOOCueOCv+OBuOOBruOCr+ODreODg+OCr+WHpueQhj09PT09PT09PT09PT09PT09PT0Kdm9pZCBjbG9jaygpCnsKICBkaWdpdGFsV3JpdGUoQ0ssIExPVyk7CiAgZGVsYXlNaWNyb3NlY29uZHMoNSk7CiAgZGlnaXRhbFdyaXRlKENLLCBISUdIKTsKICBkZWxheU1pY3Jvc2Vjb25kcyg1KTsKICBkaWdpdGFsV3JpdGUoQ0ssIExPVyk7Cn0KCi8vPT09PT09PT09PT09PT09PT09PeODieODg+ODiOODnuODiOODquOCr+OCuUxFROOBruaui+WDj+WHpueQhj09PT09PT09PT09PT09PT09PT0Kdm9pZCB3aXBlX291dF9zaGFkb3coKQp7CiAgICBkaWdpdGFsV3JpdGUoWTAsIExPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTEsIExPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTIsIExPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTMsIExPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTQsIExPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTUsIExPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTYsIExPVyk7CiAgICBkaWdpdGFsV3JpdGUoWTcsIExPVyk7Cn0KCi8vPT09PT095byV5pWw44Gu6KGo56S644OH44O844K/44KS5Lu75oSP44Gu6KeS5bqm44Gr5Zue6Lui44GX44GmZ3JvdW5k6YWN5YiX44Gr44K744OD44OIPT09PT0Kdm9pZCByb2xsKGNoYXIgdG9bXVs4XSwgY29uc3QgY2hhciBmcm9tW11bOF0sIGludCBhbmdsZSkKewogIGludCB4LCB5OwogIGRvdWJsZSB4MSA9IDAuMCwgeTEgPSAwLjA7CiAgaWYoYW5nbGUgPT0gMCl7ICAgICAgIC8vIOWbnui7ouinkuW6puOBjO+8kOOBquOCieWbnui7ouWHpueQhuOBr+ihjOOCj+OBquOBhAogICAgZm9yICh5ID0gMDsgeSA8IDg7IHkrKyl7CiAgICAgIGZvciAoeCA9IDA7IHggPCA4OyB4KyspewogICAgICAgIHRvW3ldW3hdID0gZnJvbVt5XVt4XTsKICAgICAgfQogICAgfQogIH1lbHNleyAgICAgICAgICAgICAgICAvLyDlm57ou6Llh6bnkIYKICAgIGZvciAoeSA9IDA7IHkgPCA4OyB5KyspewogICAgICBmb3IgKHggPSAwOyB4IDwgODsgeCsrKXsKICAgICAgICB4MSA9ICgoeCAtIDMuNSkgKiBDT1MoYW5nbGUpIC0gKHkgLSAzLjUpICogU0lOKGFuZ2xlKSk7CiAgICAgICAgeTEgPSAoKHggLSAzLjUpICogU0lOKGFuZ2xlKSArICh5IC0gMy41KSAqIENPUyhhbmdsZSkpOwogICAgICAgIHgxID0geDEgKyAzLjU7CS8vIOOBmuOCieOBl+OBn+W6p+aomeOCkuS/ruatowogICAgICAgIHkxID0geTEgKyAzLjU7CS8vCiAgICAgICAgCiAgICAgICAgaWYgKGZyb21beV1beF0gPT0gMSl7CiAgICAgICAgICBpZiAoKGludCkoeDEgKyAwLjUpIDwgV0lEVEhfICYmIChpbnQpKHkxICsgMC41KSA8IEhJR0hfKSB0b1soaW50KSh5MSArIDAuNSldWyhpbnQpKHgxICsgMC41KV0gPSAxOwogICAgICAgIH1lbHNlewogICAgICAgICAgaWYgKChpbnQpKHgxICsgMC41KSA8IFdJRFRIXyAmJiAoaW50KSh5MSArIDAuNSkgPCBISUdIXykgdG9bKGludCkoeTEgKyAwLjUpXVsoaW50KSh4MSArIDAuNSldID0gMDsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0=