/* package whatever; // don't place package name! */
import java.util.* ;
import java.lang.* ;
import java.io.* ;
/**
* Created by Игорь on 25.10.2015.
*/
import java.util.Random ;
public class Main {
public static void main
( String [ ] args
) { //System.out.println(isPrimeAccordingToMillerRabin(19, 5));
generatePossiblePrimeWithLength( 20 ) ;
}
public static int gcd( int a, int b) {
if ( b == 0 )
return gcd( b, a % b) ;
}
/* Символ якоби
1 (проверка взаимной простоты). Если НОД (a, b)≠1, выход из алгоритма с ответом 0.
2 (инициализация). r:=1
3 (переход к положительным числам).
Если a<0 то
a:=-a
Если b mod 4 = 3 то r:=-r
Конец если
4 (избавление от чётности). t:=0
Цикл ПОКА a – чётное
t:=t+1
a:=a/2
Конец цикла
Если t – нечётное, то
Если b mod 8 = 3 или 5, то r:=-r.
Конец если
5 (квадратичный закон взаимности). Если a mod 4 = b mod 4 = 3, то r:=-r.
c:=a; a:=b mod c; b:=c.
6 (выход из алгоритма?). Если a≠0, то идти на шаг 4, иначе выйти из алгоритма с ответом r.
*/
public static int jacobySign( int a, int b) // a - целое, b - натуральное > 1, нечетное
{
if ( gcd ( a, b) != 1 ) {
return 0 ;
}
int r = 1 ;
if ( a < 0 ) {
a = - a;
if ( b % 4 == 3 ) {
r = - r;
}
}
while ( a != 0 )
{
int t = 0 ;
while ( a % 2 == 0 ) {
t++;
a /= 2 ;
}
if ( t % 2 != 0 )
{
int mod = b % 8 ;
if ( mod == 3 || mod == 5 )
{
r = - r;
}
}
int modA = a % 4 ;
if ( ( modA == b % 4 ) && modA == 3 ) {
r = - r;
}
int c = a;
a = b % c;
b = c;
}
return r;
}
public static int randomIntInRange( int min, int max) {
int randomNum = rand.nextInt ( ( max - min) + 1 ) + min;
return randomNum;
}
public static int pow( int foundation, int degree, int modeFoundation) {
int answer = 1 ;
for ( int i = 0 ; i < degree; i++ ) {
answer *= foundation;
answer %= modeFoundation;
}
return answer;
}
/*
Алгоритм Соловея — Штрассена [6] параметризуется количеством раундов k.
В каждом раунде случайным образом выбирается число a < n. Если НОД(a,n) > 1, то выносится решение, что n составное.
Иначе проверяется справедливость сравнения \textstyle a^{(n-1)/2} \equiv \left( {a\over n} \right) \pmod{n}.
Если оно не выполняется, то выносится решение, что n — составное. Если это сравнение выполняется, то a является свидетелем простоты числа n.
Далее выбирается другое случайное a и процедура повторяется.
После нахождения k свидетелей простоты в k раундах выносится заключение, что n является простым числом с вероятностью 1 - 2^{-k} .
Вход: n > 2, тестируемое нечётное натуральное число;
k, параметр, определяющий точность теста.
Выход: составное, означает, что n точно составное;
вероятно простое, означает, что n вероятно является простым.
for i = 1, 2, ..., k:
a = случайное целое от 2 до n - 1, включительно;
если НОД(a, n) > 1, тогда:
вывести, что n — составное, и остановиться.
если a^{(n-1)/2} \not\equiv \left( {a\over n} \right) \pmod{n}, тогда:
вывести, что n — составное, и остановиться.
вывести, что n — простое с вероятностью \textstyle 1 - 2^{-k} , и остановиться.
*/
public static boolean isPrimeAccordingToSoloveiShtrassen( int number, int accuracy) { //number > 2, нечётное натуральное число
for ( int i = 0 ; i < accuracy; i++ ) {
int randomInt = randomIntInRange( 2 , number - 1 ) ;
if ( gcd( randomInt, number) > 1 ) {
return false ;
}
int checkNumberW = pow( randomInt, ( number - 1 ) / 2 , number) ;
int jacobySignum = ( jacobySign( randomInt, number) + number) % number;
if ( checkNumberW != jacobySignum) {
return false ;
}
}
return true ;
}
/*
Алгоритм Миллера — Рабина параметризуется количеством раундов r. Рекомендуется брать r порядка величины \log_2(m), где m — проверяемое число.
Для данного m находятся такие целое число s и целое нечётное число t, что m-1 = 2^s t.
Выбирается случайное число a, 1 < a < m. Если a не является свидетелем простоты числа m, то выдаётся ответ «m — составное», и алгоритм завершается. Иначе, выбирается новое случайное число a и процедура проверки повторяется.
После нахождения r свидетелей простоты, выдаётся ответ «m — вероятно простое», и алгоритм завершается.
Ввод: m > 2, нечётное натуральное число, которое необходимо проверить на простоту;
r — количество раундов.
Вывод: составное, означает, что m является составным числом;
вероятно простое, означает, что m с высокой вероятностью является простым числом.
Представить m − 1 в виде 2s·t, где t нечётно, можно сделать последовательным делением m - 1 на 2.
цикл А: повторить r раз:
Выбрать случайное целое число a в отрезке [2, m − 2]
x ← at mod m, вычисляется с помощью алгоритма возведения в степень по модулю
если x = 1 или x = m − 1, то перейти на следующую итерацию цикла А
цикл B: повторить s − 1 раз
x ← x2 mod m
если x = 1, то вернуть составное
если x = m − 1, то перейти на следующую итерацию цикла A
вернуть составное
вернуть вероятно простое
*/
// Рекомендуется брать r порядка величины log2(m), где m — проверяемое число. number > 2, нечётное натуральное число
public static boolean isPrimeAccordingToMillerRabin( int number, int roundCount) {
int numberMinus1 = number - 1 ;
int t = numberMinus1;
int s = 0 ;
while ( t % 2 == 0 )
{
t /= 2 ;
s++;
}
for ( int i = 0 ; i < roundCount; i++ ) {
int randomInt = randomIntInRange( 2 , number - 2 ) ;
int x = pow( randomInt, t, number) ;
if ( x == 1 || x == numberMinus1) continue ;
boolean flagToStop = true ;
for ( int j = 0 ; j < s - 1 ; j++ ) {
x = pow( x, 2 , number) ;
if ( x == 1 ) {
return false ;
}
if ( x == numberMinus1) {
flagToStop = false ;
break ;
}
}
if ( flagToStop)
{
return false ;
}
}
return true ;
}
public static boolean isPrime( int n) {
boolean r = true ;
for ( int i
= 2 ; i
<= ( int ) Math .
sqrt ( n
) ; i
++ ) { if ( n % i == 0 ) {
r = false ;
break ;
}
}
return r;
}
public static void generatePossiblePrimeWithLength( int length) {
int primeNumber = 2 , roundCount = 5 ;
boolean f = false ;
while ( ! f) {
primeNumber
= 2 + rnd.
nextInt ( ( int ) Math .
pow ( 2 , length
) - 2 ) ;
for ( int i = 2 ; i < 7 && isPrime( i) ; i++ ) {
if ( primeNumber % i == 0 ) {
f = false ;
break ;
}
else {
f = true ;
}
}
if ( ! isPrimeAccordingToMillerRabin( primeNumber, roundCount) ) {
f = false ;
} ;
}
System .
out .
println ( "Number: " + primeNumber
) ; }
/*
Простое число p называется сильно простым, если существуют целые числа r,s,t, удовлетвоярющие следующим условиям:
1. p+1 имеет большой простой делитель s;
2. p-1 имеет большой простой делитель r;
3. r-1 имеет большой простой делитель t.
В этом определении величина делителей зависит от вида атаки, от которой необходимо защититься.
Алгоритм Гордона (Gordon’s algorithm) для генерации сильно простого числа
Выход: Сильно простое число p.
1. Сгенерировать два больших простых числа s и t одной длины;
2. Выбрать число Gus39.gif. Найти первое простое число в последовательности 2it+1, где i= Gus39.gif, i=i+1. Обозначить это число r=2it+1;
3. Вычислить Gus40.gif;
4. Выбрать целое число Gus42.gif. Найти первое простое число в последовательности Gus41.gif, где j = Gus42.gif, j=j+1. Обозначить это число p=Gus41.gif;
5. Вернуть (p).
*/
public static void generateStrongPrime( ) {
int k = 9 ;
int i0 = 1 ;
int j0 = 1 ;
int s = 0 ;
int t = 0 ;
boolean isp1 = false ;
boolean isp2 = false ;
while ( ! isp1) {
s
= ( int ) Math .
pow ( 2 , k
- 1 ) + rnd.
nextInt ( ( int ) Math .
pow ( 2 , k
) - ( int ) Math .
pow ( 2 , k
- 1 ) ) ; isp1 = isPrime( s) ;
}
while ( ! isp2) {
t
= ( int ) Math .
pow ( 2 , k
- 1 ) + rnd.
nextInt ( ( int ) Math .
pow ( 2 , k
) - ( int ) Math .
pow ( 2 , k
- 1 ) ) ; isp2 = isPrime( t) ;
}
int i = i0;
while ( ! isPrime( 2 * i * t + 1 ) ) {
i++;
}
int r = 2 * i * t + 1 ;
int p0 = 2 * pow( s, r - 2 , r) * s - 1 ;
int j = j0;
while ( ! isPrime( p0 + 2 * j * r * s) ) {
j++;
}
int p = p0 + 2 * j * r * s;
System .
out .
println ( "Number :" + p
) ; }
}
LyogcGFja2FnZSB3aGF0ZXZlcjsgLy8gZG9uJ3QgcGxhY2UgcGFja2FnZSBuYW1lISAqLwoKaW1wb3J0IGphdmEudXRpbC4qOwppbXBvcnQgamF2YS5sYW5nLio7CmltcG9ydCBqYXZhLmlvLio7CgovKioKICogQ3JlYXRlZCBieSDQmNCz0L7RgNGMIG9uIDI1LjEwLjIwMTUuCiAqLwppbXBvcnQgIGphdmEudXRpbC5SYW5kb207CnB1YmxpYyBjbGFzcyBNYWluIHsKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpewogICAgICAgIC8vU3lzdGVtLm91dC5wcmludGxuKGlzUHJpbWVBY2NvcmRpbmdUb01pbGxlclJhYmluKDE5LCA1KSk7CiAgICAgICAgZ2VuZXJhdGVQb3NzaWJsZVByaW1lV2l0aExlbmd0aCgyMCk7CiAgICB9CgoKICAgIHB1YmxpYyBzdGF0aWMgaW50IGdjZChpbnQgYSwgaW50IGIpIHsKICAgICAgICBpZiAoYiA9PSAwKQogICAgICAgICAgICByZXR1cm4gTWF0aC5hYnMoYSk7CiAgICAgICAgcmV0dXJuIGdjZChiLCBhICUgYik7CiAgICB9CgogICAgLyog0KHQuNC80LLQvtC7INGP0LrQvtCx0LgKICAgIDEgKNC/0YDQvtCy0LXRgNC60LAg0LLQt9Cw0LjQvNC90L7QuSDQv9GA0L7RgdGC0L7RgtGLKS4g0JXRgdC70Lgg0J3QntCUIChhLCBiKeKJoDEsINCy0YvRhdC+0LQg0LjQtyDQsNC70LPQvtGA0LjRgtC80LAg0YEg0L7RgtCy0LXRgtC+0LwgMC4KCjIgKNC40L3QuNGG0LjQsNC70LjQt9Cw0YbQuNGPKS4gcjo9MQoKMyAo0L/QtdGA0LXRhdC+0LQg0Log0L/QvtC70L7QttC40YLQtdC70YzQvdGL0Lwg0YfQuNGB0LvQsNC8KS4KINCV0YHQu9C4IGE8MCDRgtC+CiAgYTo9LWEKICDQldGB0LvQuCBiIG1vZCA0ID0gMyDRgtC+IHI6PS1yCiDQmtC+0L3QtdGGINC10YHQu9C4Cgo0ICjQuNC30LHQsNCy0LvQtdC90LjQtSDQvtGCINGH0ZHRgtC90L7RgdGC0LgpLiB0Oj0wCiDQptC40LrQuyDQn9Ce0JrQkCBhIOKAkyDRh9GR0YLQvdC+0LUKICB0Oj10KzEKICBhOj1hLzIKINCa0L7QvdC10YYg0YbQuNC60LvQsAog0JXRgdC70LggdCDigJMg0L3QtdGH0ZHRgtC90L7QtSwg0YLQvgogINCV0YHQu9C4IGIgbW9kIDggPSAzINC40LvQuCA1LCDRgtC+IHI6PS1yLgog0JrQvtC90LXRhiDQtdGB0LvQuAoKNSAo0LrQstCw0LTRgNCw0YLQuNGH0L3Ri9C5INC30LDQutC+0L0g0LLQt9Cw0LjQvNC90L7RgdGC0LgpLiDQldGB0LvQuCBhIG1vZCA0ID0gYiBtb2QgNCA9IDMsINGC0L4gcjo9LXIuCiAgYzo9YTsgYTo9YiBtb2QgYzsgYjo9Yy4KCjYgKNCy0YvRhdC+0LQg0LjQtyDQsNC70LPQvtGA0LjRgtC80LA/KS4g0JXRgdC70LggYeKJoDAsINGC0L4g0LjQtNGC0Lgg0L3QsCDRiNCw0LMgNCwg0LjQvdCw0YfQtSDQstGL0LnRgtC4INC40Lcg0LDQu9Cz0L7RgNC40YLQvNCwINGBINC+0YLQstC10YLQvtC8IHIuCiAgICAgKi8KICAgIHB1YmxpYyBzdGF0aWMgaW50IGphY29ieVNpZ24oaW50IGEsIGludCBiKSAvLyBhIC0g0YbQtdC70L7QtSwgYiAtINC90LDRgtGD0YDQsNC70YzQvdC+0LUgPiAxLCDQvdC10YfQtdGC0L3QvtC1CiAgICB7CiAgICAgICAgaWYgKGdjZCAoYSwgYikgIT0gMSl7CiAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgIH0KCiAgICAgICAgaW50IHIgPSAxOwoKICAgICAgICBpZiAoYSA8IDApewogICAgICAgICAgICBhID0gLWE7CgogICAgICAgICAgICBpZiAoYiAlIDQgPT0gMyl7CiAgICAgICAgICAgICAgICByID0gLXI7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIHdoaWxlIChhICE9IDApCiAgICAgICAgewogICAgICAgICAgICBpbnQgdCA9IDA7CgogICAgICAgICAgICB3aGlsZSAoYSAlIDIgPT0gMCl7CiAgICAgICAgICAgICAgICB0Kys7CiAgICAgICAgICAgICAgICBhIC89IDI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGlmICh0ICUgMiAhPSAwKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBpbnQgbW9kID0gYiAlIDg7CgogICAgICAgICAgICAgICAgaWYgKG1vZCA9PSAzIHx8IG1vZCA9PSA1KQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIHIgPSAtcjsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgaW50IG1vZEEgPSBhICUgNDsKCiAgICAgICAgICAgIGlmICgobW9kQSA9PSBiICUgNCkgJiYgbW9kQSAgPT0gMykgewogICAgICAgICAgICAgICAgciA9IC1yOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGludCBjID0gYTsKICAgICAgICAgICAgYSA9IGIgJSBjOwogICAgICAgICAgICBiID0gYzsKICAgICAgICB9CgogICAgICAgIHJldHVybiByOwogICAgfQoKCiAgICBwdWJsaWMgc3RhdGljIGludCByYW5kb21JbnRJblJhbmdlKGludCBtaW4sIGludCBtYXgpewogICAgICAgIFJhbmRvbSByYW5kID0gbmV3IFJhbmRvbSgpOwogICAgICAgIGludCByYW5kb21OdW0gPSByYW5kLm5leHRJbnQoKG1heCAtIG1pbikgKyAxKSArIG1pbjsKCiAgICAgICAgcmV0dXJuIHJhbmRvbU51bTsKICAgIH0KCgogICAgcHVibGljIHN0YXRpYyBpbnQgcG93KGludCBmb3VuZGF0aW9uLCBpbnQgZGVncmVlLCBpbnQgbW9kZUZvdW5kYXRpb24pewogICAgICAgIGludCBhbnN3ZXIgPSAxOwoKICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IGRlZ3JlZTsgaSsrKXsKICAgICAgICAgICAgYW5zd2VyICo9IGZvdW5kYXRpb247CiAgICAgICAgICAgIGFuc3dlciAlPSBtb2RlRm91bmRhdGlvbjsKICAgICAgICB9CgogICAgICAgIHJldHVybiAgYW5zd2VyOwogICAgfQoKCiAgICAvKgogICAg0JDQu9Cz0L7RgNC40YLQvCDQodC+0LvQvtCy0LXRjyDigJQg0KjRgtGA0LDRgdGB0LXQvdCwIFs2XSDQv9Cw0YDQsNC80LXRgtGA0LjQt9GD0LXRgtGB0Y8g0LrQvtC70LjRh9C10YHRgtCy0L7QvCDRgNCw0YPQvdC00L7QsiBrLgogICAg0JIg0LrQsNC20LTQvtC8INGA0LDRg9C90LTQtSDRgdC70YPRh9Cw0LnQvdGL0Lwg0L7QsdGA0LDQt9C+0Lwg0LLRi9Cx0LjRgNCw0LXRgtGB0Y8g0YfQuNGB0LvQviBhIDwgbi4g0JXRgdC70Lgg0J3QntCUKGEsbikgPiAxLCDRgtC+INCy0YvQvdC+0YHQuNGC0YHRjyDRgNC10YjQtdC90LjQtSwg0YfRgtC+IG4g0YHQvtGB0YLQsNCy0L3QvtC1LgogICAg0JjQvdCw0YfQtSDQv9GA0L7QstC10YDRj9C10YLRgdGPINGB0L/RgNCw0LLQtdC00LvQuNCy0L7RgdGC0Ywg0YHRgNCw0LLQvdC10L3QuNGPIFx0ZXh0c3R5bGUgYV57KG4tMSkvMn0gXGVxdWl2IFxsZWZ0KCB7YVxvdmVyIG59IFxyaWdodCkgXHBtb2R7bn0uCiAgICDQldGB0LvQuCDQvtC90L4g0L3QtSDQstGL0L/QvtC70L3Rj9C10YLRgdGPLCDRgtC+INCy0YvQvdC+0YHQuNGC0YHRjyDRgNC10YjQtdC90LjQtSwg0YfRgtC+IG4g4oCUINGB0L7RgdGC0LDQstC90L7QtS4g0JXRgdC70Lgg0Y3RgtC+INGB0YDQsNCy0L3QtdC90LjQtSDQstGL0L/QvtC70L3Rj9C10YLRgdGPLCDRgtC+IGEg0Y/QstC70Y/QtdGC0YHRjyDRgdCy0LjQtNC10YLQtdC70LXQvCDQv9GA0L7RgdGC0L7RgtGLINGH0LjRgdC70LAgbi4KICAgINCU0LDQu9C10LUg0LLRi9Cx0LjRgNCw0LXRgtGB0Y8g0LTRgNGD0LPQvtC1INGB0LvRg9GH0LDQudC90L7QtSBhINC4INC/0YDQvtGG0LXQtNGD0YDQsCDQv9C+0LLRgtC+0YDRj9C10YLRgdGPLgogICAg0J/QvtGB0LvQtSDQvdCw0YXQvtC20LTQtdC90LjRjyBrINGB0LLQuNC00LXRgtC10LvQtdC5INC/0YDQvtGB0YLQvtGC0Ysg0LIgayDRgNCw0YPQvdC00LDRhSDQstGL0L3QvtGB0LjRgtGB0Y8g0LfQsNC60LvRjtGH0LXQvdC40LUsINGH0YLQviBuINGP0LLQu9GP0LXRgtGB0Y8g0L/RgNC+0YHRgtGL0Lwg0YfQuNGB0LvQvtC8INGBINCy0LXRgNC+0Y/RgtC90L7RgdGC0YzRjiAgMSAtIDJeey1rfSAgLgoKICAgINCS0YXQvtC0OiBuID4gMiwg0YLQtdGB0YLQuNGA0YPQtdC80L7QtSDQvdC10YfRkdGC0L3QvtC1INC90LDRgtGD0YDQsNC70YzQvdC+0LUg0YfQuNGB0LvQvjsKICAgICAgaywg0L/QsNGA0LDQvNC10YLRgCwg0L7Qv9GA0LXQtNC10LvRj9GO0YnQuNC5INGC0L7Rh9C90L7RgdGC0Ywg0YLQtdGB0YLQsC4K0JLRi9GF0L7QtDog0YHQvtGB0YLQsNCy0L3QvtC1LCDQvtC30L3QsNGH0LDQtdGCLCDRh9GC0L4gbiDRgtC+0YfQvdC+INGB0L7RgdGC0LDQstC90L7QtTsKICAgICAgINCy0LXRgNC+0Y/RgtC90L4g0L/RgNC+0YHRgtC+0LUsINC+0LfQvdCw0YfQsNC10YIsINGH0YLQviBuINCy0LXRgNC+0Y/RgtC90L4g0Y/QstC70Y/QtdGC0YHRjyDQv9GA0L7RgdGC0YvQvC4KCmZvciBpID0gMSwgMiwgLi4uLCBrOgogICBhID0g0YHQu9GD0YfQsNC50L3QvtC1INGG0LXQu9C+0LUg0L7RgiAyINC00L4gbiAtIDEsINCy0LrQu9GO0YfQuNGC0LXQu9GM0L3QvjsKICAg0LXRgdC70Lgg0J3QntCUKGEsIG4pID4gMSwg0YLQvtCz0LTQsDoKICAgICAgINCy0YvQstC10YHRgtC4LCDRh9GC0L4gbiDigJQg0YHQvtGB0YLQsNCy0L3QvtC1LCDQuCDQvtGB0YLQsNC90L7QstC40YLRjNGB0Y8uCiAgINC10YHQu9C4IGFeeyhuLTEpLzJ9IFxub3RcZXF1aXYgXGxlZnQoIHthXG92ZXIgbn0gXHJpZ2h0KSBccG1vZHtufSwg0YLQvtCz0LTQsDoKICAgICAgINCy0YvQstC10YHRgtC4LCDRh9GC0L4gbiDigJQg0YHQvtGB0YLQsNCy0L3QvtC1LCDQuCDQvtGB0YLQsNC90L7QstC40YLRjNGB0Y8uCgrQstGL0LLQtdGB0YLQuCwg0YfRgtC+IG4g4oCUICDQv9GA0L7RgdGC0L7QtSAg0YEg0LLQtdGA0L7Rj9GC0L3QvtGB0YLRjNGOIFx0ZXh0c3R5bGUgMSAtIDJeey1rfSAsINC4INC+0YHRgtCw0L3QvtCy0LjRgtGM0YHRjy4KICAgICAqLwoKICAgIHB1YmxpYyBzdGF0aWMgYm9vbGVhbiBpc1ByaW1lQWNjb3JkaW5nVG9Tb2xvdmVpU2h0cmFzc2VuKGludCBudW1iZXIsIGludCBhY2N1cmFjeSl7IC8vbnVtYmVyID4gMiwg0L3QtdGH0ZHRgtC90L7QtSDQvdCw0YLRg9GA0LDQu9GM0L3QvtC1INGH0LjRgdC70L4KICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IGFjY3VyYWN5OyBpKyspewogICAgICAgICAgICBpbnQgcmFuZG9tSW50ID0gcmFuZG9tSW50SW5SYW5nZSgyLCBudW1iZXIgLSAxKTsKCiAgICAgICAgICAgIGlmIChnY2QocmFuZG9tSW50LCBudW1iZXIpID4gMSl7CiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGludCBjaGVja051bWJlclcgPSBwb3cocmFuZG9tSW50LCAobnVtYmVyIC0gMSkgLyAyLCBudW1iZXIpOwogICAgICAgICAgICBpbnQgamFjb2J5U2lnbnVtID0gKGphY29ieVNpZ24ocmFuZG9tSW50LCBudW1iZXIpICsgbnVtYmVyKSAlIG51bWJlcjsKCiAgICAgICAgICAgIGlmIChjaGVja051bWJlclcgIT0gamFjb2J5U2lnbnVtKXsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgoKICAgIC8qCiAgICDQkNC70LPQvtGA0LjRgtC8INCc0LjQu9C70LXRgNCwIOKAlCDQoNCw0LHQuNC90LAg0L/QsNGA0LDQvNC10YLRgNC40LfRg9C10YLRgdGPINC60L7Qu9C40YfQtdGB0YLQstC+0Lwg0YDQsNGD0L3QtNC+0LIgci4g0KDQtdC60L7QvNC10L3QtNGD0LXRgtGB0Y8g0LHRgNCw0YLRjCByINC/0L7RgNGP0LTQutCwINCy0LXQu9C40YfQuNC90YsgXGxvZ18yKG0pLCDQs9C00LUgbSDigJQg0L/RgNC+0LLQtdGA0Y/QtdC80L7QtSDRh9C40YHQu9C+LgoK0JTQu9GPINC00LDQvdC90L7Qs9C+IG0g0L3QsNGF0L7QtNGP0YLRgdGPINGC0LDQutC40LUg0YbQtdC70L7QtSDRh9C40YHQu9C+IHMg0Lgg0YbQtdC70L7QtSDQvdC10YfRkdGC0L3QvtC1INGH0LjRgdC70L4gdCwg0YfRgtC+IG0tMSA9IDJecyB0LgrQktGL0LHQuNGA0LDQtdGC0YHRjyDRgdC70YPRh9Cw0LnQvdC+0LUg0YfQuNGB0LvQviBhLCAxIDwgYSA8IG0uINCV0YHQu9C4IGEg0L3QtSDRj9Cy0LvRj9C10YLRgdGPINGB0LLQuNC00LXRgtC10LvQtdC8INC/0YDQvtGB0YLQvtGC0Ysg0YfQuNGB0LvQsCBtLCDRgtC+INCy0YvQtNCw0ZHRgtGB0Y8g0L7RgtCy0LXRgiDCq20g4oCUINGB0L7RgdGC0LDQstC90L7QtcK7LCDQuCDQsNC70LPQvtGA0LjRgtC8INC30LDQstC10YDRiNCw0LXRgtGB0Y8uINCY0L3QsNGH0LUsINCy0YvQsdC40YDQsNC10YLRgdGPINC90L7QstC+0LUg0YHQu9GD0YfQsNC50L3QvtC1INGH0LjRgdC70L4gYSDQuCDQv9GA0L7RhtC10LTRg9GA0LAg0L/RgNC+0LLQtdGA0LrQuCDQv9C+0LLRgtC+0YDRj9C10YLRgdGPLgrQn9C+0YHQu9C1INC90LDRhdC+0LbQtNC10L3QuNGPIHIg0YHQstC40LTQtdGC0LXQu9C10Lkg0L/RgNC+0YHRgtC+0YLRiywg0LLRi9C00LDRkdGC0YHRjyDQvtGC0LLQtdGCIMKrbSDigJQg0LLQtdGA0L7Rj9GC0L3QviDQv9GA0L7RgdGC0L7QtcK7LCDQuCDQsNC70LPQvtGA0LjRgtC8INC30LDQstC10YDRiNCw0LXRgtGB0Y8uCgogICAgINCS0LLQvtC0OiBtID4gMiwg0L3QtdGH0ZHRgtC90L7QtSDQvdCw0YLRg9GA0LDQu9GM0L3QvtC1INGH0LjRgdC70L4sINC60L7RgtC+0YDQvtC1INC90LXQvtCx0YXQvtC00LjQvNC+INC/0YDQvtCy0LXRgNC40YLRjCDQvdCwINC/0YDQvtGB0YLQvtGC0YM7CiAgICAgICByIOKAlCDQutC+0LvQuNGH0LXRgdGC0LLQviDRgNCw0YPQvdC00L7Qsi4K0JLRi9Cy0L7QtDog0YHQvtGB0YLQsNCy0L3QvtC1LCDQvtC30L3QsNGH0LDQtdGCLCDRh9GC0L4gbSDRj9Cy0LvRj9C10YLRgdGPINGB0L7RgdGC0LDQstC90YvQvCDRh9C40YHQu9C+0Lw7CiAgICAgICDQstC10YDQvtGP0YLQvdC+INC/0YDQvtGB0YLQvtC1LCDQvtC30L3QsNGH0LDQtdGCLCDRh9GC0L4gbSDRgSDQstGL0YHQvtC60L7QuSDQstC10YDQvtGP0YLQvdC+0YHRgtGM0Y4g0Y/QstC70Y/QtdGC0YHRjyDQv9GA0L7RgdGC0YvQvCDRh9C40YHQu9C+0LwuCtCf0YDQtdC00YHRgtCw0LLQuNGC0YwgbSDiiJIgMSDQsiDQstC40LTQtSAyc8K3dCwg0LPQtNC1IHQg0L3QtdGH0ZHRgtC90L4sINC80L7QttC90L4g0YHQtNC10LvQsNGC0Ywg0L/QvtGB0LvQtdC00L7QstCw0YLQtdC70YzQvdGL0Lwg0LTQtdC70LXQvdC40LXQvCBtIC0gMSDQvdCwIDIuCtGG0LjQutC7INCQOiDQv9C+0LLRgtC+0YDQuNGC0YwgciDRgNCw0Lc6CiAgINCS0YvQsdGA0LDRgtGMINGB0LvRg9GH0LDQudC90L7QtSDRhtC10LvQvtC1INGH0LjRgdC70L4gYSDQsiDQvtGC0YDQtdC30LrQtSBbMiwgbSDiiJIgMl0KICAgeCDihpAgYXQgbW9kIG0sINCy0YvRh9C40YHQu9GP0LXRgtGB0Y8g0YEg0L/QvtC80L7RidGM0Y4g0LDQu9Cz0L7RgNC40YLQvNCwINCy0L7Qt9Cy0LXQtNC10L3QuNGPINCyINGB0YLQtdC/0LXQvdGMINC/0L4g0LzQvtC00YPQu9GOCiAgINC10YHQu9C4IHggPSAxINC40LvQuCB4ID0gbSDiiJIgMSwg0YLQviDQv9C10YDQtdC50YLQuCDQvdCwINGB0LvQtdC00YPRjtGJ0YPRjiDQuNGC0LXRgNCw0YbQuNGOINGG0LjQutC70LAg0JAKICAg0YbQuNC60LsgQjog0L/QvtCy0YLQvtGA0LjRgtGMIHMg4oiSIDEg0YDQsNC3CiAgICAgIHgg4oaQIHgyIG1vZCBtCiAgICAgINC10YHQu9C4IHggPSAxLCDRgtC+INCy0LXRgNC90YPRgtGMINGB0L7RgdGC0LDQstC90L7QtQogICAgICDQtdGB0LvQuCB4ID0gbSDiiJIgMSwg0YLQviDQv9C10YDQtdC50YLQuCDQvdCwINGB0LvQtdC00YPRjtGJ0YPRjiDQuNGC0LXRgNCw0YbQuNGOINGG0LjQutC70LAgQQogICDQstC10YDQvdGD0YLRjCDRgdC+0YHRgtCw0LLQvdC+0LUK0LLQtdGA0L3Rg9GC0Ywg0LLQtdGA0L7Rj9GC0L3QviDQv9GA0L7RgdGC0L7QtQogICAgICovCgogICAgLy8g0KDQtdC60L7QvNC10L3QtNGD0LXRgtGB0Y8g0LHRgNCw0YLRjCByINC/0L7RgNGP0LTQutCwINCy0LXQu9C40YfQuNC90YsgbG9nMihtKSwg0LPQtNC1IG0g4oCUINC/0YDQvtCy0LXRgNGP0LXQvNC+0LUg0YfQuNGB0LvQvi4gbnVtYmVyID4gMiwg0L3QtdGH0ZHRgtC90L7QtSDQvdCw0YLRg9GA0LDQu9GM0L3QvtC1INGH0LjRgdC70L4KICAgIHB1YmxpYyBzdGF0aWMgYm9vbGVhbiBpc1ByaW1lQWNjb3JkaW5nVG9NaWxsZXJSYWJpbihpbnQgbnVtYmVyLCBpbnQgcm91bmRDb3VudCl7CiAgICAgICAgaW50IG51bWJlck1pbnVzMSA9IG51bWJlciAtIDE7CiAgICAgICAgaW50IHQgPSBudW1iZXJNaW51czE7CiAgICAgICAgaW50IHMgPSAwOwoKICAgICAgICB3aGlsZSAodCAlIDIgPT0gMCkKICAgICAgICB7CiAgICAgICAgICAgIHQgLz0gMjsKICAgICAgICAgICAgcysrOwogICAgICAgIH0KCiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCByb3VuZENvdW50OyBpKyspewogICAgICAgICAgICBpbnQgcmFuZG9tSW50ID0gcmFuZG9tSW50SW5SYW5nZSgyLCBudW1iZXIgLSAyKTsKICAgICAgICAgICAgaW50IHggPSBwb3cocmFuZG9tSW50LCB0LCBudW1iZXIpOwoKICAgICAgICAgICAgaWYgKHggPT0gMSB8fCB4ID09IG51bWJlck1pbnVzMSkgY29udGludWU7CgogICAgICAgICAgICBib29sZWFuIGZsYWdUb1N0b3AgPSB0cnVlOwoKICAgICAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBzIC0gMTsgaisrKXsKICAgICAgICAgICAgICAgIHggPSBwb3coeCwgMiwgbnVtYmVyKTsKCiAgICAgICAgICAgICAgICBpZiAoeCA9PSAxKXsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgaWYgKHggPT0gbnVtYmVyTWludXMxKXsKICAgICAgICAgICAgICAgICAgICBmbGFnVG9TdG9wID0gZmFsc2U7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGlmIChmbGFnVG9TdG9wKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIHJldHVybiB0cnVlOwogICAgfQoKICAgIHB1YmxpYyBzdGF0aWMgYm9vbGVhbiBpc1ByaW1lKGludCBuKSB7CiAgICAgICAgYm9vbGVhbiByID0gdHJ1ZTsKCiAgICAgICAgZm9yIChpbnQgaSA9IDI7IGkgPD0gKGludCkgTWF0aC5zcXJ0KG4pOyBpKyspIHsKICAgICAgICAgICAgaWYgKG4gJSBpID09IDApIHsKICAgICAgICAgICAgICAgIHIgPSBmYWxzZTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiByOwogICAgfQoKCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgZ2VuZXJhdGVQb3NzaWJsZVByaW1lV2l0aExlbmd0aChpbnQgbGVuZ3RoKSB7CiAgICAgICAgaW50IHByaW1lTnVtYmVyID0gMiwgcm91bmRDb3VudCA9IDU7CiAgICAgICAgYm9vbGVhbiBmID0gZmFsc2U7CiAgICAgICAgUmFuZG9tIHJuZCA9IG5ldyBSYW5kb20oKTsKCiAgICAgICAgd2hpbGUoIWYpIHsKICAgICAgICAgICAgcHJpbWVOdW1iZXIgPSAyICsgcm5kLm5leHRJbnQoKGludCkgTWF0aC5wb3coMiwgbGVuZ3RoKSAtIDIpOwoKICAgICAgICAgICAgZm9yKGludCBpID0gMjsgaSA8IDcgJiYgaXNQcmltZShpKTsgaSsrKXsKICAgICAgICAgICAgICAgIGlmKHByaW1lTnVtYmVyICUgaSA9PSAwKXsKICAgICAgICAgICAgICAgICAgICBmID0gZmFsc2U7CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBmID0gdHJ1ZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgaWYoIWlzUHJpbWVBY2NvcmRpbmdUb01pbGxlclJhYmluKHByaW1lTnVtYmVyLCByb3VuZENvdW50KSl7CiAgICAgICAgICAgICAgICBmID0gZmFsc2U7CiAgICAgICAgICAgIH07CiAgICAgICAgfQoKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oIk51bWJlcjogIiArIHByaW1lTnVtYmVyKTsKICAgIH0KCgogICAgLyoKICAgINCf0YDQvtGB0YLQvtC1INGH0LjRgdC70L4gcCDQvdCw0LfRi9Cy0LDQtdGC0YHRjyDRgdC40LvRjNC90L4g0L/RgNC+0YHRgtGL0LwsINC10YHQu9C4INGB0YPRidC10YHRgtCy0YPRjtGCINGG0LXQu9GL0LUg0YfQuNGB0LvQsCByLHMsdCwg0YPQtNC+0LLQu9C10YLQstC+0Y/RgNGO0YnQuNC1INGB0LvQtdC00YPRjtGJ0LjQvCDRg9GB0LvQvtCy0LjRj9C8OgoxLiBwKzEg0LjQvNC10LXRgiDQsdC+0LvRjNGI0L7QuSDQv9GA0L7RgdGC0L7QuSDQtNC10LvQuNGC0LXQu9GMIHM7CjIuIHAtMSDQuNC80LXQtdGCINCx0L7Qu9GM0YjQvtC5INC/0YDQvtGB0YLQvtC5INC00LXQu9C40YLQtdC70YwgcjsKMy4gci0xINC40LzQtdC10YIg0LHQvtC70YzRiNC+0Lkg0L/RgNC+0YHRgtC+0Lkg0LTQtdC70LjRgtC10LvRjCB0LgrQkiDRjdGC0L7QvCDQvtC/0YDQtdC00LXQu9C10L3QuNC4INCy0LXQu9C40YfQuNC90LAg0LTQtdC70LjRgtC10LvQtdC5INC30LDQstC40YHQuNGCINC+0YIg0LLQuNC00LAg0LDRgtCw0LrQuCwg0L7RgiDQutC+0YLQvtGA0L7QuSDQvdC10L7QsdGF0L7QtNC40LzQviDQt9Cw0YnQuNGC0LjRgtGM0YHRjy4K0JDQu9Cz0L7RgNC40YLQvCDQk9C+0YDQtNC+0L3QsCAoR29yZG9u4oCZcyBhbGdvcml0aG0pINC00LvRjyDQs9C10L3QtdGA0LDRhtC40Lgg0YHQuNC70YzQvdC+INC/0YDQvtGB0YLQvtCz0L4g0YfQuNGB0LvQsArQktGL0YXQvtC0OiDQodC40LvRjNC90L4g0L/RgNC+0YHRgtC+0LUg0YfQuNGB0LvQviBwLgoxLiDQodCz0LXQvdC10YDQuNGA0L7QstCw0YLRjCDQtNCy0LAg0LHQvtC70YzRiNC40YUg0L/RgNC+0YHRgtGL0YUg0YfQuNGB0LvQsCBzINC4IHQg0L7QtNC90L7QuSDQtNC70LjQvdGLOwoyLiDQktGL0LHRgNCw0YLRjCDRh9C40YHQu9C+IEd1czM5LmdpZi4g0J3QsNC50YLQuCDQv9C10YDQstC+0LUg0L/RgNC+0YHRgtC+0LUg0YfQuNGB0LvQviDQsiDQv9C+0YHQu9C10LTQvtCy0LDRgtC10LvRjNC90L7RgdGC0LggMml0KzEsINCz0LTQtSBpPSBHdXMzOS5naWYsIGk9aSsxLiDQntCx0L7Qt9C90LDRh9C40YLRjCDRjdGC0L4g0YfQuNGB0LvQviByPTJpdCsxOwozLiDQktGL0YfQuNGB0LvQuNGC0YwgR3VzNDAuZ2lmOwo0LiDQktGL0LHRgNCw0YLRjCDRhtC10LvQvtC1INGH0LjRgdC70L4gR3VzNDIuZ2lmLiDQndCw0LnRgtC4INC/0LXRgNCy0L7QtSDQv9GA0L7RgdGC0L7QtSDRh9C40YHQu9C+INCyINC/0L7RgdC70LXQtNC+0LLQsNGC0LXQu9GM0L3QvtGB0YLQuCBHdXM0MS5naWYsINCz0LTQtSBqID0gR3VzNDIuZ2lmLCBqPWorMS4g0J7QsdC+0LfQvdCw0YfQuNGC0Ywg0Y3RgtC+INGH0LjRgdC70L4gcD1HdXM0MS5naWY7CjUuINCS0LXRgNC90YPRgtGMIChwKS4KICAgICAqLwoKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBnZW5lcmF0ZVN0cm9uZ1ByaW1lKCkgewogICAgICAgIGludCBrID0gOTsKICAgICAgICBpbnQgaTAgPSAxOwogICAgICAgIGludCBqMCA9IDE7CiAgICAgICAgaW50IHMgPSAwOwogICAgICAgIGludCB0ID0gMDsKCiAgICAgICAgYm9vbGVhbiBpc3AxID0gZmFsc2U7CiAgICAgICAgYm9vbGVhbiBpc3AyID0gZmFsc2U7CgogICAgICAgIFJhbmRvbSBybmQgPSBuZXcgUmFuZG9tKCk7CgogICAgICAgIHdoaWxlKCFpc3AxKSB7CiAgICAgICAgICAgIHMgPSAoaW50KSBNYXRoLnBvdygyLCBrIC0gMSkgKyBybmQubmV4dEludCgoaW50KSBNYXRoLnBvdygyLCBrKSAtIChpbnQpIE1hdGgucG93KDIsIGsgLSAxKSk7CiAgICAgICAgICAgIGlzcDEgPSBpc1ByaW1lKHMpOwogICAgICAgIH0KCiAgICAgICAgd2hpbGUoIWlzcDIpIHsKICAgICAgICAgICAgdCA9IChpbnQpIE1hdGgucG93KDIsIGsgLSAxKSArIHJuZC5uZXh0SW50KChpbnQpIE1hdGgucG93KDIsIGspIC0gKGludCkgTWF0aC5wb3coMiwgayAtIDEpKTsKICAgICAgICAgICAgaXNwMiA9IGlzUHJpbWUodCk7CiAgICAgICAgfQogICAgICAgIGludCBpID0gaTA7CgogICAgICAgIHdoaWxlKCFpc1ByaW1lKDIgKiBpICogdCArIDEpKSB7CiAgICAgICAgICAgIGkrKzsKICAgICAgICB9CiAgICAgICAgaW50IHIgPSAyICogaSAqIHQgKyAxOwogICAgICAgIGludCBwMCA9ICAyICogcG93KHMsIHIgLSAyLCByKSAqIHMgLSAxOwogICAgICAgIGludCBqID0gajA7CgogICAgICAgIHdoaWxlKCFpc1ByaW1lKHAwICsgMiAqIGogKiByICogcykpIHsKICAgICAgICAgICAgaisrOwogICAgICAgIH0KICAgICAgICBpbnQgcCA9IHAwICsgMiAqIGogKiByICogczsKCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJOdW1iZXIgOiIgKyBwKTsKICAgIH0KfQ==