with Ada.Exceptions;
use Ada.Exceptions;
with Ada.Numerics.Elementary_Functions;
use Ada.Numerics.Elementary_Functions;
with Ada.Finalization;
with Ada.Calendar;
with Ada.Unchecked_Deallocation;
with Ada.Numerics.Generic_Complex_Types;
with Ada.Text_IO.Complex_IO;
with Ada.Text_IO;
use Ada.Text_IO;
with Ada.Streams;
use Ada.Streams;
-- ideone requires that top-level procedures in Ada are called Prog.
procedure Prog is
-- We want to use complex numbers, which are defined in the Ada standard
-- library as a generic. (So you get to pick which precision you want.)
package Complex_Types is new Ada.Numerics.Generic_Complex_Types(float);
use Complex_Types;
-- Configuration constants.
bitmapsize: constant := 128; -- pixels
maxiterations: constant := 32;
threads: constant := 4;
-- Returns the intensity of a single point in the Mandelbrot set.
function RenderPixel(c: Complex) return float is
z: Complex := Complex'(0.0, 0.0);
begin
for n in integer range 0..maxiterations loop
z := z*z + c;
if (abs z > 2.0) then
return float(n) / float(maxiterations);
end if;
end loop;
return 0.0;
end;
-- The bitmap (well, floatmap) which the rendered Mandelbrot is going to
-- live in.
type Bitmap is array(integer range <>, integer range <>) of float;
type BitmapRef is access Bitmap;
-- Encapsulates the multithreaded render: creates a bunch of workers
-- and a scheduler, which hands out work units to the renderers.
procedure Mandelbrot(data: BitmapRef;
r1, i1, r2, i2: float) is
width: integer := data'length(1);
height: integer := data'length(2);
xdelta: float := (r2-r1) / float(width);
ydelta: float := (i2-i1) / float(height);
task Scheduler is
-- Each worker calls this to find out what it needs to do.
entry RequestWorkUnit(y: out integer; i: out float);
end;
task body Scheduler is
begin
-- Hand out each scanline in turn to tasks that want things to
-- do, then exit.
for yy in data'range(2) loop
accept RequestWorkUnit(y: out integer; i: out float) do
y := yy;
i := i1 + float(yy)*ydelta;
end RequestWorkUnit;
end loop;
end;
-- Actually does the rendering. Each of these is self contained and will
-- keep working until there's nothing left to do, at which point it
-- exits.
task type Worker;
task body Worker is
y: integer;
i: float;
c: Complex;
begin
-- Keep asking for stuff to do, then do it. When the Scheduler
-- has terminated, requesting a work unit will throw an exception and
-- the task will safely exit.
loop
Scheduler.RequestWorkUnit(y, i);
for x in data'range(1) loop
c := Complex'(r1 + float(x)*xdelta, i);
data(x, y) := RenderPixel(c);
end loop;
end loop;
end;
-- Create some work threads (which will automatically start).
scanlines: array(integer range 1..threads) of Worker;
begin
null; -- nothing to do in the main body, just wait for tasks to exit
end;
-- This sucks, but I couldn't find any other way to get ideone to emit
-- Unicode procedurally. (The UTF-8 representation of each of these is
-- three bytes. Coincidence? I think not.)
glyphs: constant array(0..255) of string(1..3) :=
("⠀", "⠁", "⠂", "⠃", "⠄", "⠅", "⠆", "⠇", "⠈", "⠉", "⠊", "⠋", "⠌", "⠍",
"⠎", "⠏", "⠐", "⠑", "⠒", "⠓", "⠔", "⠕", "⠖", "⠗", "⠘", "⠙", "⠚", "⠛",
"⠜", "⠝", "⠞", "⠟", "⠠", "⠡", "⠢", "⠣", "⠤", "⠥", "⠦", "⠧", "⠨", "⠩",
"⠪", "⠫", "⠬", "⠭", "⠮", "⠯", "⠰", "⠱", "⠲", "⠳", "⠴", "⠵", "⠶", "⠷",
"⠸", "⠹", "⠺", "⠻", "⠼", "⠽", "⠾", "⠿", "⡀", "⡁", "⡂", "⡃", "⡄", "⡅",
"⡆", "⡇", "⡈", "⡉", "⡊", "⡋", "⡌", "⡍", "⡎", "⡏", "⡐", "⡑", "⡒", "⡓",
"⡔", "⡕", "⡖", "⡗", "⡘", "⡙", "⡚", "⡛", "⡜", "⡝", "⡞", "⡟", "⡠", "⡡",
"⡢", "⡣", "⡤", "⡥", "⡦", "⡧", "⡨", "⡩", "⡪", "⡫", "⡬", "⡭", "⡮", "⡯",
"⡰", "⡱", "⡲", "⡳", "⡴", "⡵", "⡶", "⡷", "⡸", "⡹", "⡺", "⡻", "⡼", "⡽",
"⡾", "⡿", "⢀", "⢁", "⢂", "⢃", "⢄", "⢅", "⢆", "⢇", "⢈", "⢉", "⢊", "⢋",
"⢌", "⢍", "⢎", "⢏", "⢐", "⢑", "⢒", "⢓", "⢔", "⢕", "⢖", "⢗", "⢘", "⢙",
"⢚", "⢛", "⢜", "⢝", "⢞", "⢟", "⢠", "⢡", "⢢", "⢣", "⢤", "⢥", "⢦", "⢧",
"⢨", "⢩", "⢪", "⢫", "⢬", "⢭", "⢮", "⢯", "⢰", "⢱", "⢲", "⢳", "⢴", "⢵",
"⢶", "⢷", "⢸", "⢹", "⢺", "⢻", "⢼", "⢽", "⢾", "⢿", "⣀", "⣁", "⣂", "⣃",
"⣄", "⣅", "⣆", "⣇", "⣈", "⣉", "⣊", "⣋", "⣌", "⣍", "⣎", "⣏", "⣐", "⣑",
"⣒", "⣓", "⣔", "⣕", "⣖", "⣗", "⣘", "⣙", "⣚", "⣛", "⣜", "⣝", "⣞", "⣟",
"⣠", "⣡", "⣢", "⣣", "⣤", "⣥", "⣦", "⣧", "⣨", "⣩", "⣪", "⣫", "⣬", "⣭",
"⣮", "⣯", "⣰", "⣱", "⣲", "⣳", "⣴", "⣵", "⣶", "⣷", "⣸", "⣹", "⣺", "⣻",
"⣼", "⣽", "⣾", "⣿");
-- Writes the bitmap to stdout, using funky Unicode hackery to make it
-- look pretty. Sort of.
procedure DumpBitmap(data: BitmapRef) is
function IsSet(x, y: integer) return boolean is
begin
return data(x, y) > 0.0;
end;
type byte is mod 2**8;
x, y: integer;
b: byte;
begin
y := 0;
while (y <= data'last(2)) loop
x := 0;
while (x < data'last(1)) loop
b := 0;
if IsSet(x+0, y+0) then b := b or 1; end if;
if IsSet(x+0, y+1) then b := b or 2; end if;
if IsSet(x+0, y+2) then b := b or 4; end if;
if IsSet(x+0, y+3) then b := b or 64; end if;
if IsSet(x+1, y+0) then b := b or 8; end if;
if IsSet(x+1, y+1) then b := b or 16; end if;
if IsSet(x+1, y+2) then b := b or 32; end if;
if IsSet(x+1, y+3) then b := b or 128; end if;
Put(glyphs(byte'pos(b)));
x := x + 2;
end loop;
Put_Line("");
y := y + 4;
end loop;
end;
image: BitmapRef;
width: constant := bitmapsize;
height: constant := width;
begin
-- Render, print, then leak a bitmap.
image := new Bitmap(0..(width-1), 0..(height-1));
Mandelbrot(image, -2.0, -2.0, +2.0, +2.0);
DumpBitmap(image);
exception
when e: others =>
Put_Line(Exception_Information(e));
end;
d2l0aCBBZGEuRXhjZXB0aW9uczsKdXNlIEFkYS5FeGNlcHRpb25zOwp3aXRoIEFkYS5OdW1lcmljcy5FbGVtZW50YXJ5X0Z1bmN0aW9uczsKdXNlIEFkYS5OdW1lcmljcy5FbGVtZW50YXJ5X0Z1bmN0aW9uczsKd2l0aCBBZGEuRmluYWxpemF0aW9uOwp3aXRoIEFkYS5DYWxlbmRhcjsKd2l0aCBBZGEuVW5jaGVja2VkX0RlYWxsb2NhdGlvbjsKd2l0aCBBZGEuTnVtZXJpY3MuR2VuZXJpY19Db21wbGV4X1R5cGVzOwp3aXRoIEFkYS5UZXh0X0lPLkNvbXBsZXhfSU87CndpdGggQWRhLlRleHRfSU87CnVzZSBBZGEuVGV4dF9JTzsKd2l0aCBBZGEuU3RyZWFtczsKdXNlIEFkYS5TdHJlYW1zOwoKLS0gaWRlb25lIHJlcXVpcmVzIHRoYXQgdG9wLWxldmVsIHByb2NlZHVyZXMgaW4gQWRhIGFyZSBjYWxsZWQgUHJvZy4KcHJvY2VkdXJlIFByb2cgaXMKICAtLSBXZSB3YW50IHRvIHVzZSBjb21wbGV4IG51bWJlcnMsIHdoaWNoIGFyZSBkZWZpbmVkIGluIHRoZSBBZGEgc3RhbmRhcmQKICAtLSBsaWJyYXJ5IGFzIGEgZ2VuZXJpYy4gKFNvIHlvdSBnZXQgdG8gcGljayB3aGljaCBwcmVjaXNpb24geW91IHdhbnQuKQogIHBhY2thZ2UgQ29tcGxleF9UeXBlcyBpcyBuZXcgQWRhLk51bWVyaWNzLkdlbmVyaWNfQ29tcGxleF9UeXBlcyhmbG9hdCk7CiAgdXNlIENvbXBsZXhfVHlwZXM7CgogIC0tIENvbmZpZ3VyYXRpb24gY29uc3RhbnRzLgogIGJpdG1hcHNpemU6IGNvbnN0YW50IDo9IDEyODsgLS0gcGl4ZWxzCiAgbWF4aXRlcmF0aW9uczogY29uc3RhbnQgOj0gMzI7CiAgdGhyZWFkczogY29uc3RhbnQgOj0gNDsKCiAgLS0gUmV0dXJucyB0aGUgaW50ZW5zaXR5IG9mIGEgc2luZ2xlIHBvaW50IGluIHRoZSBNYW5kZWxicm90IHNldC4KICBmdW5jdGlvbiBSZW5kZXJQaXhlbChjOiBDb21wbGV4KSByZXR1cm4gZmxvYXQgaXMKICAgIHo6IENvbXBsZXggOj0gQ29tcGxleCcoMC4wLCAwLjApOwogIGJlZ2luCiAgICBmb3IgbiBpbiBpbnRlZ2VyIHJhbmdlIDAuLm1heGl0ZXJhdGlvbnMgbG9vcAogICAgICB6IDo9IHoqeiArIGM7CiAgICAgIGlmIChhYnMgeiA+IDIuMCkgdGhlbgogICAgICAgIHJldHVybiBmbG9hdChuKSAvIGZsb2F0KG1heGl0ZXJhdGlvbnMpOwogICAgICBlbmQgaWY7CiAgICBlbmQgbG9vcDsKICAgIHJldHVybiAwLjA7CiAgZW5kOwoKICAtLSBUaGUgYml0bWFwICh3ZWxsLCBmbG9hdG1hcCkgd2hpY2ggdGhlIHJlbmRlcmVkIE1hbmRlbGJyb3QgaXMgZ29pbmcgdG8KICAtLSBsaXZlIGluLgogIHR5cGUgQml0bWFwIGlzIGFycmF5KGludGVnZXIgcmFuZ2UgPD4sIGludGVnZXIgcmFuZ2UgPD4pIG9mIGZsb2F0OwogIHR5cGUgQml0bWFwUmVmIGlzIGFjY2VzcyBCaXRtYXA7CgogIC0tIEVuY2Fwc3VsYXRlcyB0aGUgbXVsdGl0aHJlYWRlZCByZW5kZXI6IGNyZWF0ZXMgYSBidW5jaCBvZiB3b3JrZXJzCiAgLS0gYW5kIGEgc2NoZWR1bGVyLCB3aGljaCBoYW5kcyBvdXQgd29yayB1bml0cyB0byB0aGUgcmVuZGVyZXJzLgogIHByb2NlZHVyZSBNYW5kZWxicm90KGRhdGE6IEJpdG1hcFJlZjsKICAgICAgICAgICAgICAgICAgICAgIHIxLCBpMSwgcjIsIGkyOiBmbG9hdCkgaXMKICAgIHdpZHRoOiBpbnRlZ2VyIDo9IGRhdGEnbGVuZ3RoKDEpOwogICAgaGVpZ2h0OiBpbnRlZ2VyIDo9IGRhdGEnbGVuZ3RoKDIpOwogICAgeGRlbHRhOiBmbG9hdCA6PSAocjItcjEpIC8gZmxvYXQod2lkdGgpOwogICAgeWRlbHRhOiBmbG9hdCA6PSAoaTItaTEpIC8gZmxvYXQoaGVpZ2h0KTsKCiAgICB0YXNrIFNjaGVkdWxlciBpcwogICAgICAtLSBFYWNoIHdvcmtlciBjYWxscyB0aGlzIHRvIGZpbmQgb3V0IHdoYXQgaXQgbmVlZHMgdG8gZG8uCiAgICAgIGVudHJ5IFJlcXVlc3RXb3JrVW5pdCh5OiBvdXQgaW50ZWdlcjsgaTogb3V0IGZsb2F0KTsKICAgIGVuZDsKCiAgICB0YXNrIGJvZHkgU2NoZWR1bGVyIGlzCiAgICBiZWdpbgogICAgICAtLSBIYW5kIG91dCBlYWNoIHNjYW5saW5lIGluIHR1cm4gdG8gdGFza3MgdGhhdCB3YW50IHRoaW5ncyB0bwogICAgICAtLSBkbywgdGhlbiBleGl0LgogICAgICBmb3IgeXkgaW4gZGF0YSdyYW5nZSgyKSBsb29wCiAgICAgICAgYWNjZXB0IFJlcXVlc3RXb3JrVW5pdCh5OiBvdXQgaW50ZWdlcjsgaTogb3V0IGZsb2F0KSBkbwogICAgICAgICAgeSA6PSB5eTsKICAgICAgICAgIGkgOj0gaTEgKyBmbG9hdCh5eSkqeWRlbHRhOwogICAgICAgIGVuZCBSZXF1ZXN0V29ya1VuaXQ7CiAgICAgIGVuZCBsb29wOwogICAgZW5kOwoKICAgIC0tIEFjdHVhbGx5IGRvZXMgdGhlIHJlbmRlcmluZy4gRWFjaCBvZiB0aGVzZSBpcyBzZWxmIGNvbnRhaW5lZCBhbmQgd2lsbAogICAgLS0ga2VlcCB3b3JraW5nIHVudGlsIHRoZXJlJ3Mgbm90aGluZyBsZWZ0IHRvIGRvLCBhdCB3aGljaCBwb2ludCBpdAogICAgLS0gZXhpdHMuCiAgICB0YXNrIHR5cGUgV29ya2VyOwogICAgdGFzayBib2R5IFdvcmtlciBpcwogICAgICB5OiBpbnRlZ2VyOwogICAgICBpOiBmbG9hdDsKICAgICAgYzogQ29tcGxleDsKICAgIGJlZ2luCiAgICAgIC0tIEtlZXAgYXNraW5nIGZvciBzdHVmZiB0byBkbywgdGhlbiBkbyBpdC4gV2hlbiB0aGUgU2NoZWR1bGVyCiAgICAgIC0tIGhhcyB0ZXJtaW5hdGVkLCByZXF1ZXN0aW5nIGEgd29yayB1bml0IHdpbGwgdGhyb3cgYW4gZXhjZXB0aW9uIGFuZAogICAgICAtLSB0aGUgdGFzayB3aWxsIHNhZmVseSBleGl0LgogICAgICBsb29wCiAgICAgICAgU2NoZWR1bGVyLlJlcXVlc3RXb3JrVW5pdCh5LCBpKTsKCiAgICAgICAgZm9yIHggaW4gZGF0YSdyYW5nZSgxKSBsb29wCiAgICAgICAgICBjIDo9IENvbXBsZXgnKHIxICsgZmxvYXQoeCkqeGRlbHRhLCBpKTsKICAgICAgICAgIGRhdGEoeCwgeSkgOj0gUmVuZGVyUGl4ZWwoYyk7CiAgICAgICAgZW5kIGxvb3A7CiAgICAgIGVuZCBsb29wOwogICAgZW5kOwoKICAgIC0tIENyZWF0ZSBzb21lIHdvcmsgdGhyZWFkcyAod2hpY2ggd2lsbCBhdXRvbWF0aWNhbGx5IHN0YXJ0KS4KICAgIHNjYW5saW5lczogYXJyYXkoaW50ZWdlciByYW5nZSAxLi50aHJlYWRzKSBvZiBXb3JrZXI7CiAgYmVnaW4KICAgIG51bGw7IC0tIG5vdGhpbmcgdG8gZG8gaW4gdGhlIG1haW4gYm9keSwganVzdCB3YWl0IGZvciB0YXNrcyB0byBleGl0CiAgZW5kOwoKICAtLSBUaGlzIHN1Y2tzLCBidXQgSSBjb3VsZG4ndCBmaW5kIGFueSBvdGhlciB3YXkgdG8gZ2V0IGlkZW9uZSB0byBlbWl0CiAgLS0gVW5pY29kZSBwcm9jZWR1cmFsbHkuIChUaGUgVVRGLTggcmVwcmVzZW50YXRpb24gb2YgZWFjaCBvZiB0aGVzZSBpcwogIC0tIHRocmVlIGJ5dGVzLiBDb2luY2lkZW5jZT8gSSB0aGluayBub3QuKQogIGdseXBoczogY29uc3RhbnQgYXJyYXkoMC4uMjU1KSBvZiBzdHJpbmcoMS4uMykgOj0KICAoIuKggCIsICLioIEiLCAi4qCCIiwgIuKggyIsICLioIQiLCAi4qCFIiwgIuKghiIsICLioIciLCAi4qCIIiwgIuKgiSIsICLioIoiLCAi4qCLIiwgIuKgjCIsICLioI0iLAogICAi4qCOIiwgIuKgjyIsICLioJAiLCAi4qCRIiwgIuKgkiIsICLioJMiLCAi4qCUIiwgIuKglSIsICLioJYiLCAi4qCXIiwgIuKgmCIsICLioJkiLCAi4qCaIiwgIuKgmyIsCiAgICLioJwiLCAi4qCdIiwgIuKgniIsICLioJ8iLCAi4qCgIiwgIuKgoSIsICLioKIiLCAi4qCjIiwgIuKgpCIsICLioKUiLCAi4qCmIiwgIuKgpyIsICLioKgiLCAi4qCpIiwKICAgIuKgqiIsICLioKsiLCAi4qCsIiwgIuKgrSIsICLioK4iLCAi4qCvIiwgIuKgsCIsICLioLEiLCAi4qCyIiwgIuKgsyIsICLioLQiLCAi4qC1IiwgIuKgtiIsICLioLciLAogICAi4qC4IiwgIuKguSIsICLioLoiLCAi4qC7IiwgIuKgvCIsICLioL0iLCAi4qC+IiwgIuKgvyIsICLioYAiLCAi4qGBIiwgIuKhgiIsICLioYMiLCAi4qGEIiwgIuKhhSIsCiAgICLioYYiLCAi4qGHIiwgIuKhiCIsICLioYkiLCAi4qGKIiwgIuKhiyIsICLioYwiLCAi4qGNIiwgIuKhjiIsICLioY8iLCAi4qGQIiwgIuKhkSIsICLioZIiLCAi4qGTIiwKICAgIuKhlCIsICLioZUiLCAi4qGWIiwgIuKhlyIsICLioZgiLCAi4qGZIiwgIuKhmiIsICLioZsiLCAi4qGcIiwgIuKhnSIsICLioZ4iLCAi4qGfIiwgIuKhoCIsICLioaEiLAogICAi4qGiIiwgIuKhoyIsICLioaQiLCAi4qGlIiwgIuKhpiIsICLioaciLCAi4qGoIiwgIuKhqSIsICLioaoiLCAi4qGrIiwgIuKhrCIsICLioa0iLCAi4qGuIiwgIuKhryIsCiAgICLiobAiLCAi4qGxIiwgIuKhsiIsICLiobMiLCAi4qG0IiwgIuKhtSIsICLiobYiLCAi4qG3IiwgIuKhuCIsICLiobkiLCAi4qG6IiwgIuKhuyIsICLiobwiLCAi4qG9IiwKICAgIuKhviIsICLiob8iLCAi4qKAIiwgIuKigSIsICLiooIiLCAi4qKDIiwgIuKihCIsICLiooUiLCAi4qKGIiwgIuKihyIsICLioogiLCAi4qKJIiwgIuKiiiIsICLioosiLAogICAi4qKMIiwgIuKijSIsICLioo4iLCAi4qKPIiwgIuKikCIsICLiopEiLCAi4qKSIiwgIuKikyIsICLiopQiLCAi4qKVIiwgIuKiliIsICLiopciLCAi4qKYIiwgIuKimSIsCiAgICLiopoiLCAi4qKbIiwgIuKinCIsICLiop0iLCAi4qKeIiwgIuKinyIsICLioqAiLCAi4qKhIiwgIuKioiIsICLioqMiLCAi4qKkIiwgIuKipSIsICLioqYiLCAi4qKnIiwKICAgIuKiqCIsICLioqkiLCAi4qKqIiwgIuKiqyIsICLioqwiLCAi4qKtIiwgIuKiriIsICLioq8iLCAi4qKwIiwgIuKisSIsICLiorIiLCAi4qKzIiwgIuKitCIsICLiorUiLAogICAi4qK2IiwgIuKityIsICLiorgiLCAi4qK5IiwgIuKiuiIsICLiorsiLCAi4qK8IiwgIuKivSIsICLior4iLCAi4qK/IiwgIuKjgCIsICLio4EiLCAi4qOCIiwgIuKjgyIsCiAgICLio4QiLCAi4qOFIiwgIuKjhiIsICLio4ciLCAi4qOIIiwgIuKjiSIsICLio4oiLCAi4qOLIiwgIuKjjCIsICLio40iLCAi4qOOIiwgIuKjjyIsICLio5AiLCAi4qORIiwKICAgIuKjkiIsICLio5MiLCAi4qOUIiwgIuKjlSIsICLio5YiLCAi4qOXIiwgIuKjmCIsICLio5kiLCAi4qOaIiwgIuKjmyIsICLio5wiLCAi4qOdIiwgIuKjniIsICLio58iLAogICAi4qOgIiwgIuKjoSIsICLio6IiLCAi4qOjIiwgIuKjpCIsICLio6UiLCAi4qOmIiwgIuKjpyIsICLio6giLCAi4qOpIiwgIuKjqiIsICLio6siLCAi4qOsIiwgIuKjrSIsCiAgICLio64iLCAi4qOvIiwgIuKjsCIsICLio7EiLCAi4qOyIiwgIuKjsyIsICLio7QiLCAi4qO1IiwgIuKjtiIsICLio7ciLCAi4qO4IiwgIuKjuSIsICLio7oiLCAi4qO7IiwKICAgIuKjvCIsICLio70iLCAi4qO+IiwgIuKjvyIpOwogIAogIC0tIFdyaXRlcyB0aGUgYml0bWFwIHRvIHN0ZG91dCwgdXNpbmcgZnVua3kgVW5pY29kZSBoYWNrZXJ5IHRvIG1ha2UgaXQKICAtLSBsb29rIHByZXR0eS4gU29ydCBvZi4KICBwcm9jZWR1cmUgRHVtcEJpdG1hcChkYXRhOiBCaXRtYXBSZWYpIGlzCiAgICBmdW5jdGlvbiBJc1NldCh4LCB5OiBpbnRlZ2VyKSByZXR1cm4gYm9vbGVhbiBpcwogICAgYmVnaW4KICAgICAJcmV0dXJuIGRhdGEoeCwgeSkgPiAwLjA7CiAgICBlbmQ7CgoJdHlwZSBieXRlIGlzIG1vZCAyKio4OwogICAgeCwgeTogaW50ZWdlcjsKICAgIGI6IGJ5dGU7CiAgYmVnaW4KICAgIHkgOj0gMDsKICAgIHdoaWxlICh5IDw9IGRhdGEnbGFzdCgyKSkgbG9vcAogICAgICB4IDo9IDA7CiAgICAgIHdoaWxlICh4IDwgZGF0YSdsYXN0KDEpKSBsb29wCiAgICAgIAliIDo9IDA7CiAgICAgCWlmIElzU2V0KHgrMCwgeSswKSB0aGVuIGIgOj0gYiBvciAxOyBlbmQgaWY7CiAgICAgCWlmIElzU2V0KHgrMCwgeSsxKSB0aGVuIGIgOj0gYiBvciAyOyBlbmQgaWY7CiAgICAgCWlmIElzU2V0KHgrMCwgeSsyKSB0aGVuIGIgOj0gYiBvciA0OyBlbmQgaWY7CiAgICAgCWlmIElzU2V0KHgrMCwgeSszKSB0aGVuIGIgOj0gYiBvciA2NDsgZW5kIGlmOwogICAgIAlpZiBJc1NldCh4KzEsIHkrMCkgdGhlbiBiIDo9IGIgb3IgODsgZW5kIGlmOwogICAgIAlpZiBJc1NldCh4KzEsIHkrMSkgdGhlbiBiIDo9IGIgb3IgMTY7IGVuZCBpZjsKICAgICAJaWYgSXNTZXQoeCsxLCB5KzIpIHRoZW4gYiA6PSBiIG9yIDMyOyBlbmQgaWY7CiAgICAgCWlmIElzU2V0KHgrMSwgeSszKSB0aGVuIGIgOj0gYiBvciAxMjg7IGVuZCBpZjsKICAgICAJUHV0KGdseXBocyhieXRlJ3BvcyhiKSkpOwogICAgICAJeCA6PSB4ICsgMjsKICAgICAgZW5kIGxvb3A7CiAgICAgIFB1dF9MaW5lKCIiKTsKICAgICAgeSA6PSB5ICsgNDsKICAgIGVuZCBsb29wOwogIGVuZDsKICAKICBpbWFnZTogQml0bWFwUmVmOwogIHdpZHRoOiBjb25zdGFudCA6PSBiaXRtYXBzaXplOwogIGhlaWdodDogY29uc3RhbnQgOj0gd2lkdGg7CmJlZ2luCiAgLS0gUmVuZGVyLCBwcmludCwgdGhlbiBsZWFrIGEgYml0bWFwLgogIGltYWdlIDo9IG5ldyBCaXRtYXAoMC4uKHdpZHRoLTEpLCAwLi4oaGVpZ2h0LTEpKTsKICBNYW5kZWxicm90KGltYWdlLCAtMi4wLCAtMi4wLCArMi4wLCArMi4wKTsKICBEdW1wQml0bWFwKGltYWdlKTsKZXhjZXB0aW9uCiAgd2hlbiBlOiBvdGhlcnMgPT4KICAgIFB1dF9MaW5lKEV4Y2VwdGlvbl9JbmZvcm1hdGlvbihlKSk7CmVuZDsK