:- use_module( library( lists) ) .
% ----------------------------
% задание 1: шелл (седжвик)
% ----------------------------
% shs(+l, -s)
shs( L, S) :-
length( L, N) ,
sg( N, Gs) ,
sp( Gs, L, S) .
% sg(+n, -gs)
sg( N, Gs) :-
( N =< 1 - > Gs = [ 1 ]
; sgk( N, 0 , [ ] , Rs) ,
reverse( Rs, Gs)
) .
sgk( N, K, A, Rs) :-
hk( K, H) ,
hk( K1, H1) ,
( 3 * H1 > N - >
Rs = [ H| A]
; sgk( N, K1, [ H| A] , Rs)
) .
% hk(+k,-h)
hk( K, H) :-
) .
sp( [ ] , L, L) .
sp( [ G| Gs] , L, S) :-
gp( G, L, L1) ,
sp( Gs, L1, S) .
% gp(+g,+l,-s)
gp( G, L, S) :-
en( L, 0 , Ps) ,
findall ( Ns
, ( between
( 0 , G1
, R
) , cls
( Ps
, G
, R
, Ns
) ) , Bs
) , append( Bs, All) ,
keysort( All, Ss) ,
vs( Ss, S) .
cls( Ps, G, R, Ns) :-
iv( Cs, Vs1, Is1) ,
ins( Vs1, Vs2) ,
pi( Is1, Vs2, Ns) .
pr
( G
, R
, I
- _
) :- 0 is ( I
- R
) mod G
.
en( [ ] , _, [ ] ) .
en( [ X| Xs] , I, [ I- X| Ps] ) :-
en( Xs, I1, Ps) .
iv( [ ] , [ ] , [ ] ) .
iv
( [ I
- V
| T
] , [ V
| Vs
] , [ I
| Is ] ) :- iv
( T
, Vs
, Is ) .
pi( [ ] , [ ] , [ ] ) .
pi
( [ I
| Is ] , [ V
| Vs
] , [ I
- V
| T
] ) :- pi
( Is , Vs
, T
) .
vs( [ ] , [ ] ) .
vs( [ _- V| T] , [ V| Vs] ) :- vs( T, Vs) .
% ins(+l,-s)
ins( [ ] , [ ] ) .
ins( [ X| Xs] , S) :- ins( Xs, S1) , is1( X, S1, S) .
is1( X, [ ] , [ X] ) .
is1( X, [ Y| Ys] , [ X, Y| Ys] ) :- X =< Y, ! .
is1( X, [ Y| Ys] , [ Y| Zs] ) :- is1( X, Ys, Zs) .
% Оценка сложности сортировки Шелла (Sedgewick's sequence): O(N^(4/3)) в среднем, до O(N^(3/2)) в худшем случае
shellsort_complexity( N, Complexity) :-
Complexity
is N
** ( 4 / 3 ) . % Средняя сложность
% Предикат для измерения времени выполнения
time_sort( Predicate, InputList, SortedList, Time) :-
statistics( runtime, [ T1, _] ) ,
call ( Predicate
, InputList
, SortedList
) , statistics( runtime, [ T2, _] ) ,
% Пример использования сортировки Шелла
ex_shs :-
L = [ 3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 , 5 , 3 , 5 ] ,
time_sort( shs, L, S, Time) ,
length( L, N) ,
shellsort_complexity( N, Complexity) ,
format( 'Сортировка Шелла:~n' ) ,
format( ' Исходный список: ~w~n' , [ L] ) ,
format( ' Отсортированный список: ~w~n' , [ S] ) ,
format( ' Время выполнения: ~w мс~n' , [ Time] ) ,
format( ' Оценка сложности (O(N^(4/3))): ~w для N = ~w~n' , [ Complexity, N] ) .
% ----------------------------
% задание 2: бинарные включения
% ----------------------------
% bis(+l,-s)
bis( L, S) :- bis1( L, [ ] , S) .
bis1( [ ] , A, A) .
bis1( [ X| Xs] , A, S) :-
bin_ins( X, A, A1) ,
bis1( Xs, A1, S) .
% bin_ins(+x,+l,-r)
bin_ins( X, L, R) :-
length( L, N) ,
bin_pos( X, L, 0 , N, P) ,
sp2( P, L, A, B) ,
append( A, [ X| B] , R) .
% bin_pos(+x,+l,+lo,+hi,-p)
bin_pos( X, L, Lo, Hi, P) :-
( Lo >= Hi - >
P = Lo
nth0( M, L, V) ,
( X =< V - >
bin_pos( X, L, Lo, M, P)
bin_pos( X, L, M1, Hi, P)
)
) .
% sp2(+k,+l,-a,-b)
sp2( 0 , L, [ ] , L) :- ! .
sp2( K, [ X| Xs] , [ X| A] , B) :-
K > 0 ,
sp2( K1, Xs, A, B) .
% Оценка сложности бинарной вставки: O(N^2) в худшем случае, O(N log N) в среднем (благодаря бинарному поиску)
binary_insertion_complexity( N, Complexity) :-
Complexity
is N
* N
. % Или N * log(N) для среднего случая
% Пример использования бинарных включений
ex_bis :-
L = [ 3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 , 5 , 3 , 5 ] ,
time_sort( bis, L, S, Time) ,
length( L, N) ,
binary_insertion_complexity( N, Complexity) ,
format( 'Бинарные включения:~n' ) ,
format( ' Исходный список: ~w~n' , [ L] ) ,
format( ' Отсортированный список: ~w~n' , [ S] ) ,
format( ' Время выполнения: ~w мс~n' , [ Time] ) ,
format( ' Оценка сложности (O(N^2)): ~w для N = ~w~n' , [ Complexity, N] ) .
% Сравнение эффективности
compare_sorts( List) :-
time_sort( shs, List, _, ShellSortTime) ,
time_sort( bis, List, _, BinaryInsertionTime) ,
length( List, N) ,
shellsort_complexity( N, ShellsortComplexity) ,
binary_insertion_complexity( N, BinaryInsertionComplexity) ,
format( 'Сравнение сортировок:~n' ) ,
format( ' Список для сортировки: ~w~n' , [ List] ) ,
format( ' Длина списка (N): ~w~n' , [ N] ) ,
format( ' Сортировка Шелла (Sedgewick):~n' ) ,
format( ' Время выполнения: ~w мс~n' , [ ShellSortTime] ) ,
format( ' Оценка сложности (O(N^(4/3))): ~w~n' , [ ShellsortComplexity] ) ,
format( ' Сортировка бинарными включениями:~n' ) ,
format( ' Время выполнения: ~w мс~n' , [ BinaryInsertionTime] ) ,
format( ' Оценка сложности (O(N^2)): ~w~n' , [ BinaryInsertionComplexity] ) ,
( ShellSortTime < BinaryInsertionTime - >
format( ' Вывод: Сортировка Шелла быстрее для данного списка.~n' )
; format( ' Вывод: Сортировка бинарными включениями быстрее для данного списка.~n' )
) .
% ----------------------------
% задание 3: "слово из домино" (игра)
% ----------------------------
% igra(-w)
igra( w( I, G, R, A) ) :-
ds( Ts) ,
gr( Ts, 7 , 42 , Ti, T1) , ch( Ti, I) ,
gr( T1, 7 , 42 , Tg, T2) , ch( Tg, G) ,
gr( T2, 7 , 42 , Tr, T3) , ch( Tr, R) ,
T3 = Ta, sm( Ta, 42 ) , ch( Ta, A) .
% ds(-ts)
ds
( Ts
) :- findall ( A
- B
, ( between
( 0 , 6 , A
) , between
( A
, 6 , B
) ) , Ts
) .
% sm(+ts,-s)
sm( [ ] , 0 ) .
sm( [ A- B| T] , S) :-
sm( T, S1) ,
% gr(+ts,+k,+s,-g,-r)
gr( Ts, 0 , 0 , [ ] , Ts) :- ! .
gr( Ts, K, S, [ X| G] , R) :-
K > 0 , S >= 0 ,
select( X, Ts, T1) ,
X = A- B,
gr( T1, K1, S1, G, R) .
% ch(+ts,-c)
ch( Ts, C) :-
select( T, Ts, R) ,
or( T, A- B) ,
ch1( R, B, [ A- B] , C) .
ch1( [ ] , _, A, C) :- reverse( A, C) .
ch1( Ts, X, A, C) :-
select( T, Ts, R) ,
or1( T, X- Y) ,
ch1( R, Y, [ X- Y| A] , C) .
or( A- B, A- B) .
or( A- B, B- A) .
or1( A- B, X- Y) :- ( X= A, Y= B ; X= B, Y= A) .
% Пример использования игры в домино
ex_igra :-
igra( W) ,
format( 'Игра "Слово из домино":~n' ) ,
format( ' Решение: ~w~n' , [ W] ) .
% ----------------------------
% задание 4 (вариант 2): вставка подсписка с i-го элемента
% ----------------------------
% ins_sub(+sub,+l,+i,-r)
ins_sub( Sub, L, I, R) :-
I >= 1 ,
sp2( K, L, P, S) ,
append( P, Sub, T) ,
append( T, S, R) .
% Пример использования вставки подсписка
ex_ins_sub :-
Sub = [ 7 , 8 , 9 ] ,
L = [ 1 , 2 , 3 , 4 , 5 , 6 ] ,
I = 3 ,
ins_sub( Sub, L, I, R) ,
format( 'Вставка подсписка:~n' ) ,
format( ' Исходный список: ~w~n' , [ L] ) ,
format( ' Подсписок: ~w~n' , [ Sub] ) ,
format( ' Индекс вставки: ~w~n' , [ I] ) ,
format( ' Результат: ~w~n' , [ R] ) .
% Запуск всех примеров
run_examples :-
ex_shs,
ex_bis,
List = [ 5 , 2 , 8 , 1 , 9 , 4 , 7 , 3 , 6 , 0 , 5 , 2 , 8 , 1 , 9 , 4 , 7 , 3 , 6 , 0 ] , % Пример списка для сравнения
compare_sorts( List) ,
ex_igra,
ex_ins_sub.
?- run_examples.
Oi0gdXNlX21vZHVsZShsaWJyYXJ5KGxpc3RzKSkuCgolIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KJSDQt9Cw0LTQsNC90LjQtSAxOiDRiNC10LvQuyAo0YHQtdC00LbQstC40LopCiUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKJSBzaHMoK2wsIC1zKQpzaHMoTCwgUykgOi0KICAgIGxlbmd0aChMLCBOKSwKICAgIHNnKE4sIEdzKSwKICAgIHNwKEdzLCBMLCBTKS4KCiUgc2coK24sIC1ncykKc2coTiwgR3MpIDotCiAgICAoIE4gPTwgMSAtPiBHcyA9IFsxXQogICAgOyBzZ2soTiwgMCwgW10sIFJzKSwKICAgICAgcmV2ZXJzZShScywgR3MpCiAgICApLgoKc2drKE4sIEssIEEsIFJzKSA6LQogICAgaGsoSywgSCksCiAgICBLMSBpcyBLICsgMSwKICAgIGhrKEsxLCBIMSksCiAgICAoIDMqSDEgPiBOIC0+CiAgICAgICAgUnMgPSBbSHxBXQogICAgOyAgIHNnayhOLCBLMSwgW0h8QV0sIFJzKQogICAgKS4KCiUgaGsoK2ssLWgpCmhrKEssIEgpIDotCiAgICAoIDAgaXMgSyBtb2QgMiAtPgogICAgICAgIFAyayAgaXMgMSA8PCBLLAogICAgICAgIEsyICAgaXMgSyAvLyAyLAogICAgICAgIFAyazIgaXMgMSA8PCBLMiwKICAgICAgICBIIGlzIDkqUDJrIC0gOSpQMmsyICsgMQogICAgOyAgIFAyayAgaXMgMSA8PCBLLAogICAgICAgIEsyICAgaXMgKEsgKyAxKSAvLyAyLAogICAgICAgIFAyazIgaXMgMSA8PCBLMiwKICAgICAgICBIIGlzIDgqUDJrIC0gNipQMmsyICsgMQogICAgKS4KCnNwKFtdLCBMLCBMKS4Kc3AoW0d8R3NdLCBMLCBTKSA6LQogICAgZ3AoRywgTCwgTDEpLAogICAgc3AoR3MsIEwxLCBTKS4KCiUgZ3AoK2csK2wsLXMpCmdwKEcsIEwsIFMpIDotCiAgICBlbihMLCAwLCBQcyksCiAgICBHMSBpcyBHIC0gMSwKICAgIGZpbmRhbGwoTnMsIChiZXR3ZWVuKDAsIEcxLCBSKSwgY2xzKFBzLCBHLCBSLCBOcykpLCBCcyksCiAgICBhcHBlbmQoQnMsIEFsbCksCiAgICBrZXlzb3J0KEFsbCwgU3MpLAogICAgdnMoU3MsIFMpLgoKY2xzKFBzLCBHLCBSLCBOcykgOi0KICAgIGluY2x1ZGUocHIoRywgUiksIFBzLCBDcyksCiAgICBpdihDcywgVnMxLCBJczEpLAogICAgaW5zKFZzMSwgVnMyKSwKICAgIHBpKElzMSwgVnMyLCBOcykuCgpwcihHLCBSLCBJLV8pIDotIDAgaXMgKEkgLSBSKSBtb2QgRy4KCmVuKFtdLCBfLCBbXSkuCmVuKFtYfFhzXSwgSSwgW0ktWHxQc10pIDotCiAgICBJMSBpcyBJICsgMSwKICAgIGVuKFhzLCBJMSwgUHMpLgoKaXYoW10sIFtdLCBbXSkuCml2KFtJLVZ8VF0sIFtWfFZzXSwgW0l8SXNdKSA6LSBpdihULCBWcywgSXMpLgoKcGkoW10sIFtdLCBbXSkuCnBpKFtJfElzXSwgW1Z8VnNdLCBbSS1WfFRdKSA6LSBwaShJcywgVnMsIFQpLgoKdnMoW10sIFtdKS4KdnMoW18tVnxUXSwgW1Z8VnNdKSA6LSB2cyhULCBWcykuCgolIGlucygrbCwtcykKaW5zKFtdLCBbXSkuCmlucyhbWHxYc10sIFMpIDotIGlucyhYcywgUzEpLCBpczEoWCwgUzEsIFMpLgoKaXMxKFgsIFtdLCBbWF0pLgppczEoWCwgW1l8WXNdLCBbWCxZfFlzXSkgOi0gWCA9PCBZLCAhLgppczEoWCwgW1l8WXNdLCBbWXxac10pIDotIGlzMShYLCBZcywgWnMpLgoKJSDQntGG0LXQvdC60LAg0YHQu9C+0LbQvdC+0YHRgtC4INGB0L7RgNGC0LjRgNC+0LLQutC4INCo0LXQu9C70LAgKFNlZGdld2ljaydzIHNlcXVlbmNlKTogTyhOXig0LzMpKSDQsiDRgdGA0LXQtNC90LXQvCwg0LTQviBPKE5eKDMvMikpICDQsiDRhdGD0LTRiNC10Lwg0YHQu9GD0YfQsNC1CnNoZWxsc29ydF9jb21wbGV4aXR5KE4sIENvbXBsZXhpdHkpIDotCiAgICBDb21wbGV4aXR5IGlzIE4qKig0LzMpLiAgJSDQodGA0LXQtNC90Y/RjyDRgdC70L7QttC90L7RgdGC0YwKCiUg0J/RgNC10LTQuNC60LDRgiDQtNC70Y8g0LjQt9C80LXRgNC10L3QuNGPINCy0YDQtdC80LXQvdC4INCy0YvQv9C+0LvQvdC10L3QuNGPCnRpbWVfc29ydChQcmVkaWNhdGUsIElucHV0TGlzdCwgU29ydGVkTGlzdCwgVGltZSkgOi0KICAgIHN0YXRpc3RpY3MocnVudGltZSwgW1QxLCBfXSksCiAgICBjYWxsKFByZWRpY2F0ZSwgSW5wdXRMaXN0LCBTb3J0ZWRMaXN0KSwKICAgIHN0YXRpc3RpY3MocnVudGltZSwgW1QyLCBfXSksCiAgICBUaW1lIGlzIFQyIC0gVDEuCgoKJSDQn9GA0LjQvNC10YAg0LjRgdC/0L7Qu9GM0LfQvtCy0LDQvdC40Y8g0YHQvtGA0YLQuNGA0L7QstC60Lgg0KjQtdC70LvQsApleF9zaHMgOi0KICAgIEwgPSBbMywgMSwgNCwgMSwgNSwgOSwgMiwgNiwgNSwgMywgNV0sCiAgICB0aW1lX3NvcnQoc2hzLCBMLCBTLCBUaW1lKSwKICAgIGxlbmd0aChMLCBOKSwKICAgIHNoZWxsc29ydF9jb21wbGV4aXR5KE4sIENvbXBsZXhpdHkpLAogICAgZm9ybWF0KCfQodC+0YDRgtC40YDQvtCy0LrQsCDQqNC10LvQu9CwOn5uJyksCiAgICBmb3JtYXQoJyAg0JjRgdGF0L7QtNC90YvQuSDRgdC/0LjRgdC+0Lo6IH53fm4nLCBbTF0pLAogICAgZm9ybWF0KCcgINCe0YLRgdC+0YDRgtC40YDQvtCy0LDQvdC90YvQuSDRgdC/0LjRgdC+0Lo6IH53fm4nLCBbU10pLAogICBmb3JtYXQoJyAg0JLRgNC10LzRjyDQstGL0L/QvtC70L3QtdC90LjRjzogfncg0LzRgX5uJywgW1RpbWVdKSwKICAgIGZvcm1hdCgnICDQntGG0LXQvdC60LAg0YHQu9C+0LbQvdC+0YHRgtC4IChPKE5eKDQvMykpKTogfncg0LTQu9GPIE4gPSB+d35uJywgW0NvbXBsZXhpdHksIE5dKS4KCgolIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KJSDQt9Cw0LTQsNC90LjQtSAyOiDQsdC40L3QsNGA0L3Ri9C1INCy0LrQu9GO0YfQtdC90LjRjwolIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiUgYmlzKCtsLC1zKQpiaXMoTCwgUykgOi0gYmlzMShMLCBbXSwgUykuCgpiaXMxKFtdLCBBLCBBKS4KYmlzMShbWHxYc10sIEEsIFMpIDotCiAgICBiaW5faW5zKFgsIEEsIEExKSwKICAgIGJpczEoWHMsIEExLCBTKS4KCiUgYmluX2lucygreCwrbCwtcikKYmluX2lucyhYLCBMLCBSKSA6LQogICAgbGVuZ3RoKEwsIE4pLAogICAgYmluX3BvcyhYLCBMLCAwLCBOLCBQKSwKICAgIHNwMihQLCBMLCBBLCBCKSwKICAgIGFwcGVuZChBLCBbWHxCXSwgUikuCgolIGJpbl9wb3MoK3gsK2wsK2xvLCtoaSwtcCkKYmluX3BvcyhYLCBMLCBMbywgSGksIFApIDotCiAgICAoIExvID49IEhpIC0+CiAgICAgICAgUCA9IExvCiAgICA7IE0gaXMgKExvICsgSGkpIC8vIDIsCiAgICAgIG50aDAoTSwgTCwgViksCiAgICAgICggWCA9PCBWIC0+CiAgICAgICAgICBiaW5fcG9zKFgsIEwsIExvLCBNLCBQKQogICAgICA7IE0xIGlzIE0gKyAxLAogICAgICAgIGJpbl9wb3MoWCwgTCwgTTEsIEhpLCBQKQogICAgICApCiAgICApLgoKJSBzcDIoK2ssK2wsLWEsLWIpCnNwMigwLCBMLCBbXSwgTCkgOi0gIS4Kc3AyKEssIFtYfFhzXSwgW1h8QV0sIEIpIDotCiAgICBLID4gMCwKICAgIEsxIGlzIEsgLSAxLAogICAgc3AyKEsxLCBYcywgQSwgQikuCgolINCe0YbQtdC90LrQsCDRgdC70L7QttC90L7RgdGC0Lgg0LHQuNC90LDRgNC90L7QuSDQstGB0YLQsNCy0LrQuDogTyhOXjIpINCyINGF0YPQtNGI0LXQvCDRgdC70YPRh9Cw0LUsIE8oTiBsb2cgTikg0LIg0YHRgNC10LTQvdC10LwgKNCx0LvQsNCz0L7QtNCw0YDRjyDQsdC40L3QsNGA0L3QvtC80YMg0L/QvtC40YHQutGDKQpiaW5hcnlfaW5zZXJ0aW9uX2NvbXBsZXhpdHkoTiwgQ29tcGxleGl0eSkgOi0KICAgIENvbXBsZXhpdHkgaXMgTipOLiAgJSDQmNC70LggTiAqIGxvZyhOKSDQtNC70Y8g0YHRgNC10LTQvdC10LPQviDRgdC70YPRh9Cw0Y8KCiUg0J/RgNC40LzQtdGAINC40YHQv9C+0LvRjNC30L7QstCw0L3QuNGPINCx0LjQvdCw0YDQvdGL0YUg0LLQutC70Y7Rh9C10L3QuNC5CmV4X2JpcyA6LQogICAgTCA9IFszLCAxLCA0LCAxLCA1LCA5LCAyLCA2LCA1LCAzLCA1XSwKICAgIHRpbWVfc29ydChiaXMsIEwsIFMsIFRpbWUpLAogICAgbGVuZ3RoKEwsIE4pLAogICAgYmluYXJ5X2luc2VydGlvbl9jb21wbGV4aXR5KE4sIENvbXBsZXhpdHkpLAogICAgZm9ybWF0KCfQkdC40L3QsNGA0L3Ri9C1INCy0LrQu9GO0YfQtdC90LjRjzp+bicpLAogICAgZm9ybWF0KCcgINCY0YHRhdC+0LTQvdGL0Lkg0YHQv9C40YHQvtC6OiB+d35uJywgW0xdKSwKICAgIGZvcm1hdCgnICDQntGC0YHQvtGA0YLQuNGA0L7QstCw0L3QvdGL0Lkg0YHQv9C40YHQvtC6OiB+d35uJywgW1NdKSwKICAgICAgICBmb3JtYXQoJyAg0JLRgNC10LzRjyDQstGL0L/QvtC70L3QtdC90LjRjzogfncg0LzRgX5uJywgW1RpbWVdKSwKICAgIGZvcm1hdCgnICDQntGG0LXQvdC60LAg0YHQu9C+0LbQvdC+0YHRgtC4IChPKE5eMikpOiB+dyDQtNC70Y8gTiA9IH53fm4nLCBbQ29tcGxleGl0eSwgTl0pLgoKJSDQodGA0LDQstC90LXQvdC40LUg0Y3RhNGE0LXQutGC0LjQstC90L7RgdGC0LgKY29tcGFyZV9zb3J0cyhMaXN0KSA6LQogICAgdGltZV9zb3J0KHNocywgTGlzdCwgXywgU2hlbGxTb3J0VGltZSksCiAgICB0aW1lX3NvcnQoYmlzLCBMaXN0LCBfLCBCaW5hcnlJbnNlcnRpb25UaW1lKSwKICAgIGxlbmd0aChMaXN0LCBOKSwKICAgIHNoZWxsc29ydF9jb21wbGV4aXR5KE4sIFNoZWxsc29ydENvbXBsZXhpdHkpLAogICAgYmluYXJ5X2luc2VydGlvbl9jb21wbGV4aXR5KE4sIEJpbmFyeUluc2VydGlvbkNvbXBsZXhpdHkpLAoKICAgIGZvcm1hdCgn0KHRgNCw0LLQvdC10L3QuNC1INGB0L7RgNGC0LjRgNC+0LLQvtC6On5uJyksCiAgICBmb3JtYXQoJyAg0KHQv9C40YHQvtC6INC00LvRjyDRgdC+0YDRgtC40YDQvtCy0LrQuDogfnd+bicsIFtMaXN0XSksCiAgICBmb3JtYXQoJyAg0JTQu9C40L3QsCDRgdC/0LjRgdC60LAgKE4pOiB+d35uJywgW05dKSwKCiAgICBmb3JtYXQoJyAg0KHQvtGA0YLQuNGA0L7QstC60LAg0KjQtdC70LvQsCAoU2VkZ2V3aWNrKTp+bicpLAogICAgZm9ybWF0KCcgICAg0JLRgNC10LzRjyDQstGL0L/QvtC70L3QtdC90LjRjzogfncg0LzRgX5uJywgW1NoZWxsU29ydFRpbWVdKSwKICAgIGZvcm1hdCgnICAgINCe0YbQtdC90LrQsCDRgdC70L7QttC90L7RgdGC0LggKE8oTl4oNC8zKSkpOiB+d35uJywgW1NoZWxsc29ydENvbXBsZXhpdHldKSwKCiAgICBmb3JtYXQoJyAg0KHQvtGA0YLQuNGA0L7QstC60LAg0LHQuNC90LDRgNC90YvQvNC4INCy0LrQu9GO0YfQtdC90LjRj9C80Lg6fm4nKSwKICAgIGZvcm1hdCgnICAgINCS0YDQtdC80Y8g0LLRi9C/0L7Qu9C90LXQvdC40Y86IH53INC80YF+bicsIFtCaW5hcnlJbnNlcnRpb25UaW1lXSksCiAgICBmb3JtYXQoJyAgICDQntGG0LXQvdC60LAg0YHQu9C+0LbQvdC+0YHRgtC4IChPKE5eMikpOiB+d35uJywgW0JpbmFyeUluc2VydGlvbkNvbXBsZXhpdHldKSwKCiAgICAoU2hlbGxTb3J0VGltZSA8IEJpbmFyeUluc2VydGlvblRpbWUgLT4KICAgICAgICBmb3JtYXQoJyAg0JLRi9Cy0L7QtDog0KHQvtGA0YLQuNGA0L7QstC60LAg0KjQtdC70LvQsCDQsdGL0YHRgtGA0LXQtSDQtNC70Y8g0LTQsNC90L3QvtCz0L4g0YHQv9C40YHQutCwLn5uJykKICAgIDsgICBmb3JtYXQoJyAg0JLRi9Cy0L7QtDog0KHQvtGA0YLQuNGA0L7QstC60LAg0LHQuNC90LDRgNC90YvQvNC4INCy0LrQu9GO0YfQtdC90LjRj9C80Lgg0LHRi9GB0YLRgNC10LUg0LTQu9GPINC00LDQvdC90L7Qs9C+INGB0L/QuNGB0LrQsC5+bicpCiAgICApLgoKCgolIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KJSDQt9Cw0LTQsNC90LjQtSAzOiAi0YHQu9C+0LLQviDQuNC3INC00L7QvNC40L3QviIgKNC40LPRgNCwKQolIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiUgaWdyYSgtdykKaWdyYSh3KEksIEcsIFIsIEEpKSA6LQogICAgZHMoVHMpLAogICAgZ3IoVHMsIDcsIDQyLCBUaSwgVDEpLCBjaChUaSwgSSksCiAgICBncihUMSwgNywgNDIsIFRnLCBUMiksIGNoKFRnLCBHKSwKICAgIGdyKFQyLCA3LCA0MiwgVHIsIFQzKSwgY2goVHIsIFIpLAogICAgVDMgPSBUYSwgc20oVGEsIDQyKSwgY2goVGEsIEEpLgoKJSBkcygtdHMpCmRzKFRzKSA6LSBmaW5kYWxsKEEtQiwgKGJldHdlZW4oMCw2LEEpLCBiZXR3ZWVuKEEsNixCKSksIFRzKS4KCiUgc20oK3RzLC1zKQpzbShbXSwgMCkuCnNtKFtBLUJ8VF0sIFMpIDotCiAgICBzbShULCBTMSksCiAgICBTIGlzIFMxICsgQSArIEIuCgolIGdyKCt0cywraywrcywtZywtcikKZ3IoVHMsIDAsIDAsIFtdLCBUcykgOi0gIS4KZ3IoVHMsIEssIFMsIFtYfEddLCBSKSA6LQogICAgSyA+IDAsIFMgPj0gMCwKICAgIHNlbGVjdChYLCBUcywgVDEpLAogICAgWCA9IEEtQiwKICAgIFMxIGlzIFMgLSAoQSArIEIpLAogICAgSzEgaXMgSyAtIDEsCiAgICBncihUMSwgSzEsIFMxLCBHLCBSKS4KCiUgY2goK3RzLC1jKQpjaChUcywgQykgOi0KICAgIHNlbGVjdChULCBUcywgUiksCiAgICBvcihULCBBLUIpLAogICAgY2gxKFIsIEIsIFtBLUJdLCBDKS4KCmNoMShbXSwgXywgQSwgQykgOi0gcmV2ZXJzZShBLCBDKS4KY2gxKFRzLCBYLCBBLCBDKSA6LQogICAgc2VsZWN0KFQsIFRzLCBSKSwKICAgIG9yMShULCBYLVkpLAogICAgY2gxKFIsIFksIFtYLVl8QV0sIEMpLgoKb3IoQS1CLCBBLUIpLgpvcihBLUIsIEItQSkuCgpvcjEoQS1CLCBYLVkpIDotIChYPUEsIFk9QiA7IFg9QiwgWT1BKS4KCiUg0J/RgNC40LzQtdGAINC40YHQv9C+0LvRjNC30L7QstCw0L3QuNGPINC40LPRgNGLINCyINC00L7QvNC40L3QvgpleF9pZ3JhIDotCiAgICBpZ3JhKFcpLAogICAgZm9ybWF0KCfQmNCz0YDQsCAi0KHQu9C+0LLQviDQuNC3INC00L7QvNC40L3QviI6fm4nKSwKICAgIGZvcm1hdCgnICDQoNC10YjQtdC90LjQtTogfnd+bicsIFtXXSkuCgolIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KJSDQt9Cw0LTQsNC90LjQtSA0ICjQstCw0YDQuNCw0L3RgiAyKTog0LLRgdGC0LDQstC60LAg0L/QvtC00YHQv9C40YHQutCwINGBIGkt0LPQviDRjdC70LXQvNC10L3RgtCwCiUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKJSBpbnNfc3ViKCtzdWIsK2wsK2ksLXIpCmluc19zdWIoU3ViLCBMLCBJLCBSKSA6LQogICAgSSA+PSAxLAogICAgSyBpcyBJIC0gMSwKICAgIHNwMihLLCBMLCBQLCBTKSwKICAgIGFwcGVuZChQLCBTdWIsIFQpLAogICAgYXBwZW5kKFQsIFMsIFIpLgoKJSDQn9GA0LjQvNC10YAg0LjRgdC/0L7Qu9GM0LfQvtCy0LDQvdC40Y8g0LLRgdGC0LDQstC60Lgg0L/QvtC00YHQv9C40YHQutCwCmV4X2luc19zdWIgOi0KICAgIFN1YiA9IFs3LCA4LCA5XSwKICAgIEwgPSBbMSwgMiwgMywgNCwgNSwgNl0sCiAgICBJID0gMywKICAgIGluc19zdWIoU3ViLCBMLCBJLCBSKSwKICAgIGZvcm1hdCgn0JLRgdGC0LDQstC60LAg0L/QvtC00YHQv9C40YHQutCwOn5uJyksCiAgICBmb3JtYXQoJyAg0JjRgdGF0L7QtNC90YvQuSDRgdC/0LjRgdC+0Lo6IH53fm4nLCBbTF0pLAogICAgZm9ybWF0KCcgINCf0L7QtNGB0L/QuNGB0L7Qujogfnd+bicsIFtTdWJdKSwKICAgIGZvcm1hdCgnICDQmNC90LTQtdC60YEg0LLRgdGC0LDQstC60Lg6IH53fm4nLCBbSV0pLAogICAgZm9ybWF0KCcgINCg0LXQt9GD0LvRjNGC0LDRgjogfnd+bicsIFtSXSkuCgolINCX0LDQv9GD0YHQuiDQstGB0LXRhSDQv9GA0LjQvNC10YDQvtCyCnJ1bl9leGFtcGxlcyA6LQogICAgZXhfc2hzLAogICAgZXhfYmlzLAogICAgTGlzdCA9IFs1LCAyLCA4LCAxLCA5LCA0LCA3LCAzLCA2LCAwLCA1LCAyLCA4LCAxLCA5LCA0LCA3LCAzLCA2LCAwXSwgJSDQn9GA0LjQvNC10YAg0YHQv9C40YHQutCwINC00LvRjyDRgdGA0LDQstC90LXQvdC40Y8KICAgIGNvbXBhcmVfc29ydHMoTGlzdCksCiAgICAgZXhfaWdyYSwKICAgIGV4X2luc19zdWIuCiAgICAKICAgID8tIHJ1bl9leGFtcGxlcy4=